blob: 37dee1fbc889c7b50c1ae1bdc2ac1ad7a8f9926a [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.jaxb.compiler;
import java.lang.reflect.Method;
import jakarta.xml.bind.Unmarshaller;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.logging.AbstractSessionLog;
import org.eclipse.persistence.logging.SessionLog;
/**
* INTERNAL:
* <p><b>Purpose:</b>Hold information about class based JAXB 2.0 Callback methods
* <p><b>Responsibilities:</b><ul>
* <li>Store information about domainClass and the callback methods</li>
* <li>Act as a means to integrate JAXB 2.0 Class based callbacks with TopLink OXM
* Listener based callbacks.</li></ul>
*
* A Map of UnmarshalCallbacks are created during JAXB 2.0 Generation and are set on a
* JAXBUnmarshallerListener on each JAXBUnmarshaller. These callbacks are used to invoke
* the JAXB 2.0 Class Based callbacks on each object at the appropriate time.
*
* @author mmacivor
* @since Oracle TopLink 11.1.1.0.0
* @see org.eclipse.persistence.jaxb.JAXBUnmarshalListener
* @see org.eclipse.persistence.jaxb.JAXBUnmarshaller
*/
public class UnmarshalCallback {
private Class<?> domainClass;
private String domainClassName;
private Method afterUnmarshalCallback;
private Method beforeUnmarshalCallback;
private boolean hasAfterUnmarshalCallback = false;
private boolean hasBeforeUnmarshalCallback = false;
public Method getAfterUnmarshalCallback() {
return afterUnmarshalCallback;
}
public Method getBeforeUnmarshalCallback() {
return beforeUnmarshalCallback;
}
public Class<?> getDomainClass() {
return domainClass;
}
/**
* Initialize information about class based JAXB 2.0 Callback methods.
*
* @param loader source class loader for {@code domainClass}
*/
public void initialize(ClassLoader loader) {
try {
domainClass = PrivilegedAccessHelper.callDoPrivilegedWithException(
() -> PrivilegedAccessHelper.getClassForName(domainClassName, true, loader)
);
} catch (ClassNotFoundException ex) {
return;
} catch (Exception ex) {
throw new RuntimeException(String.format("Failed initialization of %s class", domainClassName), ex);
}
Class<?>[] params = new Class<?>[]{ Unmarshaller.class, Object.class };
if (hasBeforeUnmarshalCallback) {
try {
Method beforeUnmarshal = PrivilegedAccessHelper.callDoPrivilegedWithException(
() -> PrivilegedAccessHelper.getMethod(domainClass, "beforeUnmarshal", params, false)
);
setBeforeUnmarshalCallback(beforeUnmarshal);
} catch (NoSuchMethodException nsmex) {
// Ignore this exception
} catch (Exception ex) {
throw new RuntimeException(String.format("Failed initialization of beforeMarshal method of %s class", domainClassName), ex);
}
}
if (hasAfterUnmarshalCallback) {
try {
Method afterUnmarshal = PrivilegedAccessHelper.callDoPrivilegedWithException(
() -> PrivilegedAccessHelper.getMethod(domainClass, "afterUnmarshal", params, false)
);
setAfterUnmarshalCallback(afterUnmarshal);
} catch (NoSuchMethodException nsmex) {
// Ignore this exception
} catch (Exception ex) {
throw new RuntimeException(String.format("Failed initialization of afterMarshal method of %s class", domainClassName), ex);
}
}
}
/**
* Should not use this method - the init method will
* overwrite the set value.
*/
public void setAfterUnmarshalCallback(Method method) {
afterUnmarshalCallback = method;
}
public void setHasAfterUnmarshalCallback() {
hasAfterUnmarshalCallback = true;
}
/**
* Should not use this method - the init method will
* overwrite the set value.
*/
public void setBeforeUnmarshalCallback(Method method) {
beforeUnmarshalCallback = method;
}
public void setHasBeforeUnmarshalCallback() {
hasBeforeUnmarshalCallback = true;
}
/**
* Should use setDomainClassName - the init method will overwrite
* the set value with Class.forName(domainClassName)
*
*/
public void setDomainClass(Class<?> clazz) {
domainClass = clazz;
setDomainClassName(clazz.getName());
}
public void setDomainClassName(String className) {
domainClassName = className;
}
}