< prev index next >
src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java
Print this page
@@ -66,10 +66,13 @@
* <p>
* For this reason, we have to hard-code the class name into the API.
*/
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 {
logger = Logger.getLogger("javax.xml.bind");
try {
@@ -90,10 +93,18 @@
// just to be extra safe. in particular System.getProperty may throw
// SecurityException.
}
}
+ 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.
*/
private static void handleInvocationTargetException(InvocationTargetException x) throws JAXBException {
@@ -157,11 +168,14 @@
// some other type of exception - just wrap it
throw new JAXBException(Messages.format(Messages.COULD_NOT_INSTANTIATE, className, x), x);
}
}
- 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 {
/*
* javax.xml.bind.context.factory points to a class which has a
* static method called 'createContext' that
@@ -237,21 +251,22 @@
static JAXBContext newInstance(Class[] classes,
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)) {
// the cast would fail, so generate an exception with a nice message
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);
Throwable x = e;
if (e.getTargetException() != null)
@@ -259,13 +274,14 @@
throw new JAXBException(x);
}
}
- 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()) {
// no context is specified
throw new JAXBException(Messages.format(Messages.NO_PACKAGE_IN_CONTEXTPATH));
@@ -273,110 +289,159 @@
// search for jaxb.properties in the class loader of each class first
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<String, ?> properties) throws JAXBException {
// search for jaxb.properties in the class loader of each class first
logger.fine("Searching jaxb.properties");
for (final Class c : classes) {
// this classloader is used only to load jaxb.properties, so doing this should be safe.
- if (c.getPackage() == null) continue; // this is possible for primitives, arrays, and classes that are loaded by poorly implemented ClassLoaders
+ // this is possible for primitives, arrays, and classes that are
+ // loaded by poorly implemented ClassLoaders
+ if (c.getPackage() == null) continue;
// TODO: do we want to optimize away searching the same package? org.Foo, org.Bar, com.Baz
// classes from the same package might come from different class loades, so it might be a bad idea
// TODO: it's easier to look things up from the class
// c.getResourceAsStream("jaxb.properties");
- String className = classNameFromPackageProperties(JAXBContext.JAXB_CONTEXT_FACTORY, getClassClassLoader(c), c.getPackage().getName().replace('.', '/'));
- if (className != null) return newInstance(classes, properties, className);
+ String factoryClassName =
+ classNameFromPackageProperties(
+ getClassClassLoader(c),
+ c.getPackage().getName().replace('.', '/'),
+ JAXBContext.JAXB_CONTEXT_FACTORY, JAXB_CONTEXT_FACTORY_DEPRECATED);
+
+ if (factoryClassName != null) return newInstance(classes, properties, factoryClassName);
}
- String factoryName = classNameFromSystemProperties();
- if (factoryName != null) return newInstance(classes, properties, factoryName);
+ String factoryClassName = classNameFromSystemProperties();
+ if (factoryClassName != null) return newInstance(classes, properties, factoryClassName);
- Class ctxFactoryClass = (Class) ServiceLoaderUtil.lookupUsingOSGiServiceLoader("javax.xml.bind.JAXBContext", logger);
- if (ctxFactoryClass != null) {
- return newInstance(classes, properties, ctxFactoryClass);
- }
+ JAXBContextFactory factory =
+ ServiceLoaderUtil.firstByServiceLoader(JAXBContextFactory.class, logger, EXCEPTION_HANDLER);
+
+ 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");
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) {
+ for(String factoryId : factoryIds) {
if (props.containsKey(factoryId)) {
return props.getProperty(factoryId);
- } else {
- throw new JAXBException(Messages.format(Messages.MISSING_PROPERTY, packageName, 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()));
+ }
+ // leave this here to assure compatibility
+ factoryClassName = getDeprecatedSystemProperty(JAXB_CONTEXT_FACTORY_DEPRECATED);
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(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 {
URL url;
if (classLoader == null)
@@ -478,21 +543,22 @@
}
});
}
}
- // TODO: to be removed - SPEC change required
// 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) ?
ClassLoader.getSystemResourceAsStream(resource) :
classLoader.getResourceAsStream(resource);
@@ -508,13 +574,10 @@
return factoryClassName;
} else {
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 {
try {
if (r != null) {
< prev index next >