org.eclipse.persistence.jaxb.JAXBContext Maven / Gradle / Ivy
Show all versions of eclipselink Show documentation
/*
* 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
// Marcel Valovy - 2.6 - added ci unmarshalling & BV in JAXB
// Dmitry Kornilov - 2.6.1 - BeanValidationHelper refactoring
package org.eclipse.persistence.jaxb;
import java.awt.Image;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.xml.namespace.QName;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.transform.Source;
import jakarta.xml.bind.JAXBElement;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.PropertyException;
import jakarta.xml.bind.SchemaOutputResolver;
import jakarta.xml.bind.ValidationEvent;
import jakarta.xml.bind.ValidationEventHandler;
import jakarta.xml.bind.annotation.adapters.XmlAdapter;
import org.eclipse.persistence.core.queries.CoreAttributeGroup;
import org.eclipse.persistence.core.sessions.CoreProject;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.exceptions.ConversionException;
import org.eclipse.persistence.exceptions.JAXBException;
import org.eclipse.persistence.internal.core.helper.CoreClassConstants;
import org.eclipse.persistence.internal.helper.ConversionManager;
import org.eclipse.persistence.internal.jaxb.JAXBSchemaOutputResolver;
import org.eclipse.persistence.internal.jaxb.JaxbClassLoader;
import org.eclipse.persistence.internal.jaxb.ObjectGraphImpl;
import org.eclipse.persistence.internal.jaxb.WrappedValue;
import org.eclipse.persistence.internal.jaxb.json.schema.JsonSchemaGenerator;
import org.eclipse.persistence.internal.jaxb.json.schema.model.JsonSchema;
import org.eclipse.persistence.internal.jaxb.many.ManyValue;
import org.eclipse.persistence.internal.oxm.Constants;
import org.eclipse.persistence.internal.oxm.Root;
import org.eclipse.persistence.internal.oxm.XMLConversionManager;
import org.eclipse.persistence.internal.oxm.XPathFragment;
import org.eclipse.persistence.internal.oxm.mappings.ChoiceCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.ChoiceObjectMapping;
import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
import org.eclipse.persistence.internal.oxm.mappings.Field;
import org.eclipse.persistence.internal.oxm.schema.SchemaModelGenerator;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.jaxb.compiler.Generator;
import org.eclipse.persistence.jaxb.compiler.MarshalCallback;
import org.eclipse.persistence.jaxb.compiler.UnmarshalCallback;
import org.eclipse.persistence.jaxb.javamodel.JavaClass;
import org.eclipse.persistence.jaxb.javamodel.reflection.AnnotationHelper;
import org.eclipse.persistence.jaxb.javamodel.reflection.JavaModelImpl;
import org.eclipse.persistence.jaxb.javamodel.reflection.JavaModelInputImpl;
import org.eclipse.persistence.jaxb.json.JsonSchemaOutputResolver;
import org.eclipse.persistence.jaxb.xmlmodel.JavaType;
import org.eclipse.persistence.jaxb.xmlmodel.XmlBindings;
import org.eclipse.persistence.jaxb.xmlmodel.XmlBindings.JavaTypes;
import org.eclipse.persistence.logging.AbstractSessionLog;
import org.eclipse.persistence.logging.LogLevel;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.oxm.MediaType;
import org.eclipse.persistence.oxm.NamespaceResolver;
import org.eclipse.persistence.oxm.XMLContext;
import org.eclipse.persistence.oxm.XMLField;
import org.eclipse.persistence.oxm.XMLLogin;
import org.eclipse.persistence.oxm.XMLMarshaller;
import org.eclipse.persistence.oxm.XMLUnmarshaller;
import org.eclipse.persistence.oxm.platform.SAXPlatform;
import org.eclipse.persistence.oxm.platform.XMLPlatform;
import org.eclipse.persistence.sessions.Project;
import org.eclipse.persistence.sessions.SessionEventListener;
import static org.eclipse.persistence.jaxb.javamodel.Helper.getQualifiedJavaTypeName;
/**
* Purpose:Provide a EclipseLink implementation of the JAXBContext interface.
*
Responsibilities:
* - Create Marshaller instances
* - Create Unmarshaller instances
* - Create Binder instances
* - Create Introspector instances
* - Create Validator instances
* - Generate Schema Files
*
* This is the EclipseLink JAXB 2.0 implementation of jakarta.xml.bind.JAXBContext. This class
* is created by the JAXBContextFactory and is used to create Marshallers, Unmarshallers, Validators,
* Binders and Introspectors. A JAXBContext can also be used to create Schema Files.
*
Bootstrapping:
* When bootstrapping the JAXBContext from a EclipseLink externalized metadata file(s) a number of
* input options are available. The externalized metadata file (one per package) is passed in
* through a property when creating the JAXBContext. The key used in the properties map is
* "eclipselink-oxm-xml". The externalized metadata file can be set in the properties map in
* one of three ways:
*
i) For a single externalized metadata file, one of the following can be set in the properties map:
* - java.io.File
* - java.io.InputStream
* - java.io.Reader
* - java.net.URL
* - javax.xml.stream.XMLEventReader
* - javax.xml.stream.XMLStreamReader
* - javax.xml.transform.Source
* - org.w3c.dom.Node
* - org.xml.sax.InputSource
* When using one of the above options, the package name must be set via package-name attribute on the
* xml-bindings element in the externalized metadata file.
* ii) For multiple externalized metadata files where the package name is specified within each externalized
* metadata file, a List can be used. The entries in the List are to be one of the types listed in i) above.
*
iii) For multiple externalized metadata files where the package name is not specified in each externalized
* metadata file, a Map can be used. The key must be a String (package name) and each value in the Map
* (externalized metadata file) is to be one of the types listed in i) above.
*
Note that in each of the above cases the package name can be set via package-name attribute on the
* xml-bindings element in the externalized metadata file. If set, any java-type names in the given metadata
* file that do not contain the package name will have that package name prepended to it. Also note that a
* List or Map can be used for a single externalized metadata file.
*
* @see jakarta.xml.bind.JAXBContext
* @see org.eclipse.persistence.jaxb.JAXBMarshaller
* @see org.eclipse.persistence.jaxb.JAXBUnmarshaller
* @see org.eclipse.persistence.jaxb.JAXBBinder
* @see org.eclipse.persistence.jaxb.JAXBIntrospector
* @see org.eclipse.persistence.jaxb.JAXBContextProperties
*
* @author mmacivor
*/
public class JAXBContext extends jakarta.xml.bind.JAXBContext {
private static final Map PARSER_FEATURES = new HashMap<>(2);
static {
PARSER_FEATURES.put("http://apache.org/xml/features/validation/schema/normalized-value", false);
PARSER_FEATURES.put("http://apache.org/xml/features/validation/schema/element-default", false);
if (MOXySystemProperties.moxyLoggingLevel != null) {
AbstractSessionLog.getLog().setLevel(LogLevel.toValue(MOXySystemProperties.moxyLoggingLevel).getId(), SessionLog.MOXY);
}
}
private static final String RI_XML_ACCESSOR_FACTORY_SUPPORT = "org.glassfish.jaxb.XmlAccessorFactory";
/**
* For JAXB 2 there is no explicitly defined default validation handler
* and the default event handling only terminates the operation after
* encountering a fatal error.
*/
protected static final ValidationEventHandler DEFAULT_VALIDATION_EVENT_HANDLER = new ValidationEventHandler() {
@Override
public boolean handleEvent(ValidationEvent event) {
return event.getSeverity() < ValidationEvent.FATAL_ERROR;
}
};
private final AtomicBoolean hasLoggedValidatorInfo = new AtomicBoolean();
protected JAXBContextInput contextInput;
protected volatile JAXBContextState contextState;
private XMLInputFactory xmlInputFactory;
private boolean initializedXMLInputFactory = false;
private JAXBMarshaller jsonSchemaMarshaller;
private static volatile BeanValidationHelper beanValidationHelper;
private static volatile Boolean beanValidationPresent;
protected JAXBContext() {
super();
contextState = new JAXBContextState();
initBeanValidation();
}
protected JAXBContext(JAXBContextInput contextInput) throws jakarta.xml.bind.JAXBException {
this.contextInput = contextInput;
this.contextState = contextInput.createContextState();
initBeanValidation();
}
/**
* Create a JAXBContext for a given XMLContext. The XMLContext contains the
* metadata about the Object to XML mappings.
*/
public JAXBContext(XMLContext context) {
contextState = new JAXBContextState(context);
initBeanValidation();
}
/**
* Create a JAXBContext. The XMLContext contains the metadata about the
* Object to XML mappings.
*/
public JAXBContext(XMLContext context, Generator generator, Type[] boundTypes) {
contextState = new JAXBContextState(context, generator, boundTypes, null);
initBeanValidation();
}
/**
* Create a JAXBContext. The XMLContext contains the metadata about the
* Object to XML mappings.
*/
public JAXBContext(XMLContext context, Generator generator, TypeMappingInfo[] boundTypes) {
contextState = new JAXBContextState(context, generator, boundTypes, null);
initBeanValidation();
}
/**
* Initializes bean validation if jakarta.validation.api bundle is on the class path.
*/
private void initBeanValidation() {
if (beanValidationPresent == null) {
beanValidationPresent = BeanValidationChecker.isBeanValidationPresent();
}
if (beanValidationPresent && beanValidationHelper == null) {
synchronized (JAXBContext.class) {
if (beanValidationHelper == null) {
// Bean validation is optional
beanValidationHelper = new BeanValidationHelper();
}
}
}
}
/**
* Returns BeanValidationHelper. Can return null if bean validation jar is not on class path.
*/
public BeanValidationHelper getBeanValidationHelper() {
return beanValidationHelper;
}
public XMLInputFactory getXMLInputFactory() {
if (!initializedXMLInputFactory) {
try {
xmlInputFactory = XMLInputFactory.newInstance();
} catch (FactoryConfigurationError e) {
} finally {
initializedXMLInputFactory = true;
}
}
return xmlInputFactory;
}
AtomicBoolean getHasLoggedValidatorInfo() {
return hasLoggedValidatorInfo;
}
/**
* This event is called when context creation is completed,
* and provides a chance to deference anything that is no longer
* needed (to reduce the memory footprint of this object).
*/
void postInitialize() {
if (this.contextState.generator != null) {
this.contextState.generator.postInitialize();
}
}
/**
* ADVANCED:
* Refresh the underlying metadata based on the inputs that were
* used to create the JAXBContext. This is particularly useful when using
* the virtual property mappings. The refreshMetadata call could be made
* in the following way:
* org.eclipse.persistence.jaxb.JAXBHelper.getJAXBContext(aJAXBContext).refreshMetadata();
* Note:
*
* - As instances of Binder maintain a cache, calling refreshMetadata will
* not affect instances of Binder. To get the new metadata you must create
* a new instance of Binder after the refresh metadata call has been made.
*
* @throws jakarta.xml.bind.JAXBException
*/
public void refreshMetadata() throws jakarta.xml.bind.JAXBException {
JAXBContextState newState = newContextState();
if (newState != null) {
contextState = newState;
}
}
/**
* INTERNAL:
* Build a new JAXBContextState from the current JAXBContextInput.
*/
private JAXBContextState newContextState() throws jakarta.xml.bind.JAXBException {
if (null == contextInput) {
return null;
}
synchronized (this) {
JAXBContextState newState = contextInput.createContextState();
XMLContext xmlContext = getXMLContext();
xmlContext.setXMLContextState(newState.getXMLContext().getXMLContextState());
newState.setXMLContext(xmlContext);
newState.setTypeToTypeMappingInfo(contextState.getTypeToTypeMappingInfo());
return newState;
}
}
/**
* INTERNAL:
* Indicates if this JAXBContext can have its metadata refreshed.
*/
boolean isRefreshable() {
return false;
/*
if (this.contextInput.properties == null) {
return true;
}
if (this.contextInput.properties.containsKey(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY)) {
return false;
}
return true;
*/
}
/**
* Return the XMLContext associated with this JAXBContext.
*/
public XMLContext getXMLContext() {
return contextState.getXMLContext();
}
public void setXMLContext(XMLContext xmlContext) {
contextState.setXMLContext(xmlContext);
}
/**
* Generate a Schema for this JAXBContext
*
* @param outputResolver Class that decides where the schema file (of the given namespace URI) will be written
*/
@Override
public void generateSchema(SchemaOutputResolver outputResolver) {
if(outputResolver instanceof JsonSchemaOutputResolver) {
generateJsonSchema(outputResolver, ((JsonSchemaOutputResolver)outputResolver).getRootClass());
} else {
generateSchema(outputResolver, null);
}
}
public void generateJsonSchema(SchemaOutputResolver outputResolver, Class rootClass) {
JsonSchemaGenerator generator = new JsonSchemaGenerator(this, this.contextState.properties);
JsonSchema schema = generator.generateSchema(rootClass);
try {
Marshaller m = getJsonSchemaMarshaller();
m.marshal(schema, outputResolver.createOutput(null, rootClass.getName() + ".json"));
} catch (Exception ex) {
throw org.eclipse.persistence.exceptions.JAXBException.exceptionDuringSchemaGeneration(ex);
}
}
private Marshaller getJsonSchemaMarshaller() throws jakarta.xml.bind.JAXBException {
if (this.jsonSchemaMarshaller == null) {
JAXBContext ctx = (JAXBContext) JAXBContextFactory.createContext(new Class[] { JsonSchema.class }, null);
this.jsonSchemaMarshaller = ctx.createMarshaller();
this.jsonSchemaMarshaller.setProperty(MarshallerProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
this.jsonSchemaMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
this.jsonSchemaMarshaller.setProperty(MarshallerProperties.JSON_REDUCE_ANY_ARRAYS, true);
}
return this.jsonSchemaMarshaller;
}
/**
* Generate a Schema for this JAXBContext
*
* @param outputResolver Class that decides where the schema file (of the given namespace URI) will be written
* @param additonalGlobalElements Map of additional global elements to be added to the generated XSD.
* Note that if any QName in this map conflicts with another global element (for example from a TypeMappingInfo object)
* then the element generated from this map will be the one that is present in the XSD.
*/
public void generateSchema(SchemaOutputResolver outputResolver, Map additonalGlobalElements) {
JAXBContextState currentJAXBContextState = contextState;
if (isRefreshable()) {
// Recreate context state, to rebuild Generator
try {
currentJAXBContextState = newContextState();
} catch (Exception e) {
throw JAXBException.exceptionDuringSchemaGeneration(e);
}
}
XMLContext xmlContext = currentJAXBContextState.getXMLContext();
Generator generator = currentJAXBContextState.getGenerator();
if (generator == null) {
SchemaModelGenerator smGen = new SchemaModelGenerator(xmlContext.getOxmConversionManager());
smGen.generateSchemas(xmlContext.getDescriptors(), null, new JAXBSchemaOutputResolver(outputResolver), additonalGlobalElements);
} else {
generator.generateSchemaFiles(outputResolver, additonalGlobalElements);
}
}
/**
* Create a JAXBMarshaller. The JAXBMarshaller is used to convert Java objects
* to XML.
*/
@Override
public JAXBMarshaller createMarshaller() throws jakarta.xml.bind.JAXBException {
return contextState.createMarshaller(this);
}
/**
* Create a JAXBUnmarshaller. The JAXBUnmarshaller is used to convert XML into
* Java objects.
*/
@Override
public JAXBUnmarshaller createUnmarshaller() throws jakarta.xml.bind.JAXBException {
return contextState.createUnmarshaller(this);
}
/**
* Create a JAXBValidator. The JAXBValidator is used to validate Java objects against
* an XSD.
*/
@Override
public JAXBValidator createValidator() {
return new JAXBValidator(getXMLContext().createValidator());
}
/**
* Create a JAXBBinder. The JAXBBinder is used to preserve unmapped XML Data.
*/
@Override
public JAXBBinder createBinder() {
return contextState.createBinder(this);
}
/**
* Create a JAXBBinder. The JAXBBinder is used to preserve unmapped XML Data.
*
* @param nodeClass The DOM Node class to use
*/
@Override
public JAXBBinder createBinder(Class nodeClass) {
if (nodeClass.getName().equals("org.w3c.dom.Node")) {
return contextState.createBinder(this);
} else {
throw new UnsupportedOperationException(JAXBException.unsupportedNodeClass(nodeClass.getName()));
}
}
/**
* Creates a JAXBIntrospector object. The JAXBIntrospector allows the user to
* access certain pieces of metadata about an instance of a JAXB bound class.
*/
@Override
public JAXBIntrospector createJAXBIntrospector() {
return new JAXBIntrospector(getXMLContext());
}
/**
* INTERNAL:
* Set the map containing which QName corresponds to which generated class.
*/
public void setQNameToGeneratedClasses(HashMap qNameToClass) {
contextState.setQNameToGeneratedClasses(qNameToClass);
}
/**
* INTERNAL:
* Get the map containing which Class (by name) corresponds to which generated class.
*/
public Map getClassToGeneratedClasses() {
return contextState.getClassToGeneratedClasses();
}
/**
* INTERNAL:
* Set the map containing which Class (by name) corresponds to which generated class.
*/
public void setClassToGeneratedClasses(HashMap classToClass) {
contextState.setClassToGeneratedClasses(classToClass);
}
/**
* ADVANCED:
* Adjust the OXM metadata to take into account ORM mapping metadata
*/
public void applyORMMetadata(AbstractSession ormSession) {
getXMLContext().applyORMMetadata(ormSession);
}
/**
* INTERNAL:
* Get the map of which QName corresponds to which declared class.
*/
public Map getQNamesToDeclaredClasses() {
return contextState.getQNamesToDeclaredClasses();
}
/**
* INTERNAL:
* Get the map of which QName corresponds to which generated class.
*/
Map getQNameToGeneratedClasses() {
return contextState.getQNameToGeneratedClasses();
}
/**
* INTERNAL:
* Set the map of which QName corresponds to which declared class.
*/
public void setQNamesToDeclaredClasses(HashMap nameToDeclaredClasses) {
contextState.setQNamesToDeclaredClasses(nameToDeclaredClasses);
}
/**
* INTERNAL:
* Get the map for which array class (by name) corresponds to which generated class
*/
public Map getArrayClassesToGeneratedClasses() {
if (contextState.getGenerator() == null) {
return null;
}
return contextState.getGenerator().getAnnotationsProcessor().getArrayClassesToGeneratedClasses();
}
/**
* INTERNAL:
* Get the map for which collection class (by Type) corresponds to which generated class
*/
public Map getCollectionClassesToGeneratedClasses() {
if (contextState.getGenerator() == null) {
return null;
}
return contextState.getGenerator().getAnnotationsProcessor().getCollectionClassesToGeneratedClasses();
}
/**
* INTERNAL:
* Populate the map of which Type corresponds to which QName.
* The keys should be all the boundTypes used to create the JAXBContext.
* If the JAXBContext was not created with the constructor that takes a Type[] then
* this Map will be empty.
*/
public void initTypeToSchemaType() {
contextState.initTypeToSchemaType();
}
/**
* INTERNAL:
* Get the map of which TypeMappingInfo corresponds to which QName.
* The keys should be all the boundTypes used to create the JAXBContext.
* If the JAXBContext was not created with the constructor that takes a TypeMappingInfo[]
* this Map will be empty.
*/
public Map getTypeMappingInfoToSchemaType() {
return contextState.getTypeMappingInfoToSchemaType();
}
/**
* INTERNAL:
* Get the map of which Type corresponds to which QName.
* The keys should be all the boundTypes used to create the JAXBContext.
* If the JAXBContext was not created with the constructor that takes a Type[] then
* this Map will be empty.
*/
public Map getTypeToSchemaType() {
return contextState.getTypeToSchemaType();
}
Map getTypeMappingInfoToGeneratedType() {
return contextState.getTypeMappingInfoToGeneratedType();
}
Map getTypeToTypeMappingInfo() {
return contextState.getTypeToTypeMappingInfo();
}
void setTypeToTypeMappingInfo(Map typeToMappingInfo) {
contextState.setTypeToTypeMappingInfo(typeToMappingInfo);
}
void setTypeMappingInfoToJavaTypeAdapaters(Map typeMappingInfoToAdapters) {
contextState.setTypeMappingInfoToJavaTypeAdapaters(typeMappingInfoToAdapters);
}
static class RootLevelXmlAdapter {
private XmlAdapter xmlAdapter;
private Class boundType;
public RootLevelXmlAdapter(XmlAdapter adapter, Class boundType) {
this.xmlAdapter = adapter;
this.boundType = boundType;
}
public XmlAdapter getXmlAdapter() {
return xmlAdapter;
}
public Class getBoundType() {
return boundType;
}
public void setXmlAdapter(XmlAdapter xmlAdapter) {
this.xmlAdapter = xmlAdapter;
}
public void setBoundType(Class boundType) {
this.boundType = boundType;
}
}
Map getTypeMappingInfoToJavaTypeAdapters() {
return contextState.getTypeMappingInfoToJavaTypeAdapters();
}
/**
* Get a value from an object based on an XPath statement.
*
* @param
* The return type of this method corresponds to the returnType parameter.
* @param object
* The XPath will be executed relative to this object.
* @param xPath
* The XPath statement.
* @param namespaceResolver
* A NamespaceResolver
containing the prefix/URI pairings from the XPath statement.
* @param returnType
* The return type.
*
* @return
* The object corresponding to the XPath or null if no result was found.
*/
public T getValueByXPath(Object object, String xPath, NamespaceResolver namespaceResolver, Class returnType) {
return getXMLContext().getValueByXPath(object, xPath, namespaceResolver, returnType);
}
/**
* Set a value on an object based on an XPath statement.
*
* @param object
* The XPath will be executed relative to this object.
* @param xPath
* The XPath statement.
* @param namespaceResolver
* A NamespaceResolver
containing the prefix/URI pairings from the XPath statement.
* @param value
* The value to be set.
*/
public void setValueByXPath(Object object, String xPath, NamespaceResolver namespaceResolver, Object value) {
getXMLContext().setValueByXPath(object, xPath, namespaceResolver, value);
}
/**
* Create a new object instance for a given XML namespace and name.
*
* @param namespace
* The namespace of the complex type to create a new Java instance of.
* @param typeName
* The XML type name to create a new Java instance of.
* @param isGlobalType
* True if the object to be created represents a global type, false if it
* represents a global element.
*
* @return
* An instance of the Java class mapped to the indicated XML type, or null
* if no result was found.
*/
public Object createByQualifiedName(String namespace, String typeName, boolean isGlobalType) {
return getXMLContext().createByQualifiedName(namespace, typeName, isGlobalType);
}
/**
* Create a new object instance for a given XPath, relative to the parentObject.
*
* @param
* The return type of this method corresponds to the returnType parameter.
* @param parentObject
* The XPath will be executed relative to this object.
* @param xPath
* The XPath statement.
* @param namespaceResolver
* A NamespaceResolver containing the prefix/URI pairings from the XPath statement.
* @param returnType
* The return type.
*
* @return
* An instance of the Java class mapped to the supplied XML type, or null
* if no result was found.
*/
public T createByXPath(Object parentObject, String xPath, NamespaceResolver namespaceResolver, Class returnType) {
return getXMLContext().createByXPath(parentObject, xPath, namespaceResolver, returnType);
}
public ObjectGraph createObjectGraph(Class type) {
CoreAttributeGroup group = new CoreAttributeGroup(null, type, true);
return new ObjectGraphImpl(group);
}
public ObjectGraph createObjectGraph(String typeName) {
ClassLoader loader = this.contextInput.classLoader;
try {
Class cls = PrivilegedAccessHelper.getClassForName(typeName, true, loader);
return createObjectGraph(cls);
} catch (Exception ex) {
throw ConversionException.couldNotBeConvertedToClass(typeName, Class.class, ex);
}
}
protected JAXBElement createJAXBElementFromXMLRoot(Root xmlRoot, Class declaredType) {
Object value = xmlRoot.getObject();
if (value instanceof List) {
List theList = (List) value;
for (int i = 0; i < theList.size(); i++) {
Object next = theList.get(i);
if (next instanceof Root) {
theList.set(i, createJAXBElementFromXMLRoot((Root) next, declaredType));
}
}
} else if (value instanceof WrappedValue) {
QName qname = new QName(xmlRoot.getNamespaceURI(), xmlRoot.getLocalName());
return new JAXBElement(qname, ((WrappedValue) value).getDeclaredType(), ((WrappedValue) value).getValue());
} else if (value instanceof JAXBElement) {
return (JAXBElement) value;
} else if (value instanceof ManyValue) {
value = ((ManyValue) value).getItem();
}
QName qname = new QName(xmlRoot.getNamespaceURI(), xmlRoot.getLocalName());
Map qNamesToDeclaredClasses = getQNamesToDeclaredClasses();
if (qNamesToDeclaredClasses != null && qNamesToDeclaredClasses.size() > 0) {
Class declaredClass = qNamesToDeclaredClasses.get(qname);
if (declaredClass != null) {
return createJAXBElement(qname, declaredClass, value);
}
}
Class xmlRootDeclaredType = xmlRoot.getDeclaredType();
if (xmlRootDeclaredType != null) {
return createJAXBElement(qname, xmlRootDeclaredType, value);
}
return createJAXBElement(qname, declaredType, value);
}
protected JAXBElement createJAXBElement(QName qname, Class theClass, Object value) {
if (theClass == null) {
return new JAXBElement(qname, Object.class, value);
}
if (CoreClassConstants.XML_GREGORIAN_CALENDAR.isAssignableFrom(theClass)) {
theClass = CoreClassConstants.XML_GREGORIAN_CALENDAR;
} else if (CoreClassConstants.DURATION.isAssignableFrom(theClass)) {
theClass = CoreClassConstants.DURATION;
}
return new JAXBElement(qname, theClass, value);
}
/**
* Returns true if any Object in this context contains a property annotated with an XmlAttachmentRef
* annotation.
* @return
*/
public boolean hasSwaRef() {
return contextState.getGenerator().getAnnotationsProcessor().hasSwaRef();
}
/**
* The JAXBContextInput is used to create a JAXBContextState which is responsible for accessing
* the underlying XMLContext
*/
public static abstract class JAXBContextInput {
protected Map properties;
protected ClassLoader classLoader;
/**
* Create a new JAXBContextInput with the specified Map of properties and ClassLoader.
* @param properties Map of properties.
* @param classLoader the classLoader to use. If null then Thread.currentThread().getContextClassLoader() will be used.
*/
public JAXBContextInput(Map properties, ClassLoader classLoader) {
SessionLog logger = AbstractSessionLog.getLog();
if (properties != null && logger.shouldLog(SessionLog.FINE, SessionLog.MOXY)) {
for (Map.Entry