changeset 600:884d98e00032

8072839: JAX-B Plugability Layer: using java.util.ServiceLoader Reviewed-by: alanb
author mkos
date Fri, 05 Jun 2015 15:05:55 +0200
parents b5878b03d1b2
children f5911c6155c2
files src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java src/java.xml.bind/share/classes/javax/xml/bind/JAXBContext.java src/java.xml.bind/share/classes/javax/xml/bind/JAXBContextFactory.java src/java.xml.bind/share/classes/javax/xml/bind/ServiceLoaderUtil.java
diffstat 4 files changed, 353 insertions(+), 186 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java	Thu Jun 04 18:49:20 2015 -0700
+++ b/src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java	Fri Jun 05 15:05:55 2015 +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<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 @@
         }
     }
 
-    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) {
+
+        } catch (NoSuchMethodException | IllegalAccessException e) {
             throw new JAXBException(e);
-        } catch (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,106 +291,155 @@
         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);
+        JAXBContextFactory factory =
+                ServiceLoaderUtil.firstByServiceLoader(JAXBContextFactory.class, logger, EXCEPTION_HANDLER);
+
+        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);
+
+        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);
         }
 
-        // TODO: to be removed - deprecated!!! Requires SPEC change!!!
-        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;
-
         // else no provider found
         logger.fine("Trying to create the platform default provider");
         return newInstance(classes, properties, PLATFORM_DEFAULT_FACTORY_CLASS);
     }
 
 
-    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) {
-            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");
-            }
+        }
+        // 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) {
+            return factoryClassName;
         }
         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 {
--- a/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContext.java	Thu Jun 04 18:49:20 2015 -0700
+++ b/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContext.java	Fri Jun 05 15:05:55 2015 +0200
@@ -45,29 +45,20 @@
  * 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 @@
  * 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 @@
  * 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 @@
  * 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 @@
  * <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 @@
  * 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 @@
  * </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 @@
      * 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 @@
 
     /**
      * <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 @@
 
     /**
      * <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 @@
 
     /**
      * <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 @@
      * </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 @@
 // 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 @@
 //     *      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 @@
 
     /**
      * <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 @@
      *      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 @@
      *
      * @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 @@
 
     /**
      * <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 @@
      *      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 @@
      *
      * @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 @@
         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();
                         }
                     });
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContextFactory.java	Fri Jun 05 15:05:55 2015 +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;
+
+/**
+ * <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;
+
+}
--- a/src/java.xml.bind/share/classes/javax/xml/bind/ServiceLoaderUtil.java	Thu Jun 04 18:49:20 2015 -0700
+++ b/src/java.xml.bind/share/classes/javax/xml/bind/ServiceLoaderUtil.java	Fri Jun 05 15:05:55 2015 +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> 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) {
 
-    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 <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 @@
         }
     }
 
-    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<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();