Merge
This commit is contained in:
commit
94c4895e47
@ -68,6 +68,9 @@ class ContextFinder {
|
||||
*/
|
||||
private static final String PLATFORM_DEFAULT_FACTORY_CLASS = "com.sun.xml.internal.bind.v2.ContextFactory";
|
||||
|
||||
// previous value of JAXBContext.JAXB_CONTEXT_FACTORY, using also this to ensure backwards compatibility
|
||||
private static final String JAXB_CONTEXT_FACTORY_DEPRECATED = "javax.xml.bind.context.factory";
|
||||
|
||||
private static final Logger logger;
|
||||
|
||||
static {
|
||||
@ -92,6 +95,14 @@ class ContextFinder {
|
||||
}
|
||||
}
|
||||
|
||||
private static ServiceLoaderUtil.ExceptionHandler<JAXBException> EXCEPTION_HANDLER =
|
||||
new ServiceLoaderUtil.ExceptionHandler<JAXBException>() {
|
||||
@Override
|
||||
public JAXBException createException(Throwable throwable, String message) {
|
||||
return new JAXBException(message, throwable);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* If the {@link InvocationTargetException} wraps an exception that shouldn't be wrapped,
|
||||
* throw the wrapped exception.
|
||||
@ -159,7 +170,10 @@ class ContextFinder {
|
||||
}
|
||||
}
|
||||
|
||||
static JAXBContext newInstance(String contextPath, Class spFactory, ClassLoader classLoader, Map properties) throws JAXBException {
|
||||
static JAXBContext newInstance(String contextPath,
|
||||
Class spFactory,
|
||||
ClassLoader classLoader,
|
||||
Map properties) throws JAXBException {
|
||||
|
||||
try {
|
||||
/*
|
||||
@ -239,6 +253,7 @@ class ContextFinder {
|
||||
Map properties,
|
||||
Class spFactory) throws JAXBException {
|
||||
try {
|
||||
|
||||
Method m = spFactory.getMethod("createContext", Class[].class, Map.class);
|
||||
Object context = m.invoke(null, classes, properties);
|
||||
if (!(context instanceof JAXBContext)) {
|
||||
@ -246,10 +261,10 @@ class ContextFinder {
|
||||
throw handleClassCastException(context.getClass(), JAXBContext.class);
|
||||
}
|
||||
return (JAXBContext) context;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new JAXBException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
throw new JAXBException(e);
|
||||
|
||||
} catch (InvocationTargetException e) {
|
||||
handleInvocationTargetException(e);
|
||||
|
||||
@ -261,9 +276,10 @@ class ContextFinder {
|
||||
}
|
||||
}
|
||||
|
||||
static JAXBContext find(String factoryId, String contextPath, ClassLoader classLoader, Map properties) throws JAXBException {
|
||||
|
||||
// TODO: do we want/need another layer of searching in $java.home/lib/jaxb.properties like JAXP?
|
||||
static JAXBContext find(String factoryId,
|
||||
String contextPath,
|
||||
ClassLoader classLoader,
|
||||
Map properties) throws JAXBException {
|
||||
|
||||
StringTokenizer packages = new StringTokenizer(contextPath, ":");
|
||||
if (!packages.hasMoreTokens()) {
|
||||
@ -275,63 +291,85 @@ class ContextFinder {
|
||||
logger.fine("Searching jaxb.properties");
|
||||
while (packages.hasMoreTokens()) {
|
||||
// com.acme.foo - > com/acme/foo/jaxb.properties
|
||||
String className = classNameFromPackageProperties(factoryId, classLoader, packages.nextToken(":").replace('.', '/'));
|
||||
if (className != null) return newInstance(contextPath, className, classLoader, properties);
|
||||
String factoryClassName =
|
||||
classNameFromPackageProperties(
|
||||
classLoader,
|
||||
packages.nextToken(":").replace('.', '/'),
|
||||
factoryId,
|
||||
JAXB_CONTEXT_FACTORY_DEPRECATED);
|
||||
|
||||
if (factoryClassName != null) {
|
||||
return newInstance(contextPath, factoryClassName, classLoader, properties);
|
||||
}
|
||||
}
|
||||
|
||||
String factoryName = classNameFromSystemProperties();
|
||||
if (factoryName != null) return newInstance(contextPath, factoryName, classLoader, properties);
|
||||
|
||||
Class ctxFactory = (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader("javax.xml.bind.JAXBContext", logger);
|
||||
JAXBContextFactory obj = ServiceLoaderUtil.firstByServiceLoader(
|
||||
JAXBContextFactory.class, logger, EXCEPTION_HANDLER);
|
||||
|
||||
if (obj != null) return obj.createContext(contextPath, classLoader, properties);
|
||||
|
||||
// to ensure backwards compatibility
|
||||
factoryName = firstByServiceLoaderDeprecated(JAXBContext.class, classLoader);
|
||||
if (factoryName != null) return newInstance(contextPath, factoryName, classLoader, properties);
|
||||
|
||||
Class ctxFactory = (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader(
|
||||
"javax.xml.bind.JAXBContext", logger);
|
||||
|
||||
if (ctxFactory != null) {
|
||||
return newInstance(contextPath, ctxFactory, classLoader, properties);
|
||||
}
|
||||
|
||||
// TODO: SPEC change required! This is supposed to be!
|
||||
// JAXBContext obj = firstByServiceLoader(JAXBContext.class, EXCEPTION_HANDLER);
|
||||
// if (obj != null) return obj;
|
||||
|
||||
// TODO: Deprecated - SPEC change required!
|
||||
factoryName = firstByServiceLoaderDeprecated(JAXBContext.class, classLoader);
|
||||
if (factoryName != null) return newInstance(contextPath, factoryName, classLoader, properties);
|
||||
|
||||
// else no provider found
|
||||
logger.fine("Trying to create the platform default provider");
|
||||
return newInstance(contextPath, PLATFORM_DEFAULT_FACTORY_CLASS, classLoader, properties);
|
||||
}
|
||||
|
||||
static JAXBContext find(Class[] classes, Map properties) throws JAXBException {
|
||||
static JAXBContext find(Class<?>[] classes, Map<String, ?> properties) throws JAXBException {
|
||||
|
||||
// search for jaxb.properties in the class loader of each class first
|
||||
logger.fine("Searching jaxb.properties");
|
||||
for (final Class c : classes) {
|
||||
// this classloader is used only to load jaxb.properties, so doing this should be safe.
|
||||
if (c.getPackage() == null) continue; // this is possible for primitives, arrays, and classes that are loaded by poorly implemented ClassLoaders
|
||||
// this is possible for primitives, arrays, and classes that are
|
||||
// loaded by poorly implemented ClassLoaders
|
||||
if (c.getPackage() == null) continue;
|
||||
|
||||
// TODO: do we want to optimize away searching the same package? org.Foo, org.Bar, com.Baz
|
||||
// classes from the same package might come from different class loades, so it might be a bad idea
|
||||
// TODO: it's easier to look things up from the class
|
||||
// c.getResourceAsStream("jaxb.properties");
|
||||
|
||||
String className = classNameFromPackageProperties(JAXBContext.JAXB_CONTEXT_FACTORY, getClassClassLoader(c), c.getPackage().getName().replace('.', '/'));
|
||||
if (className != null) return newInstance(classes, properties, className);
|
||||
String factoryClassName =
|
||||
classNameFromPackageProperties(
|
||||
getClassClassLoader(c),
|
||||
c.getPackage().getName().replace('.', '/'),
|
||||
JAXBContext.JAXB_CONTEXT_FACTORY, JAXB_CONTEXT_FACTORY_DEPRECATED);
|
||||
|
||||
if (factoryClassName != null) return newInstance(classes, properties, factoryClassName);
|
||||
}
|
||||
|
||||
String factoryName = classNameFromSystemProperties();
|
||||
if (factoryName != null) return newInstance(classes, properties, factoryName);
|
||||
String factoryClassName = classNameFromSystemProperties();
|
||||
if (factoryClassName != null) return newInstance(classes, properties, factoryClassName);
|
||||
|
||||
Class ctxFactoryClass = (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader("javax.xml.bind.JAXBContext", logger);
|
||||
if (ctxFactoryClass != null) {
|
||||
return newInstance(classes, properties, ctxFactoryClass);
|
||||
}
|
||||
JAXBContextFactory factory =
|
||||
ServiceLoaderUtil.firstByServiceLoader(JAXBContextFactory.class, logger, EXCEPTION_HANDLER);
|
||||
|
||||
// TODO: to be removed - deprecated!!! Requires SPEC change!!!
|
||||
if (factory != null) return factory.createContext(classes, properties);
|
||||
|
||||
// to ensure backwards compatibility
|
||||
String className = firstByServiceLoaderDeprecated(JAXBContext.class, getContextClassLoader());
|
||||
if (className != null) return newInstance(classes, properties, className);
|
||||
|
||||
// // TODO: supposed to be:
|
||||
// obj = firstByServiceLoader(JAXBContext.class, EXCEPTION_HANDLER);
|
||||
// if (obj != null) return obj;
|
||||
logger.fine("Trying to create the platform default provider");
|
||||
Class ctxFactoryClass =
|
||||
(Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader("javax.xml.bind.JAXBContext", logger);
|
||||
|
||||
if (ctxFactoryClass != null) {
|
||||
return newInstance(classes, properties, ctxFactoryClass);
|
||||
}
|
||||
|
||||
// else no provider found
|
||||
logger.fine("Trying to create the platform default provider");
|
||||
@ -339,42 +377,69 @@ class ContextFinder {
|
||||
}
|
||||
|
||||
|
||||
private static String classNameFromPackageProperties(String factoryId, ClassLoader classLoader, String packageName) throws JAXBException {
|
||||
/**
|
||||
* first factoryId should be the preffered one,
|
||||
* more of those can be provided to support backwards compatibility
|
||||
*/
|
||||
private static String classNameFromPackageProperties(ClassLoader classLoader,
|
||||
String packageName,
|
||||
String ... factoryIds) throws JAXBException {
|
||||
|
||||
String resourceName = packageName + "/jaxb.properties";
|
||||
logger.log(Level.FINE, "Trying to locate {0}", resourceName);
|
||||
Properties props = loadJAXBProperties(classLoader, resourceName);
|
||||
if (props != null) {
|
||||
if (props.containsKey(factoryId)) {
|
||||
return props.getProperty(factoryId);
|
||||
} else {
|
||||
throw new JAXBException(Messages.format(Messages.MISSING_PROPERTY, packageName, factoryId));
|
||||
for(String factoryId : factoryIds) {
|
||||
if (props.containsKey(factoryId)) {
|
||||
return props.getProperty(factoryId);
|
||||
}
|
||||
}
|
||||
throw new JAXBException(Messages.format(Messages.MISSING_PROPERTY, packageName, factoryIds[0]));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String classNameFromSystemProperties() throws JAXBException {
|
||||
logger.log(Level.FINE, "Checking system property {0}", JAXBContext.JAXB_CONTEXT_FACTORY);
|
||||
// search for a system property second (javax.xml.bind.JAXBContext)
|
||||
String factoryClassName = AccessController.doPrivileged(new GetPropertyAction(JAXBContext.JAXB_CONTEXT_FACTORY));
|
||||
|
||||
String factoryClassName = getSystemProperty(JAXBContext.JAXB_CONTEXT_FACTORY);
|
||||
if (factoryClassName != null) {
|
||||
return factoryClassName;
|
||||
}
|
||||
// leave this here to assure compatibility
|
||||
factoryClassName = getDeprecatedSystemProperty(JAXB_CONTEXT_FACTORY_DEPRECATED);
|
||||
if (factoryClassName != null) {
|
||||
return factoryClassName;
|
||||
}
|
||||
// leave this here to assure compatibility
|
||||
factoryClassName = getDeprecatedSystemProperty(JAXBContext.class.getName());
|
||||
if (factoryClassName != null) {
|
||||
logger.log(Level.FINE, " found {0}", factoryClassName);
|
||||
return factoryClassName;
|
||||
} else { // leave this here to assure compatibility
|
||||
logger.fine(" not found");
|
||||
logger.log(Level.FINE, "Checking system property {0}", JAXBContext.class.getName());
|
||||
factoryClassName = AccessController.doPrivileged(new GetPropertyAction(JAXBContext.class.getName()));
|
||||
if (factoryClassName != null) {
|
||||
logger.log(Level.FINE, " found {0}", factoryClassName);
|
||||
return factoryClassName;
|
||||
} else {
|
||||
logger.fine(" not found");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Properties loadJAXBProperties(ClassLoader classLoader, String propFileName) throws JAXBException {
|
||||
private static String getDeprecatedSystemProperty(String property) {
|
||||
String value = getSystemProperty(property);
|
||||
if (value != null) {
|
||||
logger.log(Level.WARNING, "Using non-standard property: {0}. Property {1} should be used instead.",
|
||||
new Object[] {property, JAXBContext.JAXB_CONTEXT_FACTORY});
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static String getSystemProperty(String property) {
|
||||
logger.log(Level.FINE, "Checking system property {0}", property);
|
||||
String value = AccessController.doPrivileged(new GetPropertyAction(property));
|
||||
if (value != null) {
|
||||
logger.log(Level.FINE, " found {0}", value);
|
||||
} else {
|
||||
logger.log(Level.FINE, " not found");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static Properties loadJAXBProperties(ClassLoader classLoader,
|
||||
String propFileName) throws JAXBException {
|
||||
|
||||
Properties props = null;
|
||||
try {
|
||||
@ -480,17 +545,18 @@ class ContextFinder {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: to be removed - SPEC change required
|
||||
// ServiceLoaderUtil.firstByServiceLoaderDeprecated should be used instead.
|
||||
// ServiceLoaderUtil.firstByServiceLoaderDeprecated should be used instead.
|
||||
@Deprecated
|
||||
static String firstByServiceLoaderDeprecated(Class spiClass, ClassLoader classLoader) throws JAXBException {
|
||||
static String firstByServiceLoaderDeprecated(Class spiClass,
|
||||
ClassLoader classLoader) throws JAXBException {
|
||||
|
||||
final String jaxbContextFQCN = spiClass.getName();
|
||||
|
||||
logger.fine("Searching META-INF/services");
|
||||
|
||||
// search META-INF services next
|
||||
BufferedReader r = null;
|
||||
final String resource = new StringBuilder().append("META-INF/services/").append(jaxbContextFQCN).toString();
|
||||
final String resource = "META-INF/services/" + jaxbContextFQCN;
|
||||
try {
|
||||
final InputStream resourceStream =
|
||||
(classLoader == null) ?
|
||||
@ -510,9 +576,6 @@ class ContextFinder {
|
||||
logger.log(Level.FINE, "Unable to load:{0}", resource);
|
||||
return null;
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// should never happen
|
||||
throw new JAXBException(e);
|
||||
} catch (IOException e) {
|
||||
throw new JAXBException(e);
|
||||
} finally {
|
||||
|
@ -45,29 +45,20 @@ import java.io.InputStream;
|
||||
* specialized forms of the method available:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #newInstance(String,ClassLoader) JAXBContext.newInstance( "com.acme.foo:com.acme.bar" )} <br>
|
||||
* The JAXBContext instance is initialized from a list of colon
|
||||
* separated Java package names. Each java package contains
|
||||
* JAXB mapped classes, schema-derived classes and/or user annotated
|
||||
* classes. Additionally, the java package may contain JAXB package annotations
|
||||
* that must be processed. (see JLS, Section 7.4.1 "Named Packages").
|
||||
* </li>
|
||||
* <li>{@link #newInstance(Class...) JAXBContext.newInstance( com.acme.foo.Foo.class )} <br>
|
||||
* The JAXBContext instance is initialized with class(es)
|
||||
* passed as parameter(s) and classes that are statically reachable from
|
||||
* these class(es). See {@link #newInstance(Class...)} for details.
|
||||
* </li>
|
||||
* <li>{@link #newInstance(String, ClassLoader) JAXBContext.newInstance( "com.acme.foo:com.acme.bar" )} <br>
|
||||
* The JAXBContext instance is initialized from a list of colon
|
||||
* separated Java package names. Each java package contains
|
||||
* JAXB mapped classes, schema-derived classes and/or user annotated
|
||||
* classes. Additionally, the java package may contain JAXB package annotations
|
||||
* that must be processed. (see JLS, Section 7.4.1 "Named Packages").
|
||||
* </li>
|
||||
* <li>{@link #newInstance(Class...) JAXBContext.newInstance( com.acme.foo.Foo.class )} <br>
|
||||
* The JAXBContext instance is initialized with class(es)
|
||||
* passed as parameter(s) and classes that are statically reachable from
|
||||
* these class(es). See {@link #newInstance(Class...)} for details.
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* <i><B>SPEC REQUIREMENT:</B> the provider must supply an implementation
|
||||
* class containing the following method signatures:</i>
|
||||
*
|
||||
* <pre>{@code
|
||||
* public static JAXBContext createContext( String contextPath, ClassLoader classLoader, Map<String,Object> properties ) throws JAXBException
|
||||
* public static JAXBContext createContext( Class[] classes, Map<String,Object> properties ) throws JAXBException
|
||||
* }</pre>
|
||||
*
|
||||
* <p><i>
|
||||
* The following JAXB 1.0 requirement is only required for schema to
|
||||
* java interface/implementation binding. It does not apply to JAXB annotated
|
||||
@ -109,11 +100,11 @@ import java.io.InputStream;
|
||||
* any of the schemas listed in the <tt>contextPath</tt>. For example:
|
||||
*
|
||||
* <pre>
|
||||
* JAXBContext jc = JAXBContext.newInstance( "com.acme.foo:com.acme.bar" );
|
||||
* Unmarshaller u = jc.createUnmarshaller();
|
||||
* FooObject fooObj = (FooObject)u.unmarshal( new File( "foo.xml" ) ); // ok
|
||||
* BarObject barObj = (BarObject)u.unmarshal( new File( "bar.xml" ) ); // ok
|
||||
* BazObject bazObj = (BazObject)u.unmarshal( new File( "baz.xml" ) ); // error, "com.acme.baz" not in contextPath
|
||||
* JAXBContext jc = JAXBContext.newInstance( "com.acme.foo:com.acme.bar" );
|
||||
* Unmarshaller u = jc.createUnmarshaller();
|
||||
* FooObject fooObj = (FooObject)u.unmarshal( new File( "foo.xml" ) ); // ok
|
||||
* BarObject barObj = (BarObject)u.unmarshal( new File( "bar.xml" ) ); // ok
|
||||
* BazObject bazObj = (BazObject)u.unmarshal( new File( "baz.xml" ) ); // error, "com.acme.baz" not in contextPath
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
@ -146,7 +137,7 @@ import java.io.InputStream;
|
||||
* Section 4.2 <i>Java Package</i> of the specification.
|
||||
*
|
||||
* <p>
|
||||
* <i><B>SPEC REQUIREMENT:</B> the provider must generate a class in each
|
||||
* <i>The provider must generate a class in each
|
||||
* package that contains all of the necessary object factory methods for that
|
||||
* package named ObjectFactory as well as the static
|
||||
* <tt>newInstance( javaContentInterface )</tt> method</i>
|
||||
@ -214,6 +205,7 @@ import java.io.InputStream;
|
||||
* by the following steps.
|
||||
*
|
||||
* <ol>
|
||||
*
|
||||
* <li>
|
||||
* For each package/class explicitly passed in to the {@link #newInstance} method, in the order they are specified,
|
||||
* <tt>jaxb.properties</tt> file is looked up in its package, by using the associated classloader —
|
||||
@ -223,7 +215,7 @@ import java.io.InputStream;
|
||||
* <p>
|
||||
* If such a file is discovered, it is {@link Properties#load(InputStream) loaded} as a property file, and
|
||||
* the value of the {@link #JAXB_CONTEXT_FACTORY} key will be assumed to be the provider factory class.
|
||||
* This class is then loaded by the associated classloader discussed above.
|
||||
* This class is then loaded by the associated class loader discussed above.
|
||||
*
|
||||
* <p>
|
||||
* This phase of the look up allows some packages to force the use of a certain JAXB implementation.
|
||||
@ -234,10 +226,36 @@ import java.io.InputStream;
|
||||
* factory class. This phase of the look up enables per-JVM override of the JAXB implementation.
|
||||
*
|
||||
* <li>
|
||||
* Look for <tt>/META-INF/services/javax.xml.bind.JAXBContext</tt> file in the associated classloader.
|
||||
* This file follows the standard service descriptor convention, and if such a file exists, its content
|
||||
* is assumed to be the provider factory class. This phase of the look up is for automatic discovery.
|
||||
* It allows users to just put a JAXB implementation in a classpath and use it without any furhter configuration.
|
||||
* Provider of {@link javax.xml.bind.JAXBContextFactory} is loaded using the service-provider loading
|
||||
* facilities, defined by the {@link java.util.ServiceLoader} class, to attempt
|
||||
* to locate and load an implementation of the service using the {@linkplain
|
||||
* java.util.ServiceLoader#load(java.lang.Class) default loading mechanism}: the service-provider loading facility
|
||||
* will use the {@linkplain java.lang.Thread#getContextClassLoader() current thread's context class loader}
|
||||
* to attempt to load the context factory. If the context class loader is null, the
|
||||
* {@linkplain ClassLoader#getSystemClassLoader() system class loader} will be used.
|
||||
* <br>
|
||||
* In case of {@link java.util.ServiceConfigurationError service
|
||||
* configuration error} a {@link javax.xml.bind.JAXBException} will be thrown.
|
||||
* </li>
|
||||
*
|
||||
* <li>
|
||||
* Look for resource {@code /META-INF/services/javax.xml.bind.JAXBContext} using provided class loader.
|
||||
* Methods without class loader parameter use {@code Thread.currentThread().getContextClassLoader()}.
|
||||
* If such a resource exists, its content is assumed to be the provider factory class and must supply
|
||||
* an implementation class containing the following method signatures:
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* public static JAXBContext createContext(
|
||||
* String contextPath,
|
||||
* ClassLoader classLoader,
|
||||
* Map<String,Object> properties throws JAXBException
|
||||
*
|
||||
* public static JAXBContext createContext(
|
||||
* Class[] classes,
|
||||
* Map<String,Object> properties ) throws JAXBException
|
||||
* </pre>
|
||||
* This configuration method is deprecated.
|
||||
*
|
||||
* <li>
|
||||
* Finally, if all the steps above fail, then the rest of the look up is unspecified. That said,
|
||||
@ -246,17 +264,30 @@ import java.io.InputStream;
|
||||
* </ol>
|
||||
*
|
||||
* <p>
|
||||
* Once the provider factory class is discovered, its
|
||||
* <tt>public static JAXBContext createContext(String,ClassLoader,Map)</tt> method
|
||||
* (see {@link #newInstance(String, ClassLoader, Map)} for the parameter semantics.)
|
||||
* or <tt>public static JAXBContext createContet(Class[],Map)</tt> method
|
||||
* (see {@link #newInstance(Class[], Map)} for the parameter semantics) are invoked
|
||||
* Once the provider factory class {@link javax.xml.bind.JAXBContextFactory} is discovered, one of its methods
|
||||
* {@link javax.xml.bind.JAXBContextFactory#createContext(String, ClassLoader, java.util.Map)} or
|
||||
* {@link javax.xml.bind.JAXBContextFactory#createContext(Class[], java.util.Map)} is invoked
|
||||
* to create a {@link JAXBContext}.
|
||||
*
|
||||
* @author <ul><li>Ryan Shoemaker, Sun Microsystems, Inc.</li><li>Kohsuke Kawaguchi, Sun Microsystems, Inc.</li><li>Joe Fialli, Sun Microsystems, Inc.</li></ul>
|
||||
* <p/>
|
||||
*
|
||||
* @apiNote
|
||||
* <p>Service discovery method using file /META-INF/services/javax.xml.bind.JAXBContext (described in step 4)
|
||||
* and leveraging provider's static methods is supported only to allow backwards compatibility, but it is strongly
|
||||
* recommended to migrate to standard ServiceLoader mechanism (described in step 3).
|
||||
*
|
||||
* @implNote
|
||||
* Within the last step, if Glassfish AS environment detected, its specific service loader is used to find factory class.
|
||||
*
|
||||
* @author <ul><li>Ryan Shoemaker, Sun Microsystems, Inc.</li>
|
||||
* <li>Kohsuke Kawaguchi, Sun Microsystems, Inc.</li>
|
||||
* <li>Joe Fialli, Sun Microsystems, Inc.</li></ul>
|
||||
*
|
||||
* @see Marshaller
|
||||
* @see Unmarshaller
|
||||
* @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-7.html#jls-7.4.1">S 7.4.1 "Named Packages" in Java Language Specification</a>
|
||||
* @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-7.html#jls-7.4.1">S 7.4.1 "Named Packages"
|
||||
* in Java Language Specification</a>
|
||||
*
|
||||
* @since 1.6, JAXB 1.0
|
||||
*/
|
||||
public abstract class JAXBContext {
|
||||
@ -265,9 +296,7 @@ public abstract class JAXBContext {
|
||||
* The name of the property that contains the name of the class capable
|
||||
* of creating new <tt>JAXBContext</tt> objects.
|
||||
*/
|
||||
public static final String JAXB_CONTEXT_FACTORY =
|
||||
"javax.xml.bind.context.factory";
|
||||
|
||||
public static final String JAXB_CONTEXT_FACTORY = "javax.xml.bind.JAXBContextFactory";
|
||||
|
||||
protected JAXBContext() {
|
||||
}
|
||||
@ -275,7 +304,7 @@ public abstract class JAXBContext {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Obtain a new instance of a <tt>JAXBContext</tt> class.
|
||||
* Create a new instance of a <tt>JAXBContext</tt> class.
|
||||
*
|
||||
* <p>
|
||||
* This is a convenience method to invoke the
|
||||
@ -300,7 +329,7 @@ public abstract class JAXBContext {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Obtain a new instance of a <tt>JAXBContext</tt> class.
|
||||
* Create a new instance of a <tt>JAXBContext</tt> class.
|
||||
*
|
||||
* <p>
|
||||
* The client application must supply a context path which is a list of
|
||||
@ -396,7 +425,7 @@ public abstract class JAXBContext {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Obtain a new instance of a <tt>JAXBContext</tt> class.
|
||||
* Create a new instance of a <tt>JAXBContext</tt> class.
|
||||
*
|
||||
* <p>
|
||||
* This is mostly the same as {@link JAXBContext#newInstance(String, ClassLoader)},
|
||||
@ -425,8 +454,9 @@ public abstract class JAXBContext {
|
||||
* </ol>
|
||||
* @since 1.6, JAXB 2.0
|
||||
*/
|
||||
public static JAXBContext newInstance( String contextPath, ClassLoader classLoader, Map<String,?> properties )
|
||||
throws JAXBException {
|
||||
public static JAXBContext newInstance( String contextPath,
|
||||
ClassLoader classLoader,
|
||||
Map<String,?> properties ) throws JAXBException {
|
||||
|
||||
return ContextFinder.find(
|
||||
/* The default property name according to the JAXB spec */
|
||||
@ -443,7 +473,7 @@ public abstract class JAXBContext {
|
||||
// TODO: resurrect this once we introduce external annotations
|
||||
// /**
|
||||
// * <p>
|
||||
// * Obtain a new instance of a <tt>JAXBContext</tt> class.
|
||||
// * Create a new instance of a <tt>JAXBContext</tt> class.
|
||||
// *
|
||||
// * <p>
|
||||
// * The client application must supply a list of classes that the new
|
||||
@ -479,7 +509,7 @@ public abstract class JAXBContext {
|
||||
// * spec-defined classes will be returned.
|
||||
// *
|
||||
// * @return
|
||||
// * A new instance of a <tt>JAXBContext</tt>. Always non-null valid object.
|
||||
// * A new instance of a <tt>JAXBContext</tt>.
|
||||
// *
|
||||
// * @throws JAXBException
|
||||
// * if an error was encountered while creating the
|
||||
@ -517,7 +547,7 @@ public abstract class JAXBContext {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Obtain a new instance of a <tt>JAXBContext</tt> class.
|
||||
* Create a new instance of a <tt>JAXBContext</tt> class.
|
||||
*
|
||||
* <p>
|
||||
* The client application must supply a list of classes that the new
|
||||
@ -559,7 +589,7 @@ public abstract class JAXBContext {
|
||||
* spec-defined classes will be returned.
|
||||
*
|
||||
* @return
|
||||
* A new instance of a <tt>JAXBContext</tt>. Always non-null valid object.
|
||||
* A new instance of a <tt>JAXBContext</tt>.
|
||||
*
|
||||
* @throws JAXBException
|
||||
* if an error was encountered while creating the
|
||||
@ -578,7 +608,7 @@ public abstract class JAXBContext {
|
||||
*
|
||||
* @since 1.6, JAXB 2.0
|
||||
*/
|
||||
public static JAXBContext newInstance( Class... classesToBeBound )
|
||||
public static JAXBContext newInstance( Class<?> ... classesToBeBound )
|
||||
throws JAXBException {
|
||||
|
||||
return newInstance(classesToBeBound,Collections.<String,Object>emptyMap());
|
||||
@ -586,7 +616,7 @@ public abstract class JAXBContext {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Obtain a new instance of a <tt>JAXBContext</tt> class.
|
||||
* Create a new instance of a <tt>JAXBContext</tt> class.
|
||||
*
|
||||
* <p>
|
||||
* An overloading of {@link JAXBContext#newInstance(Class...)}
|
||||
@ -605,7 +635,7 @@ public abstract class JAXBContext {
|
||||
* in an empty map.
|
||||
*
|
||||
* @return
|
||||
* A new instance of a <tt>JAXBContext</tt>. Always non-null valid object.
|
||||
* A new instance of a <tt>JAXBContext</tt>.
|
||||
*
|
||||
* @throws JAXBException
|
||||
* if an error was encountered while creating the
|
||||
@ -624,7 +654,7 @@ public abstract class JAXBContext {
|
||||
*
|
||||
* @since 1.6, JAXB 2.0
|
||||
*/
|
||||
public static JAXBContext newInstance( Class[] classesToBeBound, Map<String,?> properties )
|
||||
public static JAXBContext newInstance( Class<?>[] classesToBeBound, Map<String,?> properties )
|
||||
throws JAXBException {
|
||||
|
||||
if (classesToBeBound == null) {
|
||||
@ -756,9 +786,9 @@ public abstract class JAXBContext {
|
||||
if (System.getSecurityManager() == null) {
|
||||
return Thread.currentThread().getContextClassLoader();
|
||||
} else {
|
||||
return (ClassLoader) java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction() {
|
||||
public java.lang.Object run() {
|
||||
return java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<ClassLoader>() {
|
||||
public ClassLoader run() {
|
||||
return Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
});
|
||||
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.xml.bind;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>Factory that creates new <code>JAXBContext</code> instances.
|
||||
*
|
||||
* JAXBContextFactory can be located using {@link java.util.ServiceLoader#load(Class)}
|
||||
*
|
||||
* @since 1.9, JAXB 2.3
|
||||
*/
|
||||
public interface JAXBContextFactory {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Create a new instance of a <tt>JAXBContext</tt> class.
|
||||
*
|
||||
* <p>
|
||||
* For semantics see {@link javax.xml.bind.JAXBContext#newInstance(Class[], java.util.Map)}
|
||||
*
|
||||
* @param classesToBeBound
|
||||
* list of java classes to be recognized by the new {@link JAXBContext}.
|
||||
* Can be empty, in which case a {@link JAXBContext} that only knows about
|
||||
* spec-defined classes will be returned.
|
||||
* @param properties
|
||||
* provider-specific properties. Can be null, which means the same thing as passing
|
||||
* in an empty map.
|
||||
*
|
||||
* @return
|
||||
* A new instance of a <tt>JAXBContext</tt>.
|
||||
*
|
||||
* @throws JAXBException
|
||||
* if an error was encountered while creating the
|
||||
* <tt>JAXBContext</tt>, such as (but not limited to):
|
||||
* <ol>
|
||||
* <li>Classes use JAXB annotations incorrectly
|
||||
* <li>Classes have colliding annotations (i.e., two classes with the same type name)
|
||||
* <li>The JAXB implementation was unable to locate
|
||||
* provider-specific out-of-band information (such as additional
|
||||
* files generated at the development time.)
|
||||
* </ol>
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if the parameter contains {@code null} (i.e., {@code newInstance(null,someMap);})
|
||||
*
|
||||
* @since 1.9, JAXB 2.3
|
||||
*/
|
||||
JAXBContext createContext(Class<?>[] classesToBeBound,
|
||||
Map<String, ?> properties ) throws JAXBException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Create a new instance of a <tt>JAXBContext</tt> class.
|
||||
*
|
||||
* <p>
|
||||
* For semantics see {@link javax.xml.bind.JAXBContext#newInstance(String, ClassLoader, java.util.Map)}
|
||||
*
|
||||
* <p>
|
||||
* The interpretation of properties is up to implementations. Implementations should
|
||||
* throw <tt>JAXBException</tt> if it finds properties that it doesn't understand.
|
||||
*
|
||||
* @param contextPath list of java package names that contain schema derived classes
|
||||
* @param classLoader
|
||||
* This class loader will be used to locate the implementation classes.
|
||||
* @param properties
|
||||
* provider-specific properties. Can be null, which means the same thing as passing
|
||||
* in an empty map.
|
||||
*
|
||||
* @return a new instance of a <tt>JAXBContext</tt>
|
||||
* @throws JAXBException if an error was encountered while creating the
|
||||
* <tt>JAXBContext</tt> such as
|
||||
* <ol>
|
||||
* <li>failure to locate either ObjectFactory.class or jaxb.index in the packages</li>
|
||||
* <li>an ambiguity among global elements contained in the contextPath</li>
|
||||
* <li>failure to locate a value for the context factory provider property</li>
|
||||
* <li>mixing schema derived packages from different providers on the same contextPath</li>
|
||||
* </ol>
|
||||
* @since 1.9, JAXB 2.3
|
||||
*/
|
||||
JAXBContext createContext(String contextPath,
|
||||
ClassLoader classLoader,
|
||||
Map<String, ?> properties ) throws JAXBException;
|
||||
|
||||
}
|
@ -25,14 +25,9 @@
|
||||
|
||||
package javax.xml.bind;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@ -49,27 +44,27 @@ class ServiceLoaderUtil {
|
||||
private static final String OSGI_SERVICE_LOADER_CLASS_NAME = "com.sun.org.glassfish.hk2.osgiresourcelocator.ServiceLoader";
|
||||
private static final String OSGI_SERVICE_LOADER_METHOD_NAME = "lookupProviderClasses";
|
||||
|
||||
static <P> P firstByServiceLoader(Class<P> spiClass, Logger logger) {
|
||||
static <P, T extends Exception> P firstByServiceLoader(Class<P> spiClass,
|
||||
Logger logger,
|
||||
ExceptionHandler<T> handler) throws T {
|
||||
// service discovery
|
||||
ServiceLoader<P> serviceLoader = ServiceLoader.load(spiClass);
|
||||
for (P impl : serviceLoader) {
|
||||
logger.fine("ServiceProvider loading Facility used; returning object [" + impl.getClass().getName() + "]");
|
||||
return impl;
|
||||
try {
|
||||
ServiceLoader<P> serviceLoader = ServiceLoader.load(spiClass);
|
||||
|
||||
for (P impl : serviceLoader) {
|
||||
logger.fine("ServiceProvider loading Facility used; returning object [" +
|
||||
impl.getClass().getName() + "]");
|
||||
|
||||
return impl;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
throw handler.createException(t, "Error while searching for service [" + spiClass.getName() + "]");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static boolean isOsgi(Logger logger) {
|
||||
try {
|
||||
Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME);
|
||||
return true;
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
logger.log(Level.FINE, "OSGi classes not found, OSGi not available.", ignored);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Object lookupUsingOSGiServiceLoader(String factoryId, Logger logger) {
|
||||
|
||||
try {
|
||||
// Use reflection to avoid having any dependendcy on ServiceLoader class
|
||||
Class serviceClass = Class.forName(factoryId);
|
||||
@ -78,39 +73,22 @@ class ServiceLoaderUtil {
|
||||
Iterator iter = ((Iterable) m.invoke(null, serviceClass)).iterator();
|
||||
if (iter.hasNext()) {
|
||||
Object next = iter.next();
|
||||
logger.fine("Found implementation using OSGi facility; returning object [" + next.getClass().getName() + "].");
|
||||
logger.fine("Found implementation using OSGi facility; returning object [" +
|
||||
next.getClass().getName() + "].");
|
||||
return next;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
} catch (IllegalAccessException |
|
||||
InvocationTargetException |
|
||||
ClassNotFoundException |
|
||||
NoSuchMethodException ignored) {
|
||||
|
||||
logger.log(Level.FINE, "Unable to find from OSGi: [" + factoryId + "]", ignored);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static String propertyFileLookup(final String configFullPath, final String factoryId) throws IOException {
|
||||
File f = new File(configFullPath);
|
||||
String factoryClassName = null;
|
||||
if (f.exists()) {
|
||||
Properties props = new Properties();
|
||||
FileInputStream stream = null;
|
||||
try {
|
||||
stream = new FileInputStream(f);
|
||||
props.load(stream);
|
||||
factoryClassName = props.getProperty(factoryId);
|
||||
} finally {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return factoryClassName;
|
||||
}
|
||||
|
||||
static void checkPackageAccess(String className) {
|
||||
// make sure that the current thread has an access to the package of the given name.
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
@ -130,18 +108,12 @@ class ServiceLoaderUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns instance of required class. It checks package access (security) unless it is defaultClassname. It means if you
|
||||
* are trying to instantiate default implementation (fallback), pass the class name to both first and second parameter.
|
||||
*
|
||||
* @param className class to be instantiated
|
||||
* @param isDefaultClassname says whether default implementation class
|
||||
* @param handler exception handler - necessary for wrapping exceptions and logging
|
||||
* @param <T> Type of exception being thrown (necessary to distinguish between Runtime and checked exceptions)
|
||||
* @return instantiated object or throws Runtime/checked exception, depending on ExceptionHandler's type
|
||||
* @throws T
|
||||
*/
|
||||
static <T extends Exception> Object newInstance(String className, String defaultImplClassName, final ExceptionHandler<T> handler) throws T {
|
||||
// Returns instance of required class. It checks package access (security)
|
||||
// unless it is defaultClassname. It means if you are trying to instantiate
|
||||
// default implementation (fallback), pass the class name to both first and second parameter.
|
||||
static <T extends Exception> Object newInstance(String className,
|
||||
String defaultImplClassName,
|
||||
final ExceptionHandler<T> handler) throws T {
|
||||
try {
|
||||
return safeLoadClass(className, defaultImplClassName, contextClassLoader(handler)).newInstance();
|
||||
} catch (ClassNotFoundException x) {
|
||||
@ -151,7 +123,10 @@ class ServiceLoaderUtil {
|
||||
}
|
||||
}
|
||||
|
||||
static Class safeLoadClass(String className, String defaultImplClassName, ClassLoader classLoader) throws ClassNotFoundException {
|
||||
static Class safeLoadClass(String className,
|
||||
String defaultImplClassName,
|
||||
ClassLoader classLoader) throws ClassNotFoundException {
|
||||
|
||||
try {
|
||||
checkPackageAccess(className);
|
||||
} catch (SecurityException se) {
|
||||
@ -165,16 +140,6 @@ class ServiceLoaderUtil {
|
||||
return nullSafeLoadClass(className, classLoader);
|
||||
}
|
||||
|
||||
static String getJavaHomeLibConfigPath(String filename) {
|
||||
String javah = AccessController.doPrivileged(new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
return System.getProperty("java.home");
|
||||
}
|
||||
});
|
||||
return javah + File.separator + "lib" + File.separator + filename;
|
||||
}
|
||||
|
||||
static ClassLoader contextClassLoader(ExceptionHandler exceptionHandler) throws Exception {
|
||||
try {
|
||||
return Thread.currentThread().getContextClassLoader();
|
||||
|
Loading…
Reference in New Issue
Block a user