This commit is contained in:
Lana Steuck 2015-06-11 20:20:05 -07:00
commit 94c4895e47
4 changed files with 352 additions and 185 deletions

View File

@ -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 {

View File

@ -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 &mdash;
@ -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&lt;String,Object&gt; properties throws JAXBException
*
* public static JAXBContext createContext(
* Class[] classes,
* Map&lt;String,Object&gt; 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();
}
});

View File

@ -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;
}

View File

@ -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();