1 /* 2 * Copyright (c) 1997, 2017, 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 Boolean backupWithParentNamespace = getPropertyValue(properties, JAXBRIContext.BACKUP_WITH_PARENT_NAMESPACE, Boolean.class); 116 117 RuntimeAnnotationReader ar = getPropertyValue(properties,JAXBRIContext.ANNOTATION_READER,RuntimeAnnotationReader.class); 118 119 Collection<TypeReference> tr = getPropertyValue(properties, JAXBRIContext.TYPE_REFERENCES, Collection.class); 120 if (tr == null) { 121 tr = Collections.<TypeReference>emptyList(); 122 } 123 124 Map<Class,Class> subclassReplacements; 125 try { 126 subclassReplacements = TypeCast.checkedCast( 127 getPropertyValue(properties, JAXBRIContext.SUBCLASS_REPLACEMENTS, Map.class), Class.class, Class.class); 128 } catch (ClassCastException e) { 129 throw new JAXBException(Messages.INVALID_TYPE_IN_MAP.format(),e); 130 } 131 132 if(!properties.isEmpty()) { 133 throw new JAXBException(Messages.UNSUPPORTED_PROPERTY.format(properties.keySet().iterator().next())); 134 } 135 136 JAXBContextImpl.JAXBContextBuilder builder = new JAXBContextImpl.JAXBContextBuilder(); 137 builder.setClasses(classes); 138 builder.setTypeRefs(tr); 139 builder.setSubclassReplacements(subclassReplacements); 140 builder.setDefaultNsUri(defaultNsUri); 141 builder.setC14NSupport(c14nSupport); 142 builder.setAnnotationReader(ar); 143 builder.setXmlAccessorFactorySupport(xmlAccessorFactorySupport); 144 builder.setAllNillable(allNillable); 145 builder.setRetainPropertyInfo(retainPropertyInfo); 146 builder.setSupressAccessorWarnings(supressAccessorWarnings); 147 builder.setImprovedXsiTypeHandling(improvedXsiTypeHandling); 148 builder.setDisableSecurityProcessing(disablesecurityProcessing); 149 builder.setBackupWithParentNamespace(backupWithParentNamespace); 150 return builder.build(); 151 } 152 153 /** 154 * If a key is present in the map, remove the value and return it. 155 */ 156 private static <T> T getPropertyValue(Map<String, Object> properties, String keyName, Class<T> type ) throws JAXBException { 157 Object o = properties.get(keyName); 158 if(o==null) return null; 159 160 properties.remove(keyName); 161 if(!type.isInstance(o)) 162 throw new JAXBException(Messages.INVALID_PROPERTY_VALUE.format(keyName,o)); 163 else 164 return type.cast(o); 165 } 166 167 /** 168 * 169 * @param classes 170 * @param typeRefs 171 * @param subclassReplacements 172 * @param defaultNsUri 173 * @param c14nSupport 174 * @param ar 175 * @param xmlAccessorFactorySupport 176 * @param allNillable 177 * @param retainPropertyInfo 178 * @return 179 * @throws JAXBException 180 * @deprecated use {@code createContext(Class[] classes, Map<String,Object> properties)} method instead 181 */ 182 @Deprecated 183 public static JAXBRIContext createContext( Class[] classes, 184 Collection<TypeReference> typeRefs, Map<Class,Class> subclassReplacements, 185 String defaultNsUri, boolean c14nSupport, RuntimeAnnotationReader ar, 186 boolean xmlAccessorFactorySupport, boolean allNillable, boolean retainPropertyInfo) throws JAXBException { 187 188 return createContext(classes, typeRefs, subclassReplacements, 189 defaultNsUri, c14nSupport, ar, xmlAccessorFactorySupport, 190 allNillable, retainPropertyInfo, false); 191 } 192 193 /** 194 * 195 * @param classes 196 * @param typeRefs 197 * @param subclassReplacements 198 * @param defaultNsUri 199 * @param c14nSupport 200 * @param ar 201 * @param xmlAccessorFactorySupport 202 * @param allNillable 203 * @param retainPropertyInfo 204 * @param improvedXsiTypeHandling 205 * @return 206 * @throws JAXBException 207 * @deprecated use {@code createContext( Class[] classes, Map<String,Object> properties)} method instead 208 */ 209 @Deprecated 210 public static JAXBRIContext createContext( Class[] classes, 211 Collection<TypeReference> typeRefs, Map<Class,Class> subclassReplacements, 212 String defaultNsUri, boolean c14nSupport, RuntimeAnnotationReader ar, 213 boolean xmlAccessorFactorySupport, boolean allNillable, boolean retainPropertyInfo, boolean improvedXsiTypeHandling) throws JAXBException { 214 215 JAXBContextImpl.JAXBContextBuilder builder = new JAXBContextImpl.JAXBContextBuilder(); 216 builder.setClasses(classes); 217 builder.setTypeRefs(typeRefs); 218 builder.setSubclassReplacements(subclassReplacements); 219 builder.setDefaultNsUri(defaultNsUri); 220 builder.setC14NSupport(c14nSupport); 221 builder.setAnnotationReader(ar); 222 builder.setXmlAccessorFactorySupport(xmlAccessorFactorySupport); 223 builder.setAllNillable(allNillable); 224 builder.setRetainPropertyInfo(retainPropertyInfo); 225 builder.setImprovedXsiTypeHandling(improvedXsiTypeHandling); 226 return builder.build(); 227 } 228 229 /** 230 * The API will invoke this method via reflection. 231 */ 232 public static JAXBContext createContext( String contextPath, 233 ClassLoader classLoader, Map<String,Object> properties ) throws JAXBException { 234 FinalArrayList<Class> classes = new FinalArrayList<Class>(); 235 StringTokenizer tokens = new StringTokenizer(contextPath,":"); 236 List<Class> indexedClasses; 237 238 // at least on of these must be true per package 239 boolean foundObjectFactory; 240 boolean foundJaxbIndex; 241 242 while(tokens.hasMoreTokens()) { 243 foundObjectFactory = foundJaxbIndex = false; 244 String pkg = tokens.nextToken(); 245 246 // look for ObjectFactory and load it 247 final Class<?> o; 248 try { 249 o = classLoader.loadClass(pkg+".ObjectFactory"); 250 classes.add(o); 251 foundObjectFactory = true; 252 } catch (ClassNotFoundException e) { 253 // not necessarily an error 254 } 255 256 // look for jaxb.index and load the list of classes 257 try { 258 indexedClasses = loadIndexedClasses(pkg, classLoader); 259 } catch (IOException e) { 260 //TODO: think about this more 261 throw new JAXBException(e); 262 } 263 if(indexedClasses != null) { 264 classes.addAll(indexedClasses); 265 foundJaxbIndex = true; 266 } 267 268 if( !(foundObjectFactory || foundJaxbIndex) ) { 269 throw new JAXBException( Messages.BROKEN_CONTEXTPATH.format(pkg)); 270 } 271 } 272 273 274 return createContext(classes.toArray(new Class[classes.size()]),properties); 275 } 276 277 /** 278 * Look for jaxb.index file in the specified package and load it's contents 279 * 280 * @param pkg package name to search in 281 * @param classLoader ClassLoader to search in 282 * @return a List of Class objects to load, null if there weren't any 283 * @throws IOException if there is an error reading the index file 284 * @throws JAXBException if there are any errors in the index file 285 */ 286 private static List<Class> loadIndexedClasses(String pkg, ClassLoader classLoader) throws IOException, JAXBException { 287 final String resource = pkg.replace('.', '/') + "/jaxb.index"; 288 final InputStream resourceAsStream = classLoader.getResourceAsStream(resource); 289 290 if (resourceAsStream == null) { 291 return null; 292 } 293 294 BufferedReader in = 295 new BufferedReader(new InputStreamReader(resourceAsStream, "UTF-8")); 296 try { 297 FinalArrayList<Class> classes = new FinalArrayList<Class>(); 298 String className = in.readLine(); 299 while (className != null) { 300 className = className.trim(); 301 if (className.startsWith("#") || (className.length() == 0)) { 302 className = in.readLine(); 303 continue; 304 } 305 306 if (className.endsWith(".class")) { 307 throw new JAXBException(Messages.ILLEGAL_ENTRY.format(className)); 308 } 309 310 try { 311 classes.add(classLoader.loadClass(pkg + '.' + className)); 312 } catch (ClassNotFoundException e) { 313 throw new JAXBException(Messages.ERROR_LOADING_CLASS.format(className, resource),e); 314 } 315 316 className = in.readLine(); 317 } 318 return classes; 319 } finally { 320 in.close(); 321 } 322 } 323 324 public static final String USE_JAXB_PROPERTIES = "_useJAXBProperties"; 325 }