All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*
 * 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.util.Map;

import jakarta.xml.bind.JAXBException;

import javax.xml.namespace.QName;
import javax.xml.transform.Source;

import org.eclipse.persistence.internal.core.helper.CoreClassConstants;
import org.eclipse.persistence.internal.oxm.Constants;
import org.eclipse.persistence.internal.oxm.XMLConversionManager;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext.MetadataContextInput;
import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext.SchemaContextInput;
import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext.SessionsXmlContextInput;
import org.w3c.dom.Node;
import org.xml.sax.EntityResolver;

/**
 * 

* DynamicJAXBContextFactory allows the user to create a DynamicJAXBContext without having * realized Java classes available on the classpath. During context creation, the user's * metadata will be analyzed, and in-memory classes will be generated. *

* *

* Objects that are returned by EclipseLink unmarshal methods will be subclasses of DynamicEntity. * DynamicEntities offer a simple get(propertyName) / set(propertyName, propertyValue) API to * manipulate their data. *

* *

* Example: *

* *

* ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
* InputStream iStream = classLoader.getResourceAsStream("resource/MySchema.xsd");

* * Map<String, Object> properties = new HashMap<String, Object>();
* properties.put(DynamicJAXBContextFactory.XML_SCHEMA_KEY, iStream);

* * DynamicJAXBContext jaxbContext = (DynamicJAXBContext) JAXBContext.newInstance("org.example", classLoader, properties);

* * DynamicEntity employee = jaxbContext.newDynamicEntity("org.example.Employee");
* employee.set("firstName", "Bob");
* employee.set("lastName", "Barker");
* jaxbContext.createMarshaller().(employee, System.out); *

* * @see jakarta.xml.bind.JAXBContext * @see org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext * @see org.eclipse.persistence.dynamic.DynamicEntity * @see org.eclipse.persistence.dynamic.DynamicType * * @author rbarkhouse * @since EclipseLink 2.1 */ public class DynamicJAXBContextFactory { public static final String XML_SCHEMA_KEY = "xml-schema"; public static final String ENTITY_RESOLVER_KEY = "entity-resolver"; public static final String EXTERNAL_BINDINGS_KEY = "external-bindings"; public static final String SCHEMAMETADATA_CLASS_NAME = "org.eclipse.persistence.jaxb.dynamic.metadata.SchemaMetadata"; /** * Creates an instance of {@code DynamicJAXBContextFactory}. */ public DynamicJAXBContextFactory() { } /** * Create a DynamicJAXBContext, using either an XML Schema, EclipseLink OXM file, * or EclipseLink sessions.xml as the metadata source. This creation method will be * called if the user calls the newInstance() method on jakarta.xml.bind.JAXBContext, * and has specified jakarta.xml.bind.JAXBContextFactory=org.eclipse.persistence.jaxb.DynamicJAXBContextFactory in their * jaxb.properties file.

* * -- Context Creation From XML Schema --

* * The properties map must contain the following key/value pairs: *

*
DynamicJAXBContextFactory.XML_SCHEMA_KEY *
Either a org.w3c.dom.Node, javax.xml.transform.Source, or java.io.InputStream pointing to the XML Schema *
DynamicJAXBContextFactory.ENTITY_RESOLVER_KEY *
An org.xml.sax.EntityResolver, used to resolve schema imports. Can be null. *
* * Example: *
     * ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
     * InputStream iStream = classLoader.getResourceAsStream("resource/MySchema.xsd");
     *
     * Map<String, Object> properties = new HashMap<String, Object>();
     * properties.put(DynamicJAXBContextFactory.XML_SCHEMA_KEY, iStream);
     *
     * DynamicJAXBContext jaxbContext = (DynamicJAXBContext) JAXBContext.newInstance("org.example", classLoader, properties);
     * DynamicEntity emp = jaxbContext.newDynamicEntity("org.example.Employee");
     * ...
     * 
* * Context Creation From EclipseLink OXM:

* * The properties map must contain the key JAXBContextProperties.OXM_METADATA_SOURCE, which can have * several possible values: * *

    *
  • One of the following, pointing to your OXM file: 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, or org.xml.sax.InputSource. *
  • A List of objects from the set above. *
  • A Map<String, Object>, where String is a package name, and Object is the pointer to the OXM file, from the set
    * of possibilities above. If using this option, a package-name element is not required in the xml-bindings * element of your OXM file. *
* * Example: *
     * ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
     * InputStream iStream = classLoader.getResourceAsStream("resource/eclipselink-oxm.xml");
     *
     * Map<String, Object> properties = new HashMap<String, Object>();
     * properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, iStream);
     *
     * DynamicJAXBContext jaxbContext = (DynamicJAXBContext) JAXBContext.newInstance("org.example", classLoader, properties);
     * DynamicEntity emp = jaxbContext.newDynamicEntity("org.example.Employee");
     * ...
     * 
* * Context Creation From EclipseLink sessions.xml:

* * The sessionNames parameter is a colon-delimited list of session names within the * sessions.xml file. Descriptors in this session's Project must not * have javaClass set, but must have javaClassName set.

* * Example: *

     * ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
     *
     * DynamicJAXBContext jaxbContext = (DynamicJAXBContext) JAXBContext.newInstance("org.example", classLoader, null);
     * DynamicEntity emp = jaxbContext.newDynamicEntity("org.example.Employee");
     * ...
     * 
* * @param contextPath * A colon-delimited String specifying the packages containing jaxb.properties. If bootstrapping * from EclipseLink sessions.xml, this will also be the name(s) of your sessions. * @param classLoader * The application's current class loader, which will be used to first lookup * classes to see if they exist before new DynamicTypes are generated. Can be * null, in which case Thread.currentThread().getContextClassLoader() will be used. * @param properties * Map of properties to use when creating a new DynamicJAXBContext. Can be null if bootstrapping from sessions.xml. * * @return * A new instance of DynamicJAXBContext. * * @throws JAXBException * if an error was encountered while creating the DynamicJAXBContext. */ public static DynamicJAXBContext createContext(String contextPath, ClassLoader classLoader, Map properties) throws JAXBException { Object schema = null; EntityResolver resolver = null; Object bindings = null; if (properties != null) { schema = properties.get(XML_SCHEMA_KEY); resolver = (EntityResolver) properties.get(ENTITY_RESOLVER_KEY); if ((bindings = properties.get(JAXBContextProperties.OXM_METADATA_SOURCE)) == null) { // try looking up the 'old' metadata source key bindings = properties.get(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY); } } // First try looking for an XSD if (schema != null) { if (schema instanceof Node) { return createContextFromXSD((Node) schema, resolver, classLoader, properties); } if (schema instanceof InputStream) { return createContextFromXSD((InputStream) schema, resolver, classLoader, properties); } if (schema instanceof Source) { return createContextFromXSD((Source) schema, resolver, classLoader, properties); } } // Next, check for OXM if (bindings != null) { return createContextFromOXM(classLoader, properties); } // Lastly, try sessions.xml if (contextPath != null) { return new DynamicJAXBContext(new SessionsXmlContextInput(contextPath, properties, classLoader)); } else { throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.nullSessionName()); } } /** * Unsupported Operation. DynamicJAXBConexts can not be created from concrete classes. Use the standard * JAXBContext to create a context from existing Classes. * * @see org.eclipse.persistence.jaxb.JAXBContext */ public static DynamicJAXBContext createContext(Class[] classes, Map properties) throws JAXBException { throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.cannotCreateDynamicContextFromClasses()); } /** * Create a DynamicJAXBContext, using XML Schema as the metadata source. * * @param schemaDOM * org.w3c.dom.Node representing the XML Schema. * @param resolver * An org.xml.sax.EntityResolver, used to resolve schema imports. Can be null. * @param classLoader * The application's current class loader, which will be used to first lookup * classes to see if they exist before new DynamicTypes are generated. Can be * null, in which case Thread.currentThread().getContextClassLoader() will be used. * @param properties * Map of properties to use when creating a new DynamicJAXBContext. Can be null. * * @return * A new instance of DynamicJAXBContext. * * @throws JAXBException * if an error was encountered while creating the DynamicJAXBContext. */ public static DynamicJAXBContext createContextFromXSD(Node schemaDOM, EntityResolver resolver, ClassLoader classLoader, Map properties) throws JAXBException { if (schemaDOM == null) { throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.nullNode()); } if (resolver != null) { // If schema and resolver are both specified, this indicates a schema import // This is not supported when boostrapping from a Node. throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.xsdImportNotSource()); } DynamicJAXBContext ctx = new DynamicJAXBContext(new SchemaContextInput(schemaDOM, null, properties, classLoader)); fixDateTimeConversion(ctx); return ctx; } /** * Create a DynamicJAXBContext, using XML Schema as the metadata source. * * @param schemaStream * java.io.InputStream from which to read the XML Schema. * @param resolver * An org.xml.sax.EntityResolver, used to resolve schema imports. Can be null. * @param classLoader * The application's current class loader, which will be used to first lookup * classes to see if they exist before new DynamicTypes are generated. Can be * null, in which case Thread.currentThread().getContextClassLoader() will be used. * @param properties * Map of properties to use when creating a new DynamicJAXBContext. Can be null. * * @return * A new instance of DynamicJAXBContext. * * @throws JAXBException * if an error was encountered while creating the DynamicJAXBContext. */ public static DynamicJAXBContext createContextFromXSD(InputStream schemaStream, EntityResolver resolver, ClassLoader classLoader, Map properties) throws JAXBException { if (schemaStream == null) { throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.nullInputStream()); } DynamicJAXBContext ctx = new DynamicJAXBContext(new SchemaContextInput(schemaStream, resolver, properties, classLoader)); fixDateTimeConversion(ctx); return ctx; } /** * Create a DynamicJAXBContext, using XML Schema as the metadata source. * * @param schemaSource * javax.xml.transform.Source from which to read the XML Schema. * @param resolver * An org.xml.sax.EntityResolver, used to resolve schema imports. Can be null. * @param classLoader * The application's current class loader, which will be used to first lookup * classes to see if they exist before new DynamicTypes are generated. Can be * null, in which case Thread.currentThread().getContextClassLoader() will be used. * @param properties * Map of properties to use when creating a new DynamicJAXBContext. Can be null. * * @return * A new instance of DynamicJAXBContext. * * @throws JAXBException * if an error was encountered while creating the DynamicJAXBContext. */ public static DynamicJAXBContext createContextFromXSD(Source schemaSource, EntityResolver resolver, ClassLoader classLoader, Map properties) throws JAXBException { if (schemaSource == null) { throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.nullSource()); } DynamicJAXBContext ctx = new DynamicJAXBContext(new SchemaContextInput(schemaSource, resolver, properties, classLoader)); fixDateTimeConversion(ctx); return ctx; } /** * Create a DynamicJAXBContext, using an EclipseLink OXM file as the metadata source. * * @param classLoader * The application's current class loader, which will be used to first lookup * classes to see if they exist before new DynamicTypes are generated. Can be * null, in which case Thread.currentThread().getContextClassLoader() will be used. * @param properties * Map of properties to use when creating a new DynamicJAXBContext. This map must * contain a key of JAXBContextProperties.OXM_METADATA_SOURCE, which can have several possible values: * *
    *
  • One of the following, pointing to your OXM file: 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, or org.xml.sax.InputSource. *
  • A List of objects from the set above. *
  • A Map<String, Object>, where String is a package name, and Object is the pointer to the OXM file, from the set
    * of possibilities above. If using this option, a package-name element is not required in the xml-bindings * element of your OXM file. *
* * * @return * A new instance of DynamicJAXBContext. * * @throws JAXBException * if an error was encountered while creating the DynamicJAXBContext. */ public static DynamicJAXBContext createContextFromOXM(ClassLoader classLoader, Map properties) throws JAXBException { if (properties == null || (properties.get(JAXBContextProperties.OXM_METADATA_SOURCE) == null && properties.get(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY) == null)) { throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.oxmKeyNotFound()); } return new DynamicJAXBContext(new MetadataContextInput(properties, classLoader)); } /** * Ensures that XSD dateTimes will always be unmarshalled as XMLGregorianCalendars, and never * as GregorianCalendars. CALENDAR entries are removed from the default XMLConversionManager, * and replaced with XML_GREGORIAN_CALENDAR. */ private static void fixDateTimeConversion(DynamicJAXBContext ctx) { XMLConversionManager conversionManager = (XMLConversionManager) ctx.getXMLContext().getSession().getDatasourcePlatform().getConversionManager(); Map> defaultXmlTypes = XMLConversionManager.getDefaultXMLTypes(); defaultXmlTypes.remove(Constants.DATE_TIME_QNAME); defaultXmlTypes.put(Constants.DATE_TIME_QNAME, CoreClassConstants.XML_GREGORIAN_CALENDAR); Map, QName> defaultJavaTypes = XMLConversionManager.getDefaultJavaTypes(); defaultJavaTypes.remove(CoreClassConstants.CALENDAR); defaultJavaTypes.put(CoreClassConstants.XML_GREGORIAN_CALENDAR, Constants.DATE_TIME_QNAME); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy