1 /* 2 * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.xml.internal.bind.v2; 27 28 import java.io.BufferedReader; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.io.InputStreamReader; 32 import java.util.Collection; 33 import java.util.Collections; 34 import java.util.HashMap; 35 import java.util.List; 36 import java.util.Map; 37 import java.util.StringTokenizer; 38 import java.util.logging.Level; 39 40 import javax.xml.bind.JAXBContext; 41 import javax.xml.bind.JAXBException; 42 43 import com.sun.istack.internal.FinalArrayList; 44 import com.sun.xml.internal.bind.Util; 45 import com.sun.xml.internal.bind.api.JAXBRIContext; 46 import com.sun.xml.internal.bind.api.TypeReference; 47 import com.sun.xml.internal.bind.v2.model.annotation.RuntimeAnnotationReader; 48 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl; 49 import com.sun.xml.internal.bind.v2.util.TypeCast; 50 51 /** 52 * This class is responsible for producing RI JAXBContext objects. In 53 * the RI, this is the class that the javax.xml.bind.context.factory 54 * property will point to. 55 * 56 * <p> 57 * Used to create JAXBContext objects for v1.0.1 and forward 58 * 59 * @since 2.0 60 * @author Kohsuke Kawaguchi 61 */ 62 public class ContextFactory { 63 64 /** 65 * The API will invoke this method via reflection 66 */ 67 public static JAXBContext createContext(Class[] classes, Map<String,Object> properties ) throws JAXBException { 68 // fool-proof check, and copy the map to make it easier to find unrecognized properties. 69 if(properties==null) 70 properties = Collections.emptyMap(); 71 else 72 properties = new HashMap<String,Object>(properties); 73 74 String defaultNsUri = getPropertyValue(properties,JAXBRIContext.DEFAULT_NAMESPACE_REMAP,String.class); 75 76 Boolean c14nSupport = getPropertyValue(properties,JAXBRIContext.CANONICALIZATION_SUPPORT,Boolean.class); 77 if(c14nSupport==null) 78 c14nSupport = false; 79 80 Boolean disablesecurityProcessing = getPropertyValue(properties, JAXBRIContext.DISABLE_XML_SECURITY, Boolean.class); 81 if (disablesecurityProcessing==null) 82 disablesecurityProcessing = false; 83 84 Boolean allNillable = getPropertyValue(properties,JAXBRIContext.TREAT_EVERYTHING_NILLABLE,Boolean.class); 85 if(allNillable==null) 86 allNillable = false; 87 88 Boolean retainPropertyInfo = getPropertyValue(properties, JAXBRIContext.RETAIN_REFERENCE_TO_INFO, Boolean.class); 89 if(retainPropertyInfo==null) 90 retainPropertyInfo = false; 91 92 Boolean supressAccessorWarnings = getPropertyValue(properties, JAXBRIContext.SUPRESS_ACCESSOR_WARNINGS, Boolean.class); 93 if(supressAccessorWarnings==null) 94 supressAccessorWarnings = false; 95 96 Boolean improvedXsiTypeHandling = getPropertyValue(properties, JAXBRIContext.IMPROVED_XSI_TYPE_HANDLING, Boolean.class); 97 if (improvedXsiTypeHandling == null) { 98 String improvedXsiSystemProperty = Util.getSystemProperty(JAXBRIContext.IMPROVED_XSI_TYPE_HANDLING); 99 if (improvedXsiSystemProperty == null) { 100 improvedXsiTypeHandling = true; 101 } else { 102 improvedXsiTypeHandling = Boolean.valueOf(improvedXsiSystemProperty); 103 } 104 } 105 106 Boolean xmlAccessorFactorySupport = getPropertyValue(properties, 107 JAXBRIContext.XMLACCESSORFACTORY_SUPPORT,Boolean.class); 108 if(xmlAccessorFactorySupport==null){ 109 xmlAccessorFactorySupport = false; 110 Util.getClassLogger().log(Level.FINE, "Property " + 111 JAXBRIContext.XMLACCESSORFACTORY_SUPPORT + 112 "is not active. Using JAXB's implementation"); 113 } 114 115 RuntimeAnnotationReader ar = getPropertyValue(properties,JAXBRIContext.ANNOTATION_READER,RuntimeAnnotationReader.class); 116 117 Collection<TypeReference> tr = getPropertyValue(properties, JAXBRIContext.TYPE_REFERENCES, Collection.class); 118 if (tr == null) { 119 tr = Collections.<TypeReference>emptyList(); 120 } 121 122 Map<Class,Class> subclassReplacements; 123 try { 124 subclassReplacements = TypeCast.checkedCast( 125 getPropertyValue(properties, JAXBRIContext.SUBCLASS_REPLACEMENTS, Map.class), Class.class, Class.class); 126 } catch (ClassCastException e) { 127 throw new JAXBException(Messages.INVALID_TYPE_IN_MAP.format(),e); 128 } 129 130 if(!properties.isEmpty()) { 131 throw new JAXBException(Messages.UNSUPPORTED_PROPERTY.format(properties.keySet().iterator().next())); 132 } 133 134 JAXBContextImpl.JAXBContextBuilder builder = new JAXBContextImpl.JAXBContextBuilder(); 135 builder.setClasses(classes); 136 builder.setTypeRefs(tr); 137 builder.setSubclassReplacements(subclassReplacements); 138 builder.setDefaultNsUri(defaultNsUri); 139 builder.setC14NSupport(c14nSupport); 140 builder.setAnnotationReader(ar); 141 builder.setXmlAccessorFactorySupport(xmlAccessorFactorySupport); 142 builder.setAllNillable(allNillable); 143 builder.setRetainPropertyInfo(retainPropertyInfo); 144 builder.setSupressAccessorWarnings(supressAccessorWarnings); 145 builder.setImprovedXsiTypeHandling(improvedXsiTypeHandling); 146 builder.setDisableSecurityProcessing(disablesecurityProcessing); 147 return builder.build(); 148 } 149 150 /** 151 * If a key is present in the map, remove the value and return it. 152 */ 153 private static <T> T getPropertyValue(Map<String, Object> properties, String keyName, Class<T> type ) throws JAXBException { 154 Object o = properties.get(keyName); 155 if(o==null) return null; 156 157 properties.remove(keyName); 158 if(!type.isInstance(o)) 159 throw new JAXBException(Messages.INVALID_PROPERTY_VALUE.format(keyName,o)); 160 else 161 return type.cast(o); 162 } 163 164 /** 165 * 166 * @param classes 167 * @param typeRefs 168 * @param subclassReplacements 169 * @param defaultNsUri 170 * @param c14nSupport 171 * @param ar 172 * @param xmlAccessorFactorySupport 173 * @param allNillable 174 * @param retainPropertyInfo 175 * @return 176 * @throws JAXBException 177 * @deprecated use {@code createContext(Class[] classes, Map<String,Object> properties)} method instead 178 */ 179 @Deprecated 180 public static JAXBRIContext createContext( Class[] classes, 181 Collection<TypeReference> typeRefs, Map<Class,Class> subclassReplacements, 182 String defaultNsUri, boolean c14nSupport, RuntimeAnnotationReader ar, 183 boolean xmlAccessorFactorySupport, boolean allNillable, boolean retainPropertyInfo) throws JAXBException { 184 185 return createContext(classes, typeRefs, subclassReplacements, 186 defaultNsUri, c14nSupport, ar, xmlAccessorFactorySupport, 187 allNillable, retainPropertyInfo, false); 188 } 189 190 /** 191 * 192 * @param classes 193 * @param typeRefs 194 * @param subclassReplacements 195 * @param defaultNsUri 196 * @param c14nSupport 197 * @param ar 198 * @param xmlAccessorFactorySupport 199 * @param allNillable 200 * @param retainPropertyInfo 201 * @param improvedXsiTypeHandling 202 * @return 203 * @throws JAXBException 204 * @deprecated use {@code createContext( Class[] classes, Map<String,Object> properties)} method instead 205 */ 206 @Deprecated 207 public static JAXBRIContext createContext( Class[] classes, 208 Collection<TypeReference> typeRefs, Map<Class,Class> subclassReplacements, 209 String defaultNsUri, boolean c14nSupport, RuntimeAnnotationReader ar, 210 boolean xmlAccessorFactorySupport, boolean allNillable, boolean retainPropertyInfo, boolean improvedXsiTypeHandling) throws JAXBException { 211 212 JAXBContextImpl.JAXBContextBuilder builder = new JAXBContextImpl.JAXBContextBuilder(); 213 builder.setClasses(classes); 214 builder.setTypeRefs(typeRefs); 215 builder.setSubclassReplacements(subclassReplacements); 216 builder.setDefaultNsUri(defaultNsUri); 217 builder.setC14NSupport(c14nSupport); 218 builder.setAnnotationReader(ar); 219 builder.setXmlAccessorFactorySupport(xmlAccessorFactorySupport); 220 builder.setAllNillable(allNillable); 221 builder.setRetainPropertyInfo(retainPropertyInfo); 222 builder.setImprovedXsiTypeHandling(improvedXsiTypeHandling); 223 return builder.build(); 224 } 225 226 /** 227 * The API will invoke this method via reflection. 228 */ 229 public static JAXBContext createContext( String contextPath, 230 ClassLoader classLoader, Map<String,Object> properties ) throws JAXBException { 231 FinalArrayList<Class> classes = new FinalArrayList<Class>(); 232 StringTokenizer tokens = new StringTokenizer(contextPath,":"); 233 List<Class> indexedClasses; 234 235 // at least on of these must be true per package 236 boolean foundObjectFactory; 237 boolean foundJaxbIndex; 238 239 while(tokens.hasMoreTokens()) { 240 foundObjectFactory = foundJaxbIndex = false; 241 String pkg = tokens.nextToken(); 242 243 // look for ObjectFactory and load it 244 final Class<?> o; 245 try { 246 o = classLoader.loadClass(pkg+".ObjectFactory"); 247 classes.add(o); 248 foundObjectFactory = true; 249 } catch (ClassNotFoundException e) { 250 // not necessarily an error 251 } 252 253 // look for jaxb.index and load the list of classes 254 try { 255 indexedClasses = loadIndexedClasses(pkg, classLoader); 256 } catch (IOException e) { 257 //TODO: think about this more 258 throw new JAXBException(e); 259 } 260 if(indexedClasses != null) { 261 classes.addAll(indexedClasses); 262 foundJaxbIndex = true; 263 } 264 265 if( !(foundObjectFactory || foundJaxbIndex) ) { 266 throw new JAXBException( Messages.BROKEN_CONTEXTPATH.format(pkg)); 267 } 268 } 269 270 271 return createContext(classes.toArray(new Class[classes.size()]),properties); 272 } 273 274 /** 275 * Look for jaxb.index file in the specified package and load it's contents 276 * 277 * @param pkg package name to search in 278 * @param classLoader ClassLoader to search in 279 * @return a List of Class objects to load, null if there weren't any 280 * @throws IOException if there is an error reading the index file 281 * @throws JAXBException if there are any errors in the index file 282 */ 283 private static List<Class> loadIndexedClasses(String pkg, ClassLoader classLoader) throws IOException, JAXBException { 284 final String resource = pkg.replace('.', '/') + "/jaxb.index"; 285 final InputStream resourceAsStream = classLoader.getResourceAsStream(resource); 286 287 if (resourceAsStream == null) { 288 return null; 289 } 290 291 BufferedReader in = 292 new BufferedReader(new InputStreamReader(resourceAsStream, "UTF-8")); 293 try { 294 FinalArrayList<Class> classes = new FinalArrayList<Class>(); 295 String className = in.readLine(); 296 while (className != null) { 297 className = className.trim(); 298 if (className.startsWith("#") || (className.length() == 0)) { 299 className = in.readLine(); 300 continue; 301 } 302 303 if (className.endsWith(".class")) { 304 throw new JAXBException(Messages.ILLEGAL_ENTRY.format(className)); 305 } 306 307 try { 308 classes.add(classLoader.loadClass(pkg + '.' + className)); 309 } catch (ClassNotFoundException e) { 310 throw new JAXBException(Messages.ERROR_LOADING_CLASS.format(className, resource),e); 311 } 312 313 className = in.readLine(); 314 } 315 return classes; 316 } finally { 317 in.close(); 318 } 319 } 320 321 public static final String USE_JAXB_PROPERTIES = "_useJAXBProperties"; 322 }