--- old/src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java 2015-05-26 17:37:58.000000000 +0200 +++ new/src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java 2015-05-26 17:37:56.000000000 +0200 @@ -68,6 +68,9 @@ */ 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 @@ } } + private static ServiceLoaderUtil.ExceptionHandler EXCEPTION_HANDLER = + new ServiceLoaderUtil.ExceptionHandler() { + @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 @@ } } - 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 @@ 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 @@ 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 @@ } } - 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 @@ 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); - if (ctxFactory != null) { - return newInstance(contextPath, ctxFactory, classLoader, properties); - } + JAXBContextFactory obj = ServiceLoaderUtil.firstByServiceLoader( + JAXBContextFactory.class, logger, EXCEPTION_HANDLER); - // TODO: SPEC change required! This is supposed to be! - // JAXBContext obj = firstByServiceLoader(JAXBContext.class, EXCEPTION_HANDLER); - // if (obj != null) return obj; + if (obj != null) return obj.createContext(contextPath, classLoader, properties); - // TODO: Deprecated - SPEC change required! + // 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); + } + // 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 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); + + if (factory != null) return factory.createContext(classes, properties); - // TODO: to be removed - deprecated!!! Requires SPEC change!!! + // 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 @@ } - 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 @@ } } - // 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 @@ 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 { --- old/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContext.java 2015-05-26 17:38:00.000000000 +0200 +++ new/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContext.java 2015-05-26 17:38:00.000000000 +0200 @@ -45,29 +45,20 @@ * specialized forms of the method available: * *
    - *
  • {@link #newInstance(String,ClassLoader) JAXBContext.newInstance( "com.acme.foo:com.acme.bar" )}
    - * 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"). - *
  • - *
  • {@link #newInstance(Class...) JAXBContext.newInstance( com.acme.foo.Foo.class )}
    - * 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. - *
  • + *
  • {@link #newInstance(String, ClassLoader) JAXBContext.newInstance( "com.acme.foo:com.acme.bar" )}
    + * 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"). + *
  • + *
  • {@link #newInstance(Class...) JAXBContext.newInstance( com.acme.foo.Foo.class )}
    + * 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. + *
  • *
* - *

- * SPEC REQUIREMENT: the provider must supply an implementation - * class containing the following method signatures: - * - *

{@code
- * public static JAXBContext createContext( String contextPath, ClassLoader classLoader, Map properties ) throws JAXBException
- * public static JAXBContext createContext( Class[] classes, Map properties ) throws JAXBException
- * }
- * *

* 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 @@ * any of the schemas listed in the contextPath. For example: * *

- *        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
  * 
* *

@@ -146,7 +137,7 @@ * Section 4.2 Java Package of the specification. * *

- * SPEC REQUIREMENT: the provider must generate a class in each + * 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 * newInstance( javaContentInterface ) method @@ -214,6 +205,7 @@ * by the following steps. * *

    + * *
  1. * For each package/class explicitly passed in to the {@link #newInstance} method, in the order they are specified, * jaxb.properties file is looked up in its package, by using the associated classloader — @@ -223,7 +215,7 @@ *

    * 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. * *

    * This phase of the look up allows some packages to force the use of a certain JAXB implementation. @@ -234,10 +226,36 @@ * factory class. This phase of the look up enables per-JVM override of the JAXB implementation. * *

  2. - * Look for /META-INF/services/javax.xml.bind.JAXBContext 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. + *
    + * In case of {@link java.util.ServiceConfigurationError service + * configuration error} a {@link javax.xml.bind.JAXBException} will be thrown. + *
  3. + * + *
  4. + * 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: + * + *
    + *
    + * 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
    + * 
    + * This configuration method is deprecated. * *
  5. * Finally, if all the steps above fail, then the rest of the look up is unspecified. That said, @@ -246,17 +264,30 @@ *
* *

- * Once the provider factory class is discovered, its - * public static JAXBContext createContext(String,ClassLoader,Map) method - * (see {@link #newInstance(String, ClassLoader, Map)} for the parameter semantics.) - * or public static JAXBContext createContet(Class[],Map) 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

  • Ryan Shoemaker, Sun Microsystems, Inc.
  • Kohsuke Kawaguchi, Sun Microsystems, Inc.
  • Joe Fialli, Sun Microsystems, Inc.
+ *

+ * + * @apiNote + *

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

  • Ryan Shoemaker, Sun Microsystems, Inc.
  • + *
  • Kohsuke Kawaguchi, Sun Microsystems, Inc.
  • + *
  • Joe Fialli, Sun Microsystems, Inc.
+ * * @see Marshaller * @see Unmarshaller - * @see S 7.4.1 "Named Packages" in Java Language Specification + * @see S 7.4.1 "Named Packages" + * in Java Language Specification + * * @since 1.6, JAXB 1.0 */ public abstract class JAXBContext { @@ -265,9 +296,7 @@ * The name of the property that contains the name of the class capable * of creating new JAXBContext 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 @@ /** *

- * Obtain a new instance of a JAXBContext class. + * Create a new instance of a JAXBContext class. * *

* This is a convenience method to invoke the @@ -300,7 +329,7 @@ /** *

- * Obtain a new instance of a JAXBContext class. + * Create a new instance of a JAXBContext class. * *

* The client application must supply a context path which is a list of @@ -396,7 +425,7 @@ /** *

- * Obtain a new instance of a JAXBContext class. + * Create a new instance of a JAXBContext class. * *

* This is mostly the same as {@link JAXBContext#newInstance(String, ClassLoader)}, @@ -425,8 +454,9 @@ * * @since 1.6, JAXB 2.0 */ - public static JAXBContext newInstance( String contextPath, ClassLoader classLoader, Map properties ) - throws JAXBException { + public static JAXBContext newInstance( String contextPath, + ClassLoader classLoader, + Map properties ) throws JAXBException { return ContextFinder.find( /* The default property name according to the JAXB spec */ @@ -443,7 +473,7 @@ // TODO: resurrect this once we introduce external annotations // /** // *

-// * Obtain a new instance of a JAXBContext class. +// * Create a new instance of a JAXBContext class. // * // *

// * The client application must supply a list of classes that the new @@ -479,7 +509,7 @@ // * spec-defined classes will be returned. // * // * @return -// * A new instance of a JAXBContext. Always non-null valid object. +// * A new instance of a JAXBContext. // * // * @throws JAXBException // * if an error was encountered while creating the @@ -517,7 +547,7 @@ /** *

- * Obtain a new instance of a JAXBContext class. + * Create a new instance of a JAXBContext class. * *

* The client application must supply a list of classes that the new @@ -559,7 +589,7 @@ * spec-defined classes will be returned. * * @return - * A new instance of a JAXBContext. Always non-null valid object. + * A new instance of a JAXBContext. * * @throws JAXBException * if an error was encountered while creating the @@ -578,7 +608,7 @@ * * @since 1.6, JAXB 2.0 */ - public static JAXBContext newInstance( Class... classesToBeBound ) + public static JAXBContext newInstance( Class ... classesToBeBound ) throws JAXBException { return newInstance(classesToBeBound,Collections.emptyMap()); @@ -586,7 +616,7 @@ /** *

- * Obtain a new instance of a JAXBContext class. + * Create a new instance of a JAXBContext class. * *

* An overloading of {@link JAXBContext#newInstance(Class...)} @@ -605,7 +635,7 @@ * in an empty map. * * @return - * A new instance of a JAXBContext. Always non-null valid object. + * A new instance of a JAXBContext. * * @throws JAXBException * if an error was encountered while creating the @@ -624,7 +654,7 @@ * * @since 1.6, JAXB 2.0 */ - public static JAXBContext newInstance( Class[] classesToBeBound, Map properties ) + public static JAXBContext newInstance( Class[] classesToBeBound, Map properties ) throws JAXBException { if (classesToBeBound == null) { @@ -756,9 +786,9 @@ 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() { + public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } }); --- old/src/java.xml.bind/share/classes/javax/xml/bind/ServiceLoaderUtil.java 2015-05-26 17:38:08.000000000 +0200 +++ new/src/java.xml.bind/share/classes/javax/xml/bind/ServiceLoaderUtil.java 2015-05-26 17:38:08.000000000 +0200 @@ -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 @@ 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 firstByServiceLoader(Class

spiClass, Logger logger) { + static P firstByServiceLoader(Class

spiClass, + Logger logger, + ExceptionHandler handler) throws T { // service discovery - ServiceLoader

serviceLoader = ServiceLoader.load(spiClass); - for (P impl : serviceLoader) { - logger.fine("ServiceProvider loading Facility used; returning object [" + impl.getClass().getName() + "]"); - return impl; - } - 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); + ServiceLoader

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 false; + return null; } 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 @@ 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 @@ } } - /** - * 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 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 Object newInstance(String className, String defaultImplClassName, final ExceptionHandler 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 Object newInstance(String className, + String defaultImplClassName, + final ExceptionHandler handler) throws T { try { return safeLoadClass(className, defaultImplClassName, contextClassLoader(handler)).newInstance(); } catch (ClassNotFoundException x) { @@ -151,7 +123,10 @@ } } - 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 @@ return nullSafeLoadClass(className, classLoader); } - static String getJavaHomeLibConfigPath(String filename) { - String javah = AccessController.doPrivileged(new PrivilegedAction() { - @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(); --- /dev/null 2015-05-26 17:38:11.000000000 +0200 +++ new/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContextFactory.java 2015-05-26 17:38:11.000000000 +0200 @@ -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; + +/** + *

Factory that creates new JAXBContext instances. + * + * JAXBContextFactory can be located using {@link java.util.ServiceLoader#load(Class)} + * + * @since 1.9, JAXB 2.3 + */ +public interface JAXBContextFactory { + + /** + *

+ * Create a new instance of a JAXBContext class. + * + *

+ * 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 JAXBContext. + * + * @throws JAXBException + * if an error was encountered while creating the + * JAXBContext, such as (but not limited to): + *

    + *
  1. Classes use JAXB annotations incorrectly + *
  2. Classes have colliding annotations (i.e., two classes with the same type name) + *
  3. The JAXB implementation was unable to locate + * provider-specific out-of-band information (such as additional + * files generated at the development time.) + *
+ * + * @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 properties ) throws JAXBException; + + /** + *

+ * Create a new instance of a JAXBContext class. + * + *

+ * For semantics see {@link javax.xml.bind.JAXBContext#newInstance(String, ClassLoader, java.util.Map)} + * + *

+ * The interpretation of properties is up to implementations. Implementations should + * throw JAXBException 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 JAXBContext + * @throws JAXBException if an error was encountered while creating the + * JAXBContext such as + *

    + *
  1. failure to locate either ObjectFactory.class or jaxb.index in the packages
  2. + *
  3. an ambiguity among global elements contained in the contextPath
  4. + *
  5. failure to locate a value for the context factory provider property
  6. + *
  7. mixing schema derived packages from different providers on the same contextPath
  8. + *
+ * @since 1.9, JAXB 2.3 + */ + JAXBContext createContext(String contextPath, + ClassLoader classLoader, + Map properties ) throws JAXBException; + +}