#194: Simplify implementation lookup
Signed-off-by: Lukas Jungmann <lukas.jungmann@oracle.com>
diff --git a/jaxb-api/src/main/java/jakarta/xml/bind/ContextFinder.java b/jaxb-api/src/main/java/jakarta/xml/bind/ContextFinder.java
index 65667d8..6435cd1 100644
--- a/jaxb-api/src/main/java/jakarta/xml/bind/ContextFinder.java
+++ b/jaxb-api/src/main/java/jakarta/xml/bind/ContextFinder.java
@@ -10,10 +10,8 @@
package jakarta.xml.bind;
-import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
@@ -32,16 +30,13 @@
* This class is package private and therefore is not exposed as part of the
* Jakarta XML Binding API.
*
- * This code is designed to implement the JAXB 1.0 spec pluggability feature
+ * This code is designed to implement the XML Binding spec pluggability feature
*
* @author <ul><li>Ryan Shoemaker, Sun Microsystems, Inc.</li></ul>
* @see JAXBContext
*/
class ContextFinder {
- // previous value of JAXBContext.JAXB_CONTEXT_FACTORY, using also this to ensure backwards compatibility
- private static final String JAXB_CONTEXT_FACTORY_DEPRECATED = "jakarta.xml.bind.context.factory";
-
private static final Logger logger;
/**
@@ -303,18 +298,6 @@
//ModuleUtil is mr-jar class, scans context path for jaxb classes on jdk9 and higher
Class<?>[] contextPathClasses = ModuleUtil.getClassesFromContextPath(contextPath, classLoader);
- //first try with classloader#getResource
- String factoryClassName = jaxbProperties(contextPath, classLoader, factoryId);
- if (factoryClassName == null && contextPathClasses != null) {
- //try with class#getResource
- factoryClassName = jaxbProperties(contextPathClasses, factoryId);
- }
-
- if (factoryClassName != null) {
- return newInstance(contextPath, contextPathClasses, factoryClassName, classLoader, properties);
- }
-
-
String factoryName = classNameFromSystemProperties();
if (factoryName != null) return newInstance(contextPath, contextPathClasses, factoryName, classLoader, properties);
@@ -326,12 +309,8 @@
return obj.createContext(contextPath, classLoader, properties);
}
- // to ensure backwards compatibility
- factoryName = firstByServiceLoaderDeprecated(JAXBContext.class, classLoader);
- if (factoryName != null) return newInstance(contextPath, contextPathClasses, factoryName, classLoader, properties);
-
Class<?> ctxFactory = (Class<?>) ServiceLoaderUtil.lookupUsingOSGiServiceLoader(
- "jakarta.xml.bind.JAXBContext", logger);
+ JAXBContext.JAXB_CONTEXT_FACTORY, logger);
if (ctxFactory != null) {
return newInstance(contextPath, contextPathClasses, ctxFactory, classLoader, properties);
@@ -343,34 +322,6 @@
}
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.
- // 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");
-
- URL jaxbPropertiesUrl = getResourceUrl(c, "jaxb.properties");
-
- if (jaxbPropertiesUrl != null) {
-
- String factoryClassName =
- classNameFromPackageProperties(
- jaxbPropertiesUrl,
- JAXBContext.JAXB_CONTEXT_FACTORY, JAXB_CONTEXT_FACTORY_DEPRECATED);
-
- return newInstance(classes, properties, factoryClassName, getClassClassLoader(c));
- }
-
- }
-
String factoryClassName = classNameFromSystemProperties();
if (factoryClassName != null) return newInstance(classes, properties, factoryClassName);
@@ -382,22 +333,9 @@
return factory.createContext(classes, properties);
}
- // to ensure backwards compatibility
- ClassLoader loader = getContextClassLoader();
- // it is guaranteed classes are not null but it is not guaranteed, that array is not empty
- if (classes.length > 0) {
- ClassLoader c = getClassClassLoader(classes[0]);
- //switch to classloader which loaded the class if it is not a bootstrap cl
- if (c != null) {
- loader = c;
- }
- }
- String className = firstByServiceLoaderDeprecated(JAXBContext.class, loader);
- if (className != null) return newInstance(classes, properties, className, loader);
-
logger.fine("Trying to create the platform default provider");
Class<?> ctxFactoryClass =
- (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader("jakarta.xml.bind.JAXBContext", logger);
+ (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader(JAXBContext.JAXB_CONTEXT_FACTORY, logger);
if (ctxFactoryClass != null) {
return newInstance(classes, properties, ctxFactoryClass);
@@ -408,53 +346,14 @@
return newInstance(classes, properties, DEFAULT_FACTORY_CLASS);
}
-
- /**
- * first factoryId should be the preferred one,
- * more of those can be provided to support backwards compatibility
- */
- private static String classNameFromPackageProperties(URL packagePropertiesUrl,
- String ... factoryIds) throws JAXBException {
-
- logger.log(Level.FINE, "Trying to locate {0}", packagePropertiesUrl.toString());
- Properties props = loadJAXBProperties(packagePropertiesUrl);
- for(String factoryId : factoryIds) {
- if (props.containsKey(factoryId)) {
- return props.getProperty(factoryId);
- }
- }
- //Factory key not found
- String propertiesUrl = packagePropertiesUrl.toExternalForm();
- String packageName = propertiesUrl.substring(0, propertiesUrl.indexOf("/jaxb.properties"));
- throw new JAXBException(Messages.format(Messages.MISSING_PROPERTY, packageName, factoryIds[0]));
- }
-
private static String classNameFromSystemProperties() throws JAXBException {
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) {
- return factoryClassName;
- }
- return null;
- }
- 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;
+ return null;
}
private static String getSystemProperty(String property) {
@@ -588,72 +487,4 @@
}
}
- // ServiceLoaderUtil.firstByServiceLoaderDeprecated should be used instead.
- @Deprecated
- 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 = "META-INF/services/" + jaxbContextFQCN;
- try {
- final InputStream resourceStream =
- (classLoader == null) ?
- ClassLoader.getSystemResourceAsStream(resource) :
- classLoader.getResourceAsStream(resource);
-
- if (resourceStream != null) {
- r = new BufferedReader(new InputStreamReader(resourceStream, "UTF-8"));
- String factoryClassName = r.readLine();
- if (factoryClassName != null) {
- factoryClassName = factoryClassName.trim();
- }
- r.close();
- logger.log(Level.FINE, "Configured factorty class:{0}", factoryClassName);
- return factoryClassName;
- } else {
- logger.log(Level.FINE, "Unable to load:{0}", resource);
- return null;
- }
- } catch (IOException e) {
- throw new JAXBException(e);
- } finally {
- try {
- if (r != null) {
- r.close();
- }
- } catch (IOException ex) {
- logger.log(Level.SEVERE, "Unable to close resource: " + resource, ex);
- }
- }
- }
-
- private static String jaxbProperties(String contextPath, ClassLoader classLoader, String factoryId) throws JAXBException {
- String[] packages = contextPath.split(":");
-
- for (String pkg : packages) {
- String pkgUrl = pkg.replace('.', '/');
- URL jaxbPropertiesUrl = getResourceUrl(classLoader, pkgUrl + "/jaxb.properties");
- if (jaxbPropertiesUrl != null) {
- return classNameFromPackageProperties(jaxbPropertiesUrl,
- factoryId, JAXB_CONTEXT_FACTORY_DEPRECATED);
- }
- }
- return null;
- }
-
- private static String jaxbProperties(Class<?>[] classesFromContextPath, String factoryId) throws JAXBException {
- for (Class<?> c : classesFromContextPath) {
- URL jaxbPropertiesUrl = getResourceUrl(c, "jaxb.properties");
- if (jaxbPropertiesUrl != null) {
- return classNameFromPackageProperties(jaxbPropertiesUrl, factoryId, JAXB_CONTEXT_FACTORY_DEPRECATED);
- }
- }
- return null;
- }
-
}
diff --git a/jaxb-api/src/main/java/jakarta/xml/bind/JAXBContext.java b/jaxb-api/src/main/java/jakarta/xml/bind/JAXBContext.java
index 5967785..e3a99bc 100644
--- a/jaxb-api/src/main/java/jakarta/xml/bind/JAXBContext.java
+++ b/jaxb-api/src/main/java/jakarta/xml/bind/JAXBContext.java
@@ -13,10 +13,8 @@
import org.w3c.dom.Node;
import java.io.IOException;
-import java.io.InputStream;
import java.util.Collections;
import java.util.Map;
-import java.util.Properties;
/**
* The {@code JAXBContext} class provides the client's entry point to the
@@ -44,21 +42,7 @@
* </ul>
*
* <p><i>
- * The following JAXB 1.0 requirement is only required for schema to
- * java interface/implementation binding. It does not apply to Jakarta XML Binding annotated
- * classes. Jakarta XML Binding Providers must generate a {@code jaxb.properties} file in
- * each package containing schema derived classes. The property file must
- * contain a property named {@code jakarta.xml.bind.context.factory} whose
- * value is the name of the class that implements the {@code createContext}
- * APIs.</i>
- *
- * <p><i>
- * The class supplied by the provider does not have to be assignable to
- * {@code jakarta.xml.bind.JAXBContext}, it simply has to provide a class that
- * implements the {@code createContext} APIs.</i>
- *
- * <p><i>
- * In addition, the provider must call the
+ * The provider must call the
* {@link DatatypeConverter#setDatatypeConverter(DatatypeConverterInterface)
* DatatypeConverter.setDatatypeConverter} api prior to any client
* invocations of the marshal and unmarshal methods. This is necessary to
@@ -191,29 +175,8 @@
* <ol>
*
* <li>
- * Packages/classes explicitly passed in to the {@link #newInstance} method are processed in the order they are
- * specified, until {@code jaxb.properties} file is looked up in its package, by using the associated classloader —
- * this is {@link Class#getClassLoader() the owner class loader} for a {@link Class} argument, and for a package
- * the specified {@link ClassLoader}.
- *
- * <p>
- * If such a resource 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. If no value
- * found, {@code "jakarta.xml.bind.context.factory"} is used as a key for backwards compatibility reasons. 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 Jakarta XML Binding implementation.
- * (For example, perhaps the schema compiler has generated some vendor extension in the code.)
- *
- * <p>
- * This configuration method is deprecated.
- *
- * <li>
* If the system property {@link #JAXB_CONTEXT_FACTORY} exists, then its value is assumed to be the provider
- * factory class. If no such property exists, properties {@code "jakarta.xml.bind.context.factory"} and
- * {@code "jakarta.xml.bind.JAXBContext"} are checked too (in this order), for backwards compatibility reasons. This phase
- * of the look up enables per-JVM override of the Jakarta XML Binding implementation.
+ * factory class. This phase of the look up enables per-JVM override of the Jakarta XML Binding implementation.
*
* <li>
* Provider of {@link jakarta.xml.bind.JAXBContextFactory} is loaded using the service-provider loading
@@ -228,57 +191,15 @@
* configuration error} a {@link jakarta.xml.bind.JAXBException} will be thrown.
*
* <li>
- * Look for resource {@code /META-INF/services/jakarta.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.
- *
- * This configuration method is deprecated.
- *
- * <li>
* Finally, if all the steps above fail, then the rest of the look up is unspecified. That said,
* the recommended behavior is to simply look for some hard-coded platform default Jakarta XML Binding implementation.
- * This phase of the look up is so that Java SE can have its own JAXB implementation as the last resort.
+ * This phase of the look up is so that the environment can have its own Jakarta XML Binding implementation as the last resort.
* </ol>
*
* <p>
* Once the provider factory class is discovered, context creation is delegated to one of its
* {@code createContext(...)} methods.
*
- * For backward compatibility reasons, there are two ways how to implement provider factory class:
- * <ol>
- * <li>the class is implementation of {@link jakarta.xml.bind.JAXBContextFactory}. It must also implement no-arg
- * constructor. If discovered in other step then 3, new instance using no-arg constructor is created first.
- * After that, appropriate instance method is invoked on this instance.
- * <li>the class is not implementation of interface above and then it is mandated to implement the following
- * static method signatures:
- * <pre>
- *
- * public static JAXBContext createContext(
- * String contextPath,
- * ClassLoader classLoader,
- * Map<String,Object> properties ) throws JAXBException
- *
- * public static JAXBContext createContext(
- * Class[] classes,
- * Map<String,Object> properties ) throws JAXBException
- * </pre>
- * In this scenario, appropriate static method is used instead of instance method. This approach is incompatible
- * with {@link java.util.ServiceLoader} so it can't be used with step 3.
- * </ol>
- * <p>
- * There is no difference in behavior of given method {@code createContext(...)} regardless of whether it uses approach
- * 1 (JAXBContextFactory) or 2 (no interface, static methods).
- *
- * @apiNote
- * Service discovery method using resource {@code /META-INF/services/jakarta.xml.bind.JAXBContext} (described in step 4)
- * is supported only to allow backwards compatibility, it is strongly recommended to migrate to standard
- * {@link java.util.ServiceLoader} mechanism (described in step 3). The difference here is the resource name, which
- * doesn't match service's type name.
- * <p>
- * Also using providers implementing interface {@link JAXBContextFactory} is preferred over using ones defining
- * static methods, same as {@link JAXBContext#JAXB_CONTEXT_FACTORY} property is preferred over property
- * {@code "jakarta.xml.bind.context.factory"}
- *
* @implNote
* Within the last step, if Glassfish AS environment detected, its specific service loader is used to find factory class.
*
@@ -381,16 +302,6 @@
* </ul>
*
* <p>
- * To maintain compatibility with JAXB 1.0 schema to java
- * interface/implementation binding, enabled by schema customization
- * {@code <jaxb:globalBindings valueClass="false">},
- * the Jakarta XML Binding provider will ensure that each package on the context path
- * has a {@code jaxb.properties} file which contains a value for the
- * {@code jakarta.xml.bind.context.factory} property and that all values
- * resolve to the same provider. This requirement does not apply to
- * Jakarta XML Binding annotated classes.
- *
- * <p>
* If there are any global XML element name collisions across the various
* packages listed on the {@code contextPath}, a {@code JAXBException}
* will be thrown.
diff --git a/spec/src/main/asciidoc/appI-changelog.adoc b/spec/src/main/asciidoc/appI-changelog.adoc
index b6f941b..0245fe9 100644
--- a/spec/src/main/asciidoc/appI-changelog.adoc
+++ b/spec/src/main/asciidoc/appI-changelog.adoc
@@ -8,8 +8,12 @@
=== Changes in Version 4
* fixed cross-references in the specification document
-* removed deprecated jakarta.xml.bind.Validator
+* removed deprecated `jakarta.xml.bind.Validator`
* removed constraints on using `java.beans.Introspector`
+* removed deprecated steps in implementation lookup algorithm - dropped search
+through `jaxb.properties` file, `jakarta.xml.bind.context.factory` and
+`jakarta.xml.bind.JAXBContext` properties and `/META-INF/services/jakarta.xml.bind.JAXBContext`
+resource file
=== Changes in Version 3
diff --git a/spec/src/main/asciidoc/ch04-binding_framework.adoc b/spec/src/main/asciidoc/ch04-binding_framework.adoc
index 2b1d522..65e15b0 100644
--- a/spec/src/main/asciidoc/ch04-binding_framework.adoc
+++ b/spec/src/main/asciidoc/ch04-binding_framework.adoc
@@ -792,34 +792,15 @@
Implementation discovery consists of following steps in the order
specified (first successful resolution applies):
-. Context path or classes’ packages explicitly passed in
-to the newInstance method are searched for the jaxb.properties file. +
- +
-If such a resource is discovered, it is loaded as a property file,
-and the value of the `jakarta.xml.bind.JAXBContextFactory` key
-will be assumed to be the provider factory class.
-If no value found, `jakarta.xml.bind.context.factory` is used
-as a key for backwards compatibility reasons. +
- +
-This configuration method is deprecated.
-
. If the system property `jakarta.xml.bind.JAXBContextFactory` exists,
-then its value is assumed to be the provider factory class.
-If no such property exists, properties `jakarta.xml.bind.context.factory`
-and `jakarta.xml.bind.JAXBContext` are checked too (in this order),
-for backwards compatibility reasons.
+then its value is assumed to be the provider factory class. This phase
+of the look up enables per-JVM override of the Jakarta XML Binding implementation.
. Provider of `jakarta.xml.bind.JAXBContextFactory` is loaded
using the service-provider loading facilities, as defined by
Java SE Platform, to attempt to locate and load
an implementation of the service.
-. Look for resource `/META-INF/services/jakarta.xml.bind.JAXBContext`.
-If such a resource exists, its content is assumed to be the provider
-factory class. +
- +
- This configuration method is deprecated.
-
. Finally, if all of the steps above fail,
then the rest of the look up is unspecified.