/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package javax.xml.bind; import java.lang.reflect.Method; import java.util.Map; import java.util.Properties; import java.io.IOException; import java.io.InputStream; import java.io.BufferedReader; import java.io.InputStreamReader; class ContextFinder { private static final String PLATFORM_DEFAULT_FACTORY_CLASS = "com.sun.xml.bind.v2.ContextFactory"; private static final String JAXB_CONTEXT_PROPERTY = JAXBContext.class.getName(); private static final String JAXB_CONTEXT_FACTORY = JAXBContext.JAXB_CONTEXT_FACTORY; public static JAXBContext find(String contextPath, ClassLoader classLoader, Map properties) throws JAXBException { String className = null; // Patch for bug https://issues.apache.org/activemq/browse/SMX4-329 if (contextPath == null || contextPath.length() == 0) { throw new JAXBException("Invalid contextPath (empty or null)"); } String[] packages = contextPath.split(":"); if (packages == null || packages.length == 0) { throw new JAXBException("Invalid contextPath (no packages)"); } for (String pkg : packages) { String url = pkg.replace('.', '/') + "/jaxb.properties"; className = loadClassNameFromProperties(url, classLoader); if (className != null) { break; } } if (className == null) { className = System.getProperty(JAXB_CONTEXT_PROPERTY); } if (className == null) { String url = "META-INF/services/" + JAXB_CONTEXT_PROPERTY; className = loadClassName(url, classLoader); } if (className == null) { className = PLATFORM_DEFAULT_FACTORY_CLASS; } Class spi = loadSpi(className, classLoader); try { Method m = spi.getMethod("createContext", new Class[] { String.class, ClassLoader.class, Map.class }); return (JAXBContext) m.invoke(null, new Object[] { contextPath, classLoader, properties }); } catch (NoSuchMethodException e) { // ignore } catch (Throwable t) { throw new JAXBException("Unable to create context", t); } // Fallback for JAXB 1.0 compatibility (at least JAXB TCK tests are using that feature) try { Method m = spi.getMethod("createContext", new Class[] { String.class, ClassLoader.class, }); return (JAXBContext) m.invoke(null, new Object[] { contextPath, classLoader }); } catch (Throwable t) { throw new JAXBException("Unable to create context", t); } } public static JAXBContext find(Class[] classes, Map properties) throws JAXBException { String className = null; for (Class cl : classes) { Package pkg = cl.getPackage(); if (pkg != null) { String url = pkg.getName().replace('.', '/') + "/jaxb.properties"; className = loadClassNameFromProperties(url, cl.getClassLoader()); if (className != null) { break; } } } if (className == null) { className = System.getProperty(JAXB_CONTEXT_PROPERTY); } if (className == null) { String url = "META-INF/services/" + JAXB_CONTEXT_PROPERTY; className = loadClassName(url, Thread.currentThread().getContextClassLoader()); } if (className == null) { className = PLATFORM_DEFAULT_FACTORY_CLASS; } Class spi = loadSpi(className, Thread.currentThread().getContextClassLoader()); try { Method m = spi.getMethod("createContext", new Class[] { Class[].class, Map.class }); return (JAXBContext) m.invoke(null, new Object[] { classes, properties }); } catch (Throwable t) { throw new JAXBException("Unable to create context", t); } } private static String loadClassNameFromProperties(String url, ClassLoader classLoader) throws JAXBException { try { InputStream is; if (classLoader != null) { is = classLoader.getResourceAsStream(url); } else { is = ClassLoader.getSystemResourceAsStream(url); } if (is != null) { try { Properties props = new Properties(); props.load(is); String className = props.getProperty(JAXB_CONTEXT_FACTORY); if (className == null) { throw new JAXBException("jaxb.properties file " + url + " should contain a " + JAXB_CONTEXT_FACTORY + " property"); } return className.trim(); } finally { is.close(); } } else { return null; } } catch (IOException e) { throw new JAXBException(e); } } private static String loadClassName(String url, ClassLoader classLoader) throws JAXBException { try { InputStream is; if (classLoader != null) { is = classLoader.getResourceAsStream(url); } else { is = ClassLoader.getSystemResourceAsStream(url); } if (is != null) { try { BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8")); return r.readLine().trim(); } finally { is.close(); } } return null; } catch (IOException e) { throw new JAXBException(e); } } private static Class loadSpi(String className, ClassLoader classLoader) throws JAXBException { Class spiClass; try { spiClass = org.apache.servicemix.specs.locator.OsgiLocator.locate(JAXBContext.class); if (spiClass != null) { return spiClass; } } catch (Throwable t) { } try { if (classLoader != null) { spiClass = classLoader.loadClass(className); } else { spiClass = Class.forName(className); } } catch (ClassNotFoundException e) { throw new JAXBException("Provider " + className + " not found", e); } return spiClass; } }