org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* Copyright (c) 2011, 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:
// Rick Barkhouse - 2.1 - initial implementation
package org.eclipse.persistence.jaxb.dynamic;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import javax.xml.transform.stream.StreamSource;
import jakarta.xml.bind.JAXBException;
import org.eclipse.persistence.core.sessions.CoreProject;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.dynamic.DynamicClassLoader;
import org.eclipse.persistence.dynamic.DynamicEntity;
import org.eclipse.persistence.dynamic.DynamicHelper;
import org.eclipse.persistence.dynamic.DynamicType;
import org.eclipse.persistence.dynamic.DynamicTypeBuilder;
import org.eclipse.persistence.internal.descriptors.InstantiationPolicy;
import org.eclipse.persistence.internal.jaxb.JaxbClassLoader;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.jaxb.compiler.Generator;
import org.eclipse.persistence.jaxb.dynamic.metadata.Metadata;
import org.eclipse.persistence.jaxb.dynamic.metadata.OXMMetadata;
import org.eclipse.persistence.oxm.XMLContext;
import org.eclipse.persistence.sessions.DatabaseSession;
import org.eclipse.persistence.sessions.Project;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.factories.SessionManager;
import org.eclipse.persistence.sessions.factories.XMLSessionConfigLoader;
import org.w3c.dom.Node;
import org.xml.sax.EntityResolver;
/**
*
* A specialized JAXBContext
for marshalling and unmarshalling DynamicEntities
.
*
*
*
* DynamicJAXBContext
also provides methods to:
*
*
* - get the
DynamicType
associated with a given Java name
* - get the
DynamicType
associated with a given XML name
* - create a new
DynamicEntity
given the Java name of its DynamicType
* - create a new
DynamicEntity
given the XML name of its DynamicType
*
*
*
* New instances of DynamicJAXBContext
must be created with DynamicJAXBContextFactory
.
*
*
* @see jakarta.xml.bind.JAXBContext
* @see org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory
* @see org.eclipse.persistence.dynamic.DynamicEntity
* @see org.eclipse.persistence.dynamic.DynamicType
*
* @author rbarkhouse
* @since EclipseLink 2.1
*/
public class DynamicJAXBContext extends org.eclipse.persistence.jaxb.JAXBContext {
DynamicJAXBContext(JAXBContextInput input) throws JAXBException {
super(input);
}
public DynamicClassLoader getDynamicClassLoader() {
return ((DynamicJAXBContextInput) contextInput).getClassLoader();
}
private ArrayList getHelpers() {
return ((DynamicJAXBContextState) contextState).getHelpers();
}
/**
* Obtain a reference to the DynamicType
object for a given Java name. If one has
* not been generated, this method will return null
.
*
* @param javaName
* A Java class name, used to look up its DynamicType
.
*
* @return
* The DynamicType
for this Java class name.
*/
public DynamicType getDynamicType(String javaName) {
for (DynamicHelper helper : getHelpers()) {
DynamicType type = helper.getType(javaName);
if (type != null) {
return type;
}
}
return null;
}
/**
* Create a new instance of DynamicEntity
for a given Java name. If a
* DynamicType
for this Java class name has not been generated, this
* method will return null
.
*
* @param javaName
* The Java class name to create a new DynamicEntity
for.
*
* @return
* A new DynamicEntity
for this Java class name.
*/
public DynamicEntity newDynamicEntity(String javaName) throws IllegalArgumentException {
IllegalArgumentException ex = null;
for (DynamicHelper helper : getHelpers()) {
try {
return helper.newDynamicEntity(javaName);
} catch (IllegalArgumentException e) {
ex = e;
}
}
throw ex;
}
/**
* Create a new instance of DynamicEntity
for a given DynamicType
.
*
* @param dynamicType
* The DynamicType
to create a new DynamicEntity
for.
*
* @return
* A new DynamicEntity
for this DynamicType
.
*/
public DynamicEntity newDynamicEntity(DynamicType dynamicType) {
return dynamicType.newDynamicEntity();
}
/**
* Returns the constant named constantName
from the enum class specified by enumName
.
*
* @param enumName
* Java class name of an enum.
* @param constantName
* Name of the constant to get from the specified enum.
*
* @return
* An Object
, the constant from the specified enum.
*/
public Object getEnumConstant(String enumName, String constantName) throws ClassNotFoundException, JAXBException {
Object valueToReturn = null;
Class> enumClass = getDynamicClassLoader().loadClass(enumName);
Object[] enumConstants = enumClass.getEnumConstants();
for (Object enumConstant : enumConstants) {
if (enumConstant.toString().equals(constantName)) {
valueToReturn = enumConstant;
}
}
if (valueToReturn != null) {
return valueToReturn;
} else {
throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.enumConstantNotFound(enumName + "." + constantName));
}
}
// ========================================================================
static class DynamicJAXBContextState extends JAXBContextState {
private ArrayList helpers;
private DynamicClassLoader dClassLoader;
public DynamicJAXBContextState(DynamicClassLoader loader) {
super();
helpers = new ArrayList();
}
public DynamicJAXBContextState(XMLContext ctx) {
super(ctx);
}
public ArrayList getHelpers() {
return helpers;
}
public void setHelpers(ArrayList helpers) {
this.helpers = helpers;
}
public DynamicClassLoader getDynamicClassLoader() {
return dClassLoader;
}
public void setDynamicClassLoader(DynamicClassLoader dClassLoader) {
this.dClassLoader = dClassLoader;
}
}
// ========================================================================
static abstract class DynamicJAXBContextInput extends org.eclipse.persistence.jaxb.JAXBContext.JAXBContextInput {
public DynamicJAXBContextInput(Map properties, ClassLoader classLoader) {
super(properties, classLoader);
if (classLoader == null) {
classLoader = PrivilegedAccessHelper.callDoPrivileged(
() -> PrivilegedAccessHelper.getContextClassLoader(Thread.currentThread())
);
}
final DynamicClassLoader dClassLoader;
if (classLoader instanceof DynamicClassLoader) {
dClassLoader = (DynamicClassLoader) classLoader;
} else {
final ClassLoader parent = classLoader;
dClassLoader = PrivilegedAccessHelper.callDoPrivileged(
() -> new DynamicClassLoader(new JaxbClassLoader(parent))
);
}
this.classLoader = dClassLoader;
}
public DynamicClassLoader getClassLoader() {
return (DynamicClassLoader) this.classLoader;
}
}
static class MetadataContextInput extends DynamicJAXBContextInput {
public MetadataContextInput(Map properties, ClassLoader classLoader) {
super(properties, classLoader);
}
@Override
protected JAXBContextState createContextState() throws JAXBException {
DynamicJAXBContextState state = new DynamicJAXBContextState((DynamicClassLoader) classLoader);
Metadata oxmMetadata = new OXMMetadata((DynamicClassLoader) classLoader, properties);
Generator g = new Generator(oxmMetadata.getJavaModelInput(), oxmMetadata.getBindings(), classLoader, null, false);
CoreProject p = null;
Project dp = null;
try {
p = g.generateProject();
// Clear out InstantiationPolicy because it refers to ObjectFactory, which we won't be using
List descriptors = p.getOrderedDescriptors();
for (ClassDescriptor classDescriptor : descriptors) {
try {
if(null == classDescriptor.getJavaClass()) {
classDescriptor.setJavaClass(classLoader.getParent().loadClass(classDescriptor.getJavaClassName()));
}
} catch(ClassNotFoundException e) {
classDescriptor.setInstantiationPolicy(new InstantiationPolicy());
}
}
dp = DynamicTypeBuilder.loadDynamicProject((Project)p, null, (DynamicClassLoader) classLoader);
} catch (Exception e) {
throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.errorCreatingDynamicJAXBContext(e));
}
XMLContext ctx = new XMLContext(dp, classLoader, sessionEventListeners());
state.setXMLContext(ctx);
List sessions = ctx.getSessions();
for (Object session : sessions) {
state.getHelpers().add(new DynamicHelper((DatabaseSession) session));
}
return state;
}
}
static class SchemaContextInput extends DynamicJAXBContextInput {
private Object schema = null;
private EntityResolver entityResolver;
public static final String SCHEMAMETADATA_CLASS_NAME = "org.eclipse.persistence.jaxb.dynamic.metadata.SchemaMetadata";
public SchemaContextInput(Object schema, EntityResolver resolver, Map properties, ClassLoader classLoader) {
super(properties, classLoader);
this.schema = schema;
this.entityResolver = resolver;
}
@Override
protected JAXBContextState createContextState() throws JAXBException {
DynamicJAXBContextState state = new DynamicJAXBContextState((DynamicClassLoader) classLoader);
Metadata schemaMetadata = null;
Object constructorArg;
if (schema instanceof Node) {
constructorArg = schema;
} else if (schema instanceof InputStream) {
constructorArg = new StreamSource((InputStream) schema);
} else {
constructorArg = schema;
}
try {
Class> schemaMetadataClass = PrivilegedAccessHelper.getClassForName(SCHEMAMETADATA_CLASS_NAME);
Class>[] constructorClassArgs = {DynamicClassLoader.class, Map.class, constructorArg.getClass(), EntityResolver.class};
Constructor> constructor = PrivilegedAccessHelper.getConstructorFor(schemaMetadataClass, constructorClassArgs, true);
Object[] contructorObjectArgs = {classLoader, properties, constructorArg, entityResolver};
schemaMetadata = (Metadata) PrivilegedAccessHelper.invokeConstructor(constructor, contructorObjectArgs);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof JAXBException) {
throw (JAXBException) cause;
} else if (cause instanceof org.eclipse.persistence.exceptions.JAXBException) {
throw (org.eclipse.persistence.exceptions.JAXBException) cause;
} else {
throw new JAXBException(e);
}
} catch (org.eclipse.persistence.exceptions.JAXBException e) {
throw e;
} catch (Exception e) {
throw new JAXBException(e);
}
Generator g = new Generator(schemaMetadata.getJavaModelInput(), schemaMetadata.getBindings(), classLoader, null, false);
Project p = null;
Project dp = null;
try {
p = (Project) g.generateProject();
// Clear out InstantiationPolicy because it refers to ObjectFactory, which we won't be using
List descriptors = p.getOrderedDescriptors();
for (ClassDescriptor classDescriptor : descriptors) {
classDescriptor.setInstantiationPolicy(new InstantiationPolicy());
}
dp = DynamicTypeBuilder.loadDynamicProject(p, null, (DynamicClassLoader) classLoader);
} catch (Exception e) {
throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.errorCreatingDynamicJAXBContext(e));
}
XMLContext ctx = new XMLContext(dp, classLoader, sessionEventListeners());
state.setXMLContext(ctx);
List sessions = ctx.getSessions();
for (Object session : sessions) {
state.getHelpers().add(new DynamicHelper((DatabaseSession) session));
}
return state;
}
}
static class SessionsXmlContextInput extends DynamicJAXBContextInput {
private String sessions;
public SessionsXmlContextInput(String sessionNames, Map properties, ClassLoader classLoader) {
super(properties, classLoader);
this.sessions = sessionNames;
}
@Override
protected JAXBContextState createContextState() throws JAXBException {
DynamicJAXBContextState state = new DynamicJAXBContextState((DynamicClassLoader) classLoader);
StringTokenizer st = new StringTokenizer(sessions, ":");
ArrayList dynamicProjects = new ArrayList(st.countTokens());
XMLSessionConfigLoader loader = new XMLSessionConfigLoader();
while (st.hasMoreTokens()) {
DatabaseSession dbSession =
(DatabaseSession) SessionManager.getManager().getSession(loader, st.nextToken(), classLoader, false, true);
Project p = DynamicTypeBuilder.loadDynamicProject(dbSession.getProject(), null, (DynamicClassLoader) classLoader);
dynamicProjects.add(p);
}
XMLContext xmlContext = new XMLContext(dynamicProjects);
state.setXMLContext(xmlContext);
List sessions = xmlContext.getSessions();
for (Object session : sessions) {
state.getHelpers().add(new DynamicHelper((DatabaseSession) session));
}
return state;
}
}
}