author | mkos |
Fri, 22 Nov 2013 21:11:19 +0100 | |
changeset 22427 | 1f8304cd1d53 |
parent 18372 | 4d90cbb0d70a |
child 23961 | 439846965790 |
permissions | -rw-r--r-- |
12009 | 1 |
/* |
18372
4d90cbb0d70a
8013021: Rebase 8005432 & 8003542 against the latest jdk8/jaxws
mkos
parents:
16791
diff
changeset
|
2 |
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. |
12009 | 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.runtime; |
|
27 |
||
28 |
import java.io.IOException; |
|
29 |
import java.lang.ref.WeakReference; |
|
30 |
import java.lang.reflect.Field; |
|
31 |
import java.lang.reflect.Method; |
|
32 |
import java.lang.reflect.Type; |
|
33 |
import java.util.Arrays; |
|
34 |
import java.util.Collection; |
|
35 |
import java.util.Collections; |
|
36 |
import java.util.Comparator; |
|
37 |
import java.util.HashMap; |
|
38 |
import java.util.HashSet; |
|
39 |
import java.util.LinkedHashMap; |
|
40 |
import java.util.List; |
|
41 |
import java.util.Map; |
|
42 |
import java.util.Map.Entry; |
|
43 |
import java.util.Set; |
|
44 |
import java.util.TreeSet; |
|
45 |
import javax.xml.bind.Binder; |
|
46 |
import javax.xml.bind.JAXBContext; |
|
47 |
import javax.xml.bind.JAXBElement; |
|
48 |
import javax.xml.bind.JAXBException; |
|
49 |
import javax.xml.bind.JAXBIntrospector; |
|
50 |
import javax.xml.bind.Marshaller; |
|
51 |
import javax.xml.bind.SchemaOutputResolver; |
|
52 |
import javax.xml.bind.Unmarshaller; |
|
53 |
import javax.xml.bind.Validator; |
|
54 |
import javax.xml.bind.annotation.XmlAttachmentRef; |
|
55 |
import javax.xml.bind.annotation.XmlList; |
|
56 |
import javax.xml.bind.annotation.XmlNs; |
|
57 |
import javax.xml.bind.annotation.XmlSchema; |
|
58 |
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; |
|
59 |
import javax.xml.namespace.QName; |
|
60 |
import javax.xml.parsers.DocumentBuilder; |
|
61 |
import javax.xml.parsers.DocumentBuilderFactory; |
|
62 |
import javax.xml.parsers.FactoryConfigurationError; |
|
63 |
import javax.xml.parsers.ParserConfigurationException; |
|
64 |
import javax.xml.transform.Result; |
|
65 |
import javax.xml.transform.Transformer; |
|
66 |
import javax.xml.transform.TransformerConfigurationException; |
|
67 |
import javax.xml.transform.TransformerFactory; |
|
68 |
import javax.xml.transform.sax.SAXTransformerFactory; |
|
69 |
import javax.xml.transform.sax.TransformerHandler; |
|
70 |
||
71 |
import com.sun.istack.internal.NotNull; |
|
72 |
import com.sun.istack.internal.Pool; |
|
16791 | 73 |
import com.sun.xml.internal.bind.v2.WellKnownNamespace; |
12009 | 74 |
import com.sun.xml.internal.bind.api.AccessorException; |
75 |
import com.sun.xml.internal.bind.api.Bridge; |
|
76 |
import com.sun.xml.internal.bind.api.BridgeContext; |
|
77 |
import com.sun.xml.internal.bind.api.CompositeStructure; |
|
78 |
import com.sun.xml.internal.bind.api.ErrorListener; |
|
79 |
import com.sun.xml.internal.bind.api.JAXBRIContext; |
|
80 |
import com.sun.xml.internal.bind.api.RawAccessor; |
|
81 |
import com.sun.xml.internal.bind.api.TypeReference; |
|
82 |
import com.sun.xml.internal.bind.unmarshaller.DOMScanner; |
|
83 |
import com.sun.xml.internal.bind.util.Which; |
|
84 |
import com.sun.xml.internal.bind.v2.model.annotation.RuntimeAnnotationReader; |
|
85 |
import com.sun.xml.internal.bind.v2.model.annotation.RuntimeInlineAnnotationReader; |
|
86 |
import com.sun.xml.internal.bind.v2.model.core.Adapter; |
|
87 |
import com.sun.xml.internal.bind.v2.model.core.NonElement; |
|
88 |
import com.sun.xml.internal.bind.v2.model.core.Ref; |
|
89 |
import com.sun.xml.internal.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl; |
|
90 |
import com.sun.xml.internal.bind.v2.model.impl.RuntimeModelBuilder; |
|
91 |
import com.sun.xml.internal.bind.v2.model.nav.Navigator; |
|
92 |
import com.sun.xml.internal.bind.v2.model.runtime.RuntimeArrayInfo; |
|
93 |
import com.sun.xml.internal.bind.v2.model.runtime.RuntimeBuiltinLeafInfo; |
|
94 |
import com.sun.xml.internal.bind.v2.model.runtime.RuntimeClassInfo; |
|
95 |
import com.sun.xml.internal.bind.v2.model.runtime.RuntimeElementInfo; |
|
96 |
import com.sun.xml.internal.bind.v2.model.runtime.RuntimeEnumLeafInfo; |
|
97 |
import com.sun.xml.internal.bind.v2.model.runtime.RuntimeLeafInfo; |
|
98 |
import com.sun.xml.internal.bind.v2.model.runtime.RuntimeTypeInfo; |
|
99 |
import com.sun.xml.internal.bind.v2.model.runtime.RuntimeTypeInfoSet; |
|
100 |
import com.sun.xml.internal.bind.v2.runtime.output.Encoded; |
|
101 |
import com.sun.xml.internal.bind.v2.runtime.property.AttributeProperty; |
|
102 |
import com.sun.xml.internal.bind.v2.runtime.property.Property; |
|
103 |
import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; |
|
104 |
import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader; |
|
105 |
import com.sun.xml.internal.bind.v2.runtime.unmarshaller.TagName; |
|
106 |
import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl; |
|
107 |
import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext; |
|
108 |
import com.sun.xml.internal.bind.v2.schemagen.XmlSchemaGenerator; |
|
109 |
import com.sun.xml.internal.bind.v2.util.EditDistance; |
|
110 |
import com.sun.xml.internal.bind.v2.util.QNameMap; |
|
16791 | 111 |
import com.sun.xml.internal.bind.v2.util.XmlFactory; |
12009 | 112 |
import com.sun.xml.internal.txw2.output.ResultFactory; |
113 |
||
114 |
import org.w3c.dom.Document; |
|
115 |
import org.w3c.dom.Element; |
|
116 |
import org.w3c.dom.Node; |
|
117 |
import org.xml.sax.SAXException; |
|
118 |
import org.xml.sax.SAXParseException; |
|
119 |
||
120 |
/** |
|
121 |
* This class provides the implementation of JAXBContext. |
|
122 |
* |
|
123 |
*/ |
|
124 |
public final class JAXBContextImpl extends JAXBRIContext { |
|
125 |
||
126 |
/** |
|
127 |
* All the bridge classes. |
|
128 |
*/ |
|
129 |
private final Map<TypeReference,Bridge> bridges = new LinkedHashMap<TypeReference,Bridge>(); |
|
130 |
||
131 |
/** |
|
132 |
* Shared instance of {@link TransformerFactory}. |
|
133 |
* Lock before use, because a {@link TransformerFactory} is not thread-safe |
|
134 |
* whereas {@link JAXBContextImpl} is. |
|
135 |
* Lazily created. |
|
136 |
*/ |
|
137 |
private volatile static SAXTransformerFactory tf; |
|
138 |
||
139 |
/** |
|
140 |
* Shared instance of {@link DocumentBuilder}. |
|
141 |
* Lock before use. Lazily created. |
|
142 |
*/ |
|
143 |
private static DocumentBuilder db; |
|
144 |
||
145 |
private final QNameMap<JaxBeanInfo> rootMap = new QNameMap<JaxBeanInfo>(); |
|
146 |
private final HashMap<QName,JaxBeanInfo> typeMap = new HashMap<QName,JaxBeanInfo>(); |
|
147 |
||
148 |
/** |
|
149 |
* Map from JAXB-bound {@link Class} to its {@link JaxBeanInfo}. |
|
150 |
*/ |
|
151 |
private final Map<Class,JaxBeanInfo> beanInfoMap = new LinkedHashMap<Class,JaxBeanInfo>(); |
|
152 |
||
153 |
/** |
|
154 |
* All created {@link JaxBeanInfo}s. |
|
155 |
* Updated from each {@link JaxBeanInfo}s constructors to avoid infinite recursion |
|
156 |
* for a cyclic reference. |
|
157 |
* |
|
158 |
* <p> |
|
159 |
* This map is only used while the {@link JAXBContextImpl} is built and set to null |
|
160 |
* to avoid keeping references too long. |
|
161 |
*/ |
|
162 |
protected Map<RuntimeTypeInfo,JaxBeanInfo> beanInfos = new LinkedHashMap<RuntimeTypeInfo, JaxBeanInfo>(); |
|
163 |
||
164 |
private final Map<Class/*scope*/,Map<QName,ElementBeanInfoImpl>> elements = new LinkedHashMap<Class, Map<QName, ElementBeanInfoImpl>>(); |
|
165 |
||
166 |
/** |
|
167 |
* Pool of {@link Marshaller}s. |
|
168 |
*/ |
|
169 |
public final Pool<Marshaller> marshallerPool = new Pool.Impl<Marshaller>() { |
|
170 |
protected @NotNull Marshaller create() { |
|
171 |
return createMarshaller(); |
|
172 |
} |
|
173 |
}; |
|
174 |
||
175 |
public final Pool<Unmarshaller> unmarshallerPool = new Pool.Impl<Unmarshaller>() { |
|
176 |
protected @NotNull Unmarshaller create() { |
|
177 |
return createUnmarshaller(); |
|
178 |
} |
|
179 |
}; |
|
180 |
||
181 |
/** |
|
182 |
* Used to assign indices to known names in this grammar. |
|
183 |
* Reset to null once the build phase is completed. |
|
184 |
*/ |
|
185 |
public NameBuilder nameBuilder = new NameBuilder(); |
|
186 |
||
187 |
/** |
|
188 |
* Keeps the list of known names. |
|
189 |
* This field is set once the build pahse is completed. |
|
190 |
*/ |
|
191 |
public final NameList nameList; |
|
192 |
||
193 |
/** |
|
194 |
* Input to the JAXBContext.newInstance, so that we can recreate |
|
195 |
* {@link RuntimeTypeInfoSet} whenever we need. |
|
196 |
*/ |
|
197 |
private final String defaultNsUri; |
|
198 |
private final Class[] classes; |
|
199 |
||
200 |
/** |
|
201 |
* true to reorder attributes lexicographically in preparation of the c14n support. |
|
202 |
*/ |
|
203 |
protected final boolean c14nSupport; |
|
204 |
||
205 |
/** |
|
206 |
* Flag that user has provided a custom AccessorFactory for JAXB to use |
|
207 |
*/ |
|
208 |
public final boolean xmlAccessorFactorySupport; |
|
209 |
||
210 |
/** |
|
211 |
* @see JAXBRIContext#TREAT_EVERYTHING_NILLABLE |
|
212 |
*/ |
|
213 |
public final boolean allNillable; |
|
214 |
||
215 |
/** |
|
216 |
* Store properties, so that they can be recovered in the run (is here because of JSON encoding of Jersey). |
|
217 |
*/ |
|
218 |
public final boolean retainPropertyInfo; |
|
219 |
||
220 |
/** |
|
16791 | 221 |
* Suppress reflection accessor warnings. |
12009 | 222 |
*/ |
223 |
public final boolean supressAccessorWarnings; |
|
224 |
||
225 |
/** |
|
226 |
* Improved xsi type handling. |
|
227 |
*/ |
|
228 |
public final boolean improvedXsiTypeHandling; |
|
229 |
||
16791 | 230 |
/** |
231 |
* Disable security processing. |
|
232 |
*/ |
|
233 |
public final boolean disableSecurityProcessing; |
|
234 |
||
12009 | 235 |
private WeakReference<RuntimeTypeInfoSet> typeInfoSetCache; |
236 |
||
237 |
private @NotNull RuntimeAnnotationReader annotationReader; |
|
238 |
||
239 |
private /*almost final*/ boolean hasSwaRef; |
|
240 |
private final @NotNull Map<Class,Class> subclassReplacements; |
|
241 |
||
242 |
/** |
|
16791 | 243 |
* If true, we aim for faster {@link JAXBContext} instantiation performance, |
12009 | 244 |
* instead of going after efficient sustained unmarshalling/marshalling performance. |
245 |
* |
|
246 |
* @since 2.0.4 |
|
247 |
*/ |
|
248 |
public final boolean fastBoot; |
|
249 |
||
250 |
private Set<XmlNs> xmlNsSet = null; |
|
251 |
||
252 |
/** |
|
253 |
* Returns declared XmlNs annotations (from package-level annotation XmlSchema |
|
254 |
* |
|
255 |
* @return set of all present XmlNs annotations |
|
256 |
*/ |
|
257 |
public Set<XmlNs> getXmlNsSet() { |
|
258 |
return xmlNsSet; |
|
259 |
} |
|
260 |
||
261 |
private JAXBContextImpl(JAXBContextBuilder builder) throws JAXBException { |
|
262 |
||
263 |
this.defaultNsUri = builder.defaultNsUri; |
|
264 |
this.retainPropertyInfo = builder.retainPropertyInfo; |
|
265 |
this.annotationReader = builder.annotationReader; |
|
266 |
this.subclassReplacements = builder.subclassReplacements; |
|
267 |
this.c14nSupport = builder.c14nSupport; |
|
268 |
this.classes = builder.classes; |
|
269 |
this.xmlAccessorFactorySupport = builder.xmlAccessorFactorySupport; |
|
270 |
this.allNillable = builder.allNillable; |
|
271 |
this.supressAccessorWarnings = builder.supressAccessorWarnings; |
|
272 |
this.improvedXsiTypeHandling = builder.improvedXsiTypeHandling; |
|
16791 | 273 |
this.disableSecurityProcessing = builder.disableSecurityProcessing; |
12009 | 274 |
|
275 |
Collection<TypeReference> typeRefs = builder.typeRefs; |
|
276 |
||
277 |
boolean fastB; |
|
278 |
try { |
|
279 |
fastB = Boolean.getBoolean(JAXBContextImpl.class.getName()+".fastBoot"); |
|
280 |
} catch (SecurityException e) { |
|
281 |
fastB = false; |
|
282 |
} |
|
283 |
this.fastBoot = fastB; |
|
284 |
||
285 |
RuntimeTypeInfoSet typeSet = getTypeInfoSet(); |
|
286 |
||
287 |
// at least prepare the empty table so that we don't have to check for null later |
|
288 |
elements.put(null,new LinkedHashMap<QName, ElementBeanInfoImpl>()); |
|
289 |
||
290 |
// recognize leaf bean infos |
|
291 |
for( RuntimeBuiltinLeafInfo leaf : RuntimeBuiltinLeafInfoImpl.builtinBeanInfos ) { |
|
292 |
LeafBeanInfoImpl<?> bi = new LeafBeanInfoImpl(this,leaf); |
|
293 |
beanInfoMap.put(leaf.getClazz(),bi); |
|
294 |
for( QName t : bi.getTypeNames() ) |
|
295 |
typeMap.put(t,bi); |
|
296 |
} |
|
297 |
||
298 |
for (RuntimeEnumLeafInfo e : typeSet.enums().values()) { |
|
299 |
JaxBeanInfo<?> bi = getOrCreate(e); |
|
300 |
for (QName qn : bi.getTypeNames()) |
|
301 |
typeMap.put( qn, bi ); |
|
302 |
if(e.isElement()) |
|
303 |
rootMap.put( e.getElementName(), bi ); |
|
304 |
} |
|
305 |
||
306 |
for (RuntimeArrayInfo a : typeSet.arrays().values()) { |
|
307 |
JaxBeanInfo<?> ai = getOrCreate(a); |
|
308 |
for (QName qn : ai.getTypeNames()) |
|
309 |
typeMap.put( qn, ai ); |
|
310 |
} |
|
311 |
||
312 |
for( Entry<Class, ? extends RuntimeClassInfo> e : typeSet.beans().entrySet() ) { |
|
313 |
ClassBeanInfoImpl<?> bi = getOrCreate(e.getValue()); |
|
314 |
||
315 |
XmlSchema xs = this.annotationReader.getPackageAnnotation(XmlSchema.class, e.getKey(), null); |
|
316 |
if(xs != null) { |
|
317 |
if(xs.xmlns() != null && xs.xmlns().length > 0) { |
|
318 |
if(xmlNsSet == null) |
|
319 |
xmlNsSet = new HashSet<XmlNs>(); |
|
320 |
xmlNsSet.addAll(Arrays.asList(xs.xmlns())); |
|
321 |
} |
|
322 |
} |
|
323 |
||
324 |
if(bi.isElement()) |
|
325 |
rootMap.put( e.getValue().getElementName(), bi ); |
|
326 |
||
327 |
for (QName qn : bi.getTypeNames()) |
|
328 |
typeMap.put( qn, bi ); |
|
329 |
} |
|
330 |
||
331 |
// fill in element mappings |
|
332 |
for( RuntimeElementInfo n : typeSet.getAllElements() ) { |
|
333 |
ElementBeanInfoImpl bi = getOrCreate(n); |
|
334 |
if(n.getScope()==null) |
|
335 |
rootMap.put(n.getElementName(),bi); |
|
336 |
||
337 |
RuntimeClassInfo scope = n.getScope(); |
|
338 |
Class scopeClazz = scope==null?null:scope.getClazz(); |
|
339 |
Map<QName,ElementBeanInfoImpl> m = elements.get(scopeClazz); |
|
340 |
if(m==null) { |
|
341 |
m = new LinkedHashMap<QName, ElementBeanInfoImpl>(); |
|
342 |
elements.put(scopeClazz,m); |
|
343 |
} |
|
344 |
m.put(n.getElementName(),bi); |
|
345 |
} |
|
346 |
||
347 |
// this one is so that we can handle plain JAXBElements. |
|
348 |
beanInfoMap.put(JAXBElement.class,new ElementBeanInfoImpl(this)); |
|
349 |
// another special BeanInfoImpl just for marshalling |
|
350 |
beanInfoMap.put(CompositeStructure.class,new CompositeStructureBeanInfo(this)); |
|
351 |
||
352 |
getOrCreate(typeSet.getAnyTypeInfo()); |
|
353 |
||
354 |
// then link them all! |
|
355 |
for (JaxBeanInfo bi : beanInfos.values()) |
|
356 |
bi.link(this); |
|
357 |
||
358 |
// register primitives for boxed types just to make GrammarInfo fool-proof |
|
359 |
for( Map.Entry<Class,Class> e : RuntimeUtil.primitiveToBox.entrySet() ) |
|
360 |
beanInfoMap.put( e.getKey(), beanInfoMap.get(e.getValue()) ); |
|
361 |
||
362 |
// build bridges |
|
22427 | 363 |
Navigator<Type, Class, Field, Method> nav = typeSet.getNavigator(); |
12009 | 364 |
|
365 |
for (TypeReference tr : typeRefs) { |
|
366 |
XmlJavaTypeAdapter xjta = tr.get(XmlJavaTypeAdapter.class); |
|
367 |
Adapter<Type,Class> a=null; |
|
368 |
XmlList xl = tr.get(XmlList.class); |
|
369 |
||
370 |
// eventually compute the in-memory type |
|
22427 | 371 |
Class erasedType = (Class) nav.erasure(tr.type); |
12009 | 372 |
|
373 |
if(xjta!=null) { |
|
374 |
a = new Adapter<Type,Class>(xjta.value(),nav); |
|
375 |
} |
|
376 |
if(tr.get(XmlAttachmentRef.class)!=null) { |
|
377 |
a = new Adapter<Type,Class>(SwaRefAdapter.class,nav); |
|
378 |
hasSwaRef = true; |
|
379 |
} |
|
380 |
||
381 |
if(a!=null) { |
|
22427 | 382 |
erasedType = (Class) nav.erasure(a.defaultType); |
12009 | 383 |
} |
384 |
||
385 |
Name name = nameBuilder.createElementName(tr.tagName); |
|
386 |
||
387 |
InternalBridge bridge; |
|
388 |
if(xl==null) |
|
389 |
bridge = new BridgeImpl(this, name,getBeanInfo(erasedType,true),tr); |
|
390 |
else |
|
391 |
bridge = new BridgeImpl(this, name,new ValueListBeanInfoImpl(this,erasedType),tr); |
|
392 |
||
393 |
if(a!=null) |
|
394 |
bridge = new BridgeAdapter(bridge,a.adapterType); |
|
395 |
||
396 |
bridges.put(tr,bridge); |
|
397 |
} |
|
398 |
||
399 |
this.nameList = nameBuilder.conclude(); |
|
400 |
||
401 |
for (JaxBeanInfo bi : beanInfos.values()) |
|
402 |
bi.wrapUp(); |
|
403 |
||
404 |
// no use for them now |
|
405 |
nameBuilder = null; |
|
406 |
beanInfos = null; |
|
407 |
} |
|
408 |
||
409 |
/** |
|
410 |
* True if this JAXBContext has {@link XmlAttachmentRef}. |
|
411 |
*/ |
|
412 |
public boolean hasSwaRef() { |
|
413 |
return hasSwaRef; |
|
414 |
} |
|
415 |
||
416 |
public RuntimeTypeInfoSet getRuntimeTypeInfoSet() { |
|
417 |
try { |
|
418 |
return getTypeInfoSet(); |
|
419 |
} catch (IllegalAnnotationsException e) { |
|
420 |
// impossible, once the model is constructred |
|
421 |
throw new AssertionError(e); |
|
422 |
} |
|
423 |
} |
|
424 |
||
425 |
/** |
|
426 |
* Creates a {@link RuntimeTypeInfoSet}. |
|
427 |
*/ |
|
428 |
public RuntimeTypeInfoSet getTypeInfoSet() throws IllegalAnnotationsException { |
|
429 |
||
430 |
// check cache |
|
431 |
if(typeInfoSetCache!=null) { |
|
432 |
RuntimeTypeInfoSet r = typeInfoSetCache.get(); |
|
433 |
if(r!=null) |
|
434 |
return r; |
|
435 |
} |
|
436 |
||
437 |
final RuntimeModelBuilder builder = new RuntimeModelBuilder(this,annotationReader,subclassReplacements,defaultNsUri); |
|
438 |
||
439 |
IllegalAnnotationsException.Builder errorHandler = new IllegalAnnotationsException.Builder(); |
|
440 |
builder.setErrorHandler(errorHandler); |
|
441 |
||
442 |
for( Class c : classes ) { |
|
443 |
if(c==CompositeStructure.class) |
|
444 |
// CompositeStructure doesn't have TypeInfo, so skip it. |
|
445 |
// We'll add JaxBeanInfo for this later automatically |
|
446 |
continue; |
|
447 |
builder.getTypeInfo(new Ref<Type,Class>(c)); |
|
448 |
} |
|
449 |
||
450 |
this.hasSwaRef |= builder.hasSwaRef; |
|
451 |
RuntimeTypeInfoSet r = builder.link(); |
|
452 |
||
453 |
errorHandler.check(); |
|
454 |
assert r!=null : "if no error was reported, the link must be a success"; |
|
455 |
||
456 |
typeInfoSetCache = new WeakReference<RuntimeTypeInfoSet>(r); |
|
457 |
||
458 |
return r; |
|
459 |
} |
|
460 |
||
461 |
||
462 |
public ElementBeanInfoImpl getElement(Class scope, QName name) { |
|
463 |
Map<QName,ElementBeanInfoImpl> m = elements.get(scope); |
|
464 |
if(m!=null) { |
|
465 |
ElementBeanInfoImpl bi = m.get(name); |
|
466 |
if(bi!=null) |
|
467 |
return bi; |
|
468 |
} |
|
469 |
m = elements.get(null); |
|
470 |
return m.get(name); |
|
471 |
} |
|
472 |
||
473 |
||
474 |
||
475 |
||
476 |
||
477 |
private ElementBeanInfoImpl getOrCreate( RuntimeElementInfo rei ) { |
|
478 |
JaxBeanInfo bi = beanInfos.get(rei); |
|
479 |
if(bi!=null) return (ElementBeanInfoImpl)bi; |
|
480 |
||
481 |
// all elements share the same type, so we can't register them to beanInfoMap |
|
482 |
return new ElementBeanInfoImpl(this, rei); |
|
483 |
} |
|
484 |
||
485 |
protected JaxBeanInfo getOrCreate( RuntimeEnumLeafInfo eli ) { |
|
486 |
JaxBeanInfo bi = beanInfos.get(eli); |
|
487 |
if(bi!=null) return bi; |
|
488 |
bi = new LeafBeanInfoImpl(this,eli); |
|
489 |
beanInfoMap.put(bi.jaxbType,bi); |
|
490 |
return bi; |
|
491 |
} |
|
492 |
||
493 |
protected ClassBeanInfoImpl getOrCreate( RuntimeClassInfo ci ) { |
|
494 |
ClassBeanInfoImpl bi = (ClassBeanInfoImpl)beanInfos.get(ci); |
|
495 |
if(bi!=null) return bi; |
|
496 |
bi = new ClassBeanInfoImpl(this,ci); |
|
497 |
beanInfoMap.put(bi.jaxbType,bi); |
|
498 |
return bi; |
|
499 |
} |
|
500 |
||
501 |
protected JaxBeanInfo getOrCreate( RuntimeArrayInfo ai ) { |
|
502 |
JaxBeanInfo abi = beanInfos.get(ai); |
|
503 |
if(abi!=null) return abi; |
|
504 |
||
505 |
abi = new ArrayBeanInfoImpl(this,ai); |
|
506 |
||
507 |
beanInfoMap.put(ai.getType(),abi); |
|
508 |
return abi; |
|
509 |
} |
|
510 |
||
511 |
public JaxBeanInfo getOrCreate(RuntimeTypeInfo e) { |
|
512 |
if(e instanceof RuntimeElementInfo) |
|
513 |
return getOrCreate((RuntimeElementInfo)e); |
|
514 |
if(e instanceof RuntimeClassInfo) |
|
515 |
return getOrCreate((RuntimeClassInfo)e); |
|
516 |
if(e instanceof RuntimeLeafInfo) { |
|
517 |
JaxBeanInfo bi = beanInfos.get(e); // must have been created |
|
518 |
assert bi!=null; |
|
519 |
return bi; |
|
520 |
} |
|
521 |
if(e instanceof RuntimeArrayInfo) |
|
522 |
return getOrCreate((RuntimeArrayInfo)e); |
|
523 |
if(e.getType()==Object.class) { |
|
524 |
// anyType |
|
525 |
JaxBeanInfo bi = beanInfoMap.get(Object.class); |
|
526 |
if(bi==null) { |
|
527 |
bi = new AnyTypeBeanInfo(this,e); |
|
528 |
beanInfoMap.put(Object.class,bi); |
|
529 |
} |
|
530 |
return bi; |
|
531 |
} |
|
532 |
||
533 |
throw new IllegalArgumentException(); |
|
534 |
} |
|
535 |
||
536 |
/** |
|
537 |
* Gets the {@link JaxBeanInfo} object that can handle |
|
538 |
* the given JAXB-bound object. |
|
539 |
* |
|
540 |
* <p> |
|
541 |
* This method traverses the base classes of the given object. |
|
542 |
* |
|
543 |
* @return null |
|
544 |
* if <tt>c</tt> isn't a JAXB-bound class and <tt>fatal==false</tt>. |
|
545 |
*/ |
|
546 |
public final JaxBeanInfo getBeanInfo(Object o) { |
|
547 |
// don't allow xs:anyType beanInfo to handle all the unbound objects |
|
548 |
for( Class c=o.getClass(); c!=Object.class; c=c.getSuperclass()) { |
|
549 |
JaxBeanInfo bi = beanInfoMap.get(c); |
|
550 |
if(bi!=null) return bi; |
|
551 |
} |
|
552 |
if(o instanceof Element) |
|
553 |
return beanInfoMap.get(Object.class); // return the BeanInfo for xs:anyType |
|
554 |
for( Class c : o.getClass().getInterfaces()) { |
|
555 |
JaxBeanInfo bi = beanInfoMap.get(c); |
|
556 |
if(bi!=null) return bi; |
|
557 |
} |
|
558 |
return null; |
|
559 |
} |
|
560 |
||
561 |
/** |
|
562 |
* Gets the {@link JaxBeanInfo} object that can handle |
|
563 |
* the given JAXB-bound object. |
|
564 |
* |
|
565 |
* @param fatal |
|
566 |
* if true, the failure to look up will throw an exception. |
|
567 |
* Otherwise it will just return null. |
|
568 |
*/ |
|
569 |
public final JaxBeanInfo getBeanInfo(Object o,boolean fatal) throws JAXBException { |
|
570 |
JaxBeanInfo bi = getBeanInfo(o); |
|
571 |
if(bi!=null) return bi; |
|
572 |
if(fatal) { |
|
573 |
if(o instanceof Document) |
|
574 |
throw new JAXBException(Messages.ELEMENT_NEEDED_BUT_FOUND_DOCUMENT.format(o.getClass())); |
|
575 |
throw new JAXBException(Messages.UNKNOWN_CLASS.format(o.getClass())); |
|
576 |
} |
|
577 |
return null; |
|
578 |
} |
|
579 |
||
580 |
/** |
|
581 |
* Gets the {@link JaxBeanInfo} object that can handle |
|
582 |
* the given JAXB-bound class. |
|
583 |
* |
|
584 |
* <p> |
|
585 |
* This method doesn't look for base classes. |
|
586 |
* |
|
587 |
* @return null |
|
588 |
* if <tt>c</tt> isn't a JAXB-bound class and <tt>fatal==false</tt>. |
|
589 |
*/ |
|
590 |
public final <T> JaxBeanInfo<T> getBeanInfo(Class<T> clazz) { |
|
591 |
return (JaxBeanInfo<T>)beanInfoMap.get(clazz); |
|
592 |
} |
|
593 |
||
594 |
/** |
|
595 |
* Gets the {@link JaxBeanInfo} object that can handle |
|
596 |
* the given JAXB-bound class. |
|
597 |
* |
|
598 |
* @param fatal |
|
599 |
* if true, the failure to look up will throw an exception. |
|
600 |
* Otherwise it will just return null. |
|
601 |
*/ |
|
602 |
public final <T> JaxBeanInfo<T> getBeanInfo(Class<T> clazz,boolean fatal) throws JAXBException { |
|
603 |
JaxBeanInfo<T> bi = getBeanInfo(clazz); |
|
604 |
if(bi!=null) return bi; |
|
605 |
if(fatal) |
|
606 |
throw new JAXBException(clazz.getName()+" is not known to this context"); |
|
607 |
return null; |
|
608 |
} |
|
609 |
||
610 |
/** |
|
611 |
* Based on the tag name, determine what object to unmarshal, |
|
612 |
* and then set a new object and its loader to the current unmarshaller state. |
|
613 |
* |
|
614 |
* @return |
|
615 |
* null if the given name pair is not recognized. |
|
616 |
*/ |
|
617 |
public final Loader selectRootLoader( UnmarshallingContext.State state, TagName tag ) { |
|
618 |
JaxBeanInfo beanInfo = rootMap.get(tag.uri,tag.local); |
|
619 |
if(beanInfo==null) |
|
620 |
return null; |
|
621 |
||
622 |
return beanInfo.getLoader(this,true); |
|
623 |
} |
|
624 |
||
625 |
/** |
|
626 |
* Gets the {@link JaxBeanInfo} for the given named XML Schema type. |
|
627 |
* |
|
628 |
* @return |
|
629 |
* null if the type name is not recognized. For schema |
|
630 |
* languages other than XML Schema, this method always |
|
631 |
* returns null. |
|
632 |
*/ |
|
633 |
public JaxBeanInfo getGlobalType(QName name) { |
|
634 |
return typeMap.get(name); |
|
635 |
} |
|
636 |
||
637 |
/** |
|
638 |
* Finds a type name that this context recognizes which is |
|
639 |
* "closest" to the given type name. |
|
640 |
* |
|
641 |
* <p> |
|
642 |
* This method is used for error recovery. |
|
643 |
*/ |
|
644 |
public String getNearestTypeName(QName name) { |
|
645 |
String[] all = new String[typeMap.size()]; |
|
646 |
int i=0; |
|
647 |
for (QName qn : typeMap.keySet()) { |
|
648 |
if(qn.getLocalPart().equals(name.getLocalPart())) |
|
649 |
return qn.toString(); // probably a match, as people often gets confused about namespace. |
|
650 |
all[i++] = qn.toString(); |
|
651 |
} |
|
652 |
||
653 |
String nearest = EditDistance.findNearest(name.toString(), all); |
|
654 |
||
655 |
if(EditDistance.editDistance(nearest,name.toString())>10) |
|
656 |
return null; // too far apart. |
|
657 |
||
658 |
return nearest; |
|
659 |
} |
|
660 |
||
661 |
/** |
|
662 |
* Returns the set of valid root tag names. |
|
663 |
* For diagnostic use. |
|
664 |
*/ |
|
665 |
public Set<QName> getValidRootNames() { |
|
666 |
Set<QName> r = new TreeSet<QName>(QNAME_COMPARATOR); |
|
667 |
for (QNameMap.Entry e : rootMap.entrySet()) { |
|
668 |
r.add(e.createQName()); |
|
669 |
} |
|
670 |
return r; |
|
671 |
} |
|
672 |
||
673 |
/** |
|
674 |
* Cache of UTF-8 encoded local names to improve the performance for the marshalling. |
|
675 |
*/ |
|
676 |
private Encoded[] utf8nameTable; |
|
677 |
||
678 |
public synchronized Encoded[] getUTF8NameTable() { |
|
679 |
if(utf8nameTable==null) { |
|
680 |
Encoded[] x = new Encoded[nameList.localNames.length]; |
|
681 |
for( int i=0; i<x.length; i++ ) { |
|
682 |
Encoded e = new Encoded(nameList.localNames[i]); |
|
683 |
e.compact(); |
|
684 |
x[i] = e; |
|
685 |
} |
|
686 |
utf8nameTable = x; |
|
687 |
} |
|
688 |
return utf8nameTable; |
|
689 |
} |
|
690 |
||
691 |
public int getNumberOfLocalNames() { |
|
692 |
return nameList.localNames.length; |
|
693 |
} |
|
694 |
||
695 |
public int getNumberOfElementNames() { |
|
696 |
return nameList.numberOfElementNames; |
|
697 |
} |
|
698 |
||
699 |
public int getNumberOfAttributeNames() { |
|
700 |
return nameList.numberOfAttributeNames; |
|
701 |
} |
|
702 |
||
703 |
/** |
|
704 |
* Creates a new identity transformer. |
|
705 |
*/ |
|
16791 | 706 |
static Transformer createTransformer(boolean disableSecureProcessing) { |
12009 | 707 |
try { |
708 |
if (tf==null) { |
|
709 |
synchronized(JAXBContextImpl.class) { |
|
710 |
if (tf==null) { |
|
16791 | 711 |
tf = (SAXTransformerFactory)XmlFactory.createTransformerFactory(disableSecureProcessing); |
12009 | 712 |
} |
713 |
} |
|
714 |
} |
|
715 |
return tf.newTransformer(); |
|
716 |
} catch (TransformerConfigurationException e) { |
|
717 |
throw new Error(e); // impossible |
|
718 |
} |
|
719 |
} |
|
720 |
||
721 |
/** |
|
722 |
* Creates a new identity transformer. |
|
723 |
*/ |
|
16791 | 724 |
public static TransformerHandler createTransformerHandler(boolean disableSecureProcessing) { |
12009 | 725 |
try { |
726 |
if (tf==null) { |
|
727 |
synchronized(JAXBContextImpl.class) { |
|
728 |
if (tf==null) { |
|
16791 | 729 |
tf = (SAXTransformerFactory)XmlFactory.createTransformerFactory(disableSecureProcessing); |
12009 | 730 |
} |
731 |
} |
|
732 |
} |
|
733 |
return tf.newTransformerHandler(); |
|
734 |
} catch (TransformerConfigurationException e) { |
|
735 |
throw new Error(e); // impossible |
|
736 |
} |
|
737 |
} |
|
738 |
||
739 |
/** |
|
740 |
* Creates a new DOM document. |
|
741 |
*/ |
|
16791 | 742 |
static Document createDom(boolean disableSecurityProcessing) { |
12009 | 743 |
synchronized(JAXBContextImpl.class) { |
744 |
if(db==null) { |
|
745 |
try { |
|
16791 | 746 |
DocumentBuilderFactory dbf = XmlFactory.createDocumentBuilderFactory(disableSecurityProcessing); |
12009 | 747 |
db = dbf.newDocumentBuilder(); |
748 |
} catch (ParserConfigurationException e) { |
|
749 |
// impossible |
|
750 |
throw new FactoryConfigurationError(e); |
|
751 |
} |
|
752 |
} |
|
753 |
return db.newDocument(); |
|
754 |
} |
|
755 |
} |
|
756 |
||
757 |
public MarshallerImpl createMarshaller() { |
|
758 |
return new MarshallerImpl(this,null); |
|
759 |
} |
|
760 |
||
761 |
public UnmarshallerImpl createUnmarshaller() { |
|
762 |
return new UnmarshallerImpl(this,null); |
|
763 |
} |
|
764 |
||
765 |
public Validator createValidator() { |
|
766 |
throw new UnsupportedOperationException(Messages.NOT_IMPLEMENTED_IN_2_0.format()); |
|
767 |
} |
|
768 |
||
769 |
@Override |
|
770 |
public JAXBIntrospector createJAXBIntrospector() { |
|
771 |
return new JAXBIntrospector() { |
|
772 |
public boolean isElement(Object object) { |
|
773 |
return getElementName(object)!=null; |
|
774 |
} |
|
775 |
||
776 |
public QName getElementName(Object jaxbElement) { |
|
777 |
try { |
|
778 |
return JAXBContextImpl.this.getElementName(jaxbElement); |
|
779 |
} catch (JAXBException e) { |
|
780 |
return null; |
|
781 |
} |
|
782 |
} |
|
783 |
}; |
|
784 |
} |
|
785 |
||
786 |
private NonElement<Type,Class> getXmlType(RuntimeTypeInfoSet tis, TypeReference tr) { |
|
787 |
if(tr==null) |
|
788 |
throw new IllegalArgumentException(); |
|
789 |
||
790 |
XmlJavaTypeAdapter xjta = tr.get(XmlJavaTypeAdapter.class); |
|
791 |
XmlList xl = tr.get(XmlList.class); |
|
792 |
||
793 |
Ref<Type,Class> ref = new Ref<Type,Class>(annotationReader, tis.getNavigator(), tr.type, xjta, xl ); |
|
794 |
||
795 |
return tis.getTypeInfo(ref); |
|
796 |
} |
|
797 |
||
798 |
@Override |
|
799 |
public void generateEpisode(Result output) { |
|
800 |
if(output==null) |
|
801 |
throw new IllegalArgumentException(); |
|
802 |
createSchemaGenerator().writeEpisodeFile(ResultFactory.createSerializer(output)); |
|
803 |
} |
|
804 |
||
805 |
@Override |
|
806 |
@SuppressWarnings("ThrowableInitCause") |
|
807 |
public void generateSchema(SchemaOutputResolver outputResolver) throws IOException { |
|
808 |
if(outputResolver==null) |
|
809 |
throw new IOException(Messages.NULL_OUTPUT_RESOLVER.format()); |
|
810 |
||
811 |
final SAXParseException[] e = new SAXParseException[1]; |
|
812 |
final SAXParseException[] w = new SAXParseException[1]; |
|
813 |
||
814 |
createSchemaGenerator().write(outputResolver, new ErrorListener() { |
|
815 |
public void error(SAXParseException exception) { |
|
816 |
e[0] = exception; |
|
817 |
} |
|
818 |
||
819 |
public void fatalError(SAXParseException exception) { |
|
820 |
e[0] = exception; |
|
821 |
} |
|
822 |
||
823 |
public void warning(SAXParseException exception) { |
|
824 |
w[0] = exception; |
|
825 |
} |
|
826 |
||
827 |
public void info(SAXParseException exception) {} |
|
828 |
}); |
|
829 |
||
830 |
if (e[0]!=null) { |
|
831 |
IOException x = new IOException(Messages.FAILED_TO_GENERATE_SCHEMA.format()); |
|
832 |
x.initCause(e[0]); |
|
833 |
throw x; |
|
834 |
} |
|
835 |
if (w[0]!=null) { |
|
836 |
IOException x = new IOException(Messages.ERROR_PROCESSING_SCHEMA.format()); |
|
837 |
x.initCause(w[0]); |
|
838 |
throw x; |
|
839 |
} |
|
840 |
} |
|
841 |
||
842 |
private XmlSchemaGenerator<Type,Class,Field,Method> createSchemaGenerator() { |
|
843 |
RuntimeTypeInfoSet tis; |
|
844 |
try { |
|
845 |
tis = getTypeInfoSet(); |
|
846 |
} catch (IllegalAnnotationsException e) { |
|
847 |
// this shouldn't happen because we've already |
|
848 |
throw new AssertionError(e); |
|
849 |
} |
|
850 |
||
851 |
XmlSchemaGenerator<Type,Class,Field,Method> xsdgen = |
|
852 |
new XmlSchemaGenerator<Type,Class,Field,Method>(tis.getNavigator(),tis); |
|
853 |
||
854 |
// JAX-RPC uses Bridge objects that collide with |
|
855 |
// @XmlRootElement. |
|
856 |
// we will avoid collision here |
|
857 |
Set<QName> rootTagNames = new HashSet<QName>(); |
|
858 |
for (RuntimeElementInfo ei : tis.getAllElements()) { |
|
859 |
rootTagNames.add(ei.getElementName()); |
|
860 |
} |
|
861 |
for (RuntimeClassInfo ci : tis.beans().values()) { |
|
862 |
if(ci.isElement()) |
|
863 |
rootTagNames.add(ci.asElement().getElementName()); |
|
864 |
} |
|
865 |
||
866 |
for (TypeReference tr : bridges.keySet()) { |
|
867 |
if(rootTagNames.contains(tr.tagName)) |
|
868 |
continue; |
|
869 |
||
870 |
if(tr.type==void.class || tr.type==Void.class) { |
|
871 |
xsdgen.add(tr.tagName,false,null); |
|
872 |
} else |
|
873 |
if(tr.type==CompositeStructure.class) { |
|
874 |
// this is a special class we introduced for JAX-WS that we *don't* want in the schema |
|
875 |
} else { |
|
876 |
NonElement<Type,Class> typeInfo = getXmlType(tis,tr); |
|
22427 | 877 |
xsdgen.add(tr.tagName, !tis.getNavigator().isPrimitive(tr.type),typeInfo); |
12009 | 878 |
} |
879 |
} |
|
880 |
return xsdgen; |
|
881 |
} |
|
882 |
||
883 |
public QName getTypeName(TypeReference tr) { |
|
884 |
try { |
|
885 |
NonElement<Type,Class> xt = getXmlType(getTypeInfoSet(),tr); |
|
886 |
if(xt==null) throw new IllegalArgumentException(); |
|
887 |
return xt.getTypeName(); |
|
888 |
} catch (IllegalAnnotationsException e) { |
|
889 |
// impossible given that JAXBRIContext has been successfully built in the first place |
|
890 |
throw new AssertionError(e); |
|
891 |
} |
|
892 |
} |
|
893 |
||
894 |
@Override |
|
895 |
public <T> Binder<T> createBinder(Class<T> domType) { |
|
896 |
if(domType==Node.class) |
|
897 |
return (Binder<T>)createBinder(); |
|
898 |
else |
|
899 |
return super.createBinder(domType); |
|
900 |
} |
|
901 |
||
902 |
@Override |
|
903 |
public Binder<Node> createBinder() { |
|
904 |
return new BinderImpl<Node>(this,new DOMScanner()); |
|
905 |
} |
|
906 |
||
907 |
public QName getElementName(Object o) throws JAXBException { |
|
908 |
JaxBeanInfo bi = getBeanInfo(o,true); |
|
909 |
if(!bi.isElement()) |
|
910 |
return null; |
|
911 |
return new QName(bi.getElementNamespaceURI(o),bi.getElementLocalName(o)); |
|
912 |
} |
|
913 |
||
914 |
public QName getElementName(Class o) throws JAXBException { |
|
915 |
JaxBeanInfo bi = getBeanInfo(o,true); |
|
916 |
if(!bi.isElement()) |
|
917 |
return null; |
|
918 |
return new QName(bi.getElementNamespaceURI(o),bi.getElementLocalName(o)); |
|
919 |
} |
|
920 |
||
921 |
public Bridge createBridge(TypeReference ref) { |
|
922 |
return bridges.get(ref); |
|
923 |
} |
|
924 |
||
925 |
public @NotNull BridgeContext createBridgeContext() { |
|
926 |
return new BridgeContextImpl(this); |
|
927 |
} |
|
928 |
||
929 |
public RawAccessor getElementPropertyAccessor(Class wrapperBean, String nsUri, String localName) throws JAXBException { |
|
930 |
JaxBeanInfo bi = getBeanInfo(wrapperBean,true); |
|
931 |
if(!(bi instanceof ClassBeanInfoImpl)) |
|
932 |
throw new JAXBException(wrapperBean+" is not a bean"); |
|
933 |
||
934 |
for( ClassBeanInfoImpl cb = (ClassBeanInfoImpl) bi; cb!=null; cb=cb.superClazz) { |
|
935 |
for (Property p : cb.properties) { |
|
936 |
final Accessor acc = p.getElementPropertyAccessor(nsUri,localName); |
|
937 |
if(acc!=null) |
|
938 |
return new RawAccessor() { |
|
939 |
// Accessor.set/get are designed for unmarshaller/marshaller, and hence |
|
940 |
// they go through an adapter behind the scene. |
|
941 |
// this isn't desirable for JAX-WS, which essentially uses this method |
|
942 |
// just as a reflection library. So use the "unadapted" version to |
|
943 |
// achieve the desired semantics |
|
944 |
public Object get(Object bean) throws AccessorException { |
|
945 |
return acc.getUnadapted(bean); |
|
946 |
} |
|
947 |
||
948 |
public void set(Object bean, Object value) throws AccessorException { |
|
949 |
acc.setUnadapted(bean,value); |
|
950 |
} |
|
951 |
}; |
|
952 |
} |
|
953 |
} |
|
954 |
throw new JAXBException(new QName(nsUri,localName)+" is not a valid property on "+wrapperBean); |
|
955 |
} |
|
956 |
||
957 |
public List<String> getKnownNamespaceURIs() { |
|
958 |
return Arrays.asList(nameList.namespaceURIs); |
|
959 |
} |
|
960 |
||
961 |
public String getBuildId() { |
|
962 |
Package pkg = getClass().getPackage(); |
|
963 |
if(pkg==null) return null; |
|
964 |
return pkg.getImplementationVersion(); |
|
965 |
} |
|
966 |
||
967 |
@Override |
|
968 |
public String toString() { |
|
969 |
StringBuilder buf = new StringBuilder(Which.which(getClass()) + " Build-Id: " + getBuildId()); |
|
970 |
buf.append("\nClasses known to this context:\n"); |
|
971 |
||
972 |
Set<String> names = new TreeSet<String>(); // sort them so that it's easy to read |
|
973 |
||
974 |
for (Class key : beanInfoMap.keySet()) |
|
975 |
names.add(key.getName()); |
|
976 |
||
977 |
for(String name: names) |
|
978 |
buf.append(" ").append(name).append('\n'); |
|
979 |
||
980 |
return buf.toString(); |
|
981 |
} |
|
982 |
||
983 |
/** |
|
984 |
* Gets the value of the xmime:contentType attribute on the given object, or null |
|
985 |
* if for some reason it couldn't be found, including any error. |
|
986 |
*/ |
|
987 |
public String getXMIMEContentType( Object o ) { |
|
988 |
JaxBeanInfo bi = getBeanInfo(o); |
|
989 |
if(!(bi instanceof ClassBeanInfoImpl)) |
|
990 |
return null; |
|
991 |
||
992 |
ClassBeanInfoImpl cb = (ClassBeanInfoImpl) bi; |
|
993 |
for (Property p : cb.properties) { |
|
994 |
if (p instanceof AttributeProperty) { |
|
995 |
AttributeProperty ap = (AttributeProperty) p; |
|
996 |
if(ap.attName.equals(WellKnownNamespace.XML_MIME_URI,"contentType")) |
|
997 |
try { |
|
998 |
return (String)ap.xacc.print(o); |
|
999 |
} catch (AccessorException e) { |
|
1000 |
return null; |
|
1001 |
} catch (SAXException e) { |
|
1002 |
return null; |
|
1003 |
} catch (ClassCastException e) { |
|
1004 |
return null; |
|
1005 |
} |
|
1006 |
} |
|
1007 |
} |
|
1008 |
return null; |
|
1009 |
} |
|
1010 |
||
1011 |
/** |
|
1012 |
* Creates a {@link JAXBContextImpl} that includes the specified additional classes. |
|
1013 |
*/ |
|
1014 |
public JAXBContextImpl createAugmented(Class<?> clazz) throws JAXBException { |
|
1015 |
Class[] newList = new Class[classes.length+1]; |
|
1016 |
System.arraycopy(classes,0,newList,0,classes.length); |
|
1017 |
newList[classes.length] = clazz; |
|
1018 |
||
1019 |
JAXBContextBuilder builder = new JAXBContextBuilder(this); |
|
1020 |
builder.setClasses(newList); |
|
1021 |
return builder.build(); |
|
1022 |
} |
|
1023 |
||
1024 |
private static final Comparator<QName> QNAME_COMPARATOR = new Comparator<QName>() { |
|
1025 |
public int compare(QName lhs, QName rhs) { |
|
1026 |
int r = lhs.getLocalPart().compareTo(rhs.getLocalPart()); |
|
1027 |
if(r!=0) return r; |
|
1028 |
||
1029 |
return lhs.getNamespaceURI().compareTo(rhs.getNamespaceURI()); |
|
1030 |
} |
|
1031 |
}; |
|
1032 |
||
1033 |
public static class JAXBContextBuilder { |
|
1034 |
||
1035 |
private boolean retainPropertyInfo = false; |
|
1036 |
private boolean supressAccessorWarnings = false; |
|
1037 |
private String defaultNsUri = ""; |
|
1038 |
private @NotNull RuntimeAnnotationReader annotationReader = new RuntimeInlineAnnotationReader(); |
|
1039 |
private @NotNull Map<Class,Class> subclassReplacements = Collections.emptyMap(); |
|
1040 |
private boolean c14nSupport = false; |
|
1041 |
private Class[] classes; |
|
1042 |
private Collection<TypeReference> typeRefs; |
|
1043 |
private boolean xmlAccessorFactorySupport = false; |
|
1044 |
private boolean allNillable; |
|
1045 |
private boolean improvedXsiTypeHandling = true; |
|
16791 | 1046 |
private boolean disableSecurityProcessing = true; |
12009 | 1047 |
|
1048 |
public JAXBContextBuilder() {}; |
|
1049 |
||
1050 |
public JAXBContextBuilder(JAXBContextImpl baseImpl) { |
|
1051 |
this.supressAccessorWarnings = baseImpl.supressAccessorWarnings; |
|
1052 |
this.retainPropertyInfo = baseImpl.retainPropertyInfo; |
|
1053 |
this.defaultNsUri = baseImpl.defaultNsUri; |
|
1054 |
this.annotationReader = baseImpl.annotationReader; |
|
1055 |
this.subclassReplacements = baseImpl.subclassReplacements; |
|
1056 |
this.c14nSupport = baseImpl.c14nSupport; |
|
1057 |
this.classes = baseImpl.classes; |
|
1058 |
this.typeRefs = baseImpl.bridges.keySet(); |
|
1059 |
this.xmlAccessorFactorySupport = baseImpl.xmlAccessorFactorySupport; |
|
1060 |
this.allNillable = baseImpl.allNillable; |
|
16791 | 1061 |
this.disableSecurityProcessing = baseImpl.disableSecurityProcessing; |
12009 | 1062 |
} |
1063 |
||
1064 |
public JAXBContextBuilder setRetainPropertyInfo(boolean val) { |
|
1065 |
this.retainPropertyInfo = val; |
|
1066 |
return this; |
|
1067 |
} |
|
1068 |
||
1069 |
public JAXBContextBuilder setSupressAccessorWarnings(boolean val) { |
|
1070 |
this.supressAccessorWarnings = val; |
|
1071 |
return this; |
|
1072 |
} |
|
1073 |
||
1074 |
public JAXBContextBuilder setC14NSupport(boolean val) { |
|
1075 |
this.c14nSupport = val; |
|
1076 |
return this; |
|
1077 |
} |
|
1078 |
||
1079 |
public JAXBContextBuilder setXmlAccessorFactorySupport(boolean val) { |
|
1080 |
this.xmlAccessorFactorySupport = val; |
|
1081 |
return this; |
|
1082 |
} |
|
1083 |
||
1084 |
public JAXBContextBuilder setDefaultNsUri(String val) { |
|
1085 |
this.defaultNsUri = val; |
|
1086 |
return this; |
|
1087 |
} |
|
1088 |
||
1089 |
public JAXBContextBuilder setAllNillable(boolean val) { |
|
1090 |
this.allNillable = val; |
|
1091 |
return this; |
|
1092 |
} |
|
1093 |
||
1094 |
public JAXBContextBuilder setClasses(Class[] val) { |
|
1095 |
this.classes = val; |
|
1096 |
return this; |
|
1097 |
} |
|
1098 |
||
1099 |
public JAXBContextBuilder setAnnotationReader(RuntimeAnnotationReader val) { |
|
1100 |
this.annotationReader = val; |
|
1101 |
return this; |
|
1102 |
} |
|
1103 |
||
1104 |
public JAXBContextBuilder setSubclassReplacements(Map<Class,Class> val) { |
|
1105 |
this.subclassReplacements = val; |
|
1106 |
return this; |
|
1107 |
} |
|
1108 |
||
1109 |
public JAXBContextBuilder setTypeRefs(Collection<TypeReference> val) { |
|
1110 |
this.typeRefs = val; |
|
1111 |
return this; |
|
1112 |
} |
|
1113 |
||
1114 |
public JAXBContextBuilder setImprovedXsiTypeHandling(boolean val) { |
|
1115 |
this.improvedXsiTypeHandling = val; |
|
1116 |
return this; |
|
1117 |
} |
|
1118 |
||
16791 | 1119 |
public JAXBContextBuilder setDisableSecurityProcessing(boolean val) { |
1120 |
this.disableSecurityProcessing = val; |
|
1121 |
return this; |
|
1122 |
} |
|
1123 |
||
12009 | 1124 |
public JAXBContextImpl build() throws JAXBException { |
1125 |
||
1126 |
// fool-proof |
|
1127 |
if (this.defaultNsUri == null) { |
|
1128 |
this.defaultNsUri = ""; |
|
1129 |
} |
|
1130 |
||
1131 |
if (this.subclassReplacements == null) { |
|
1132 |
this.subclassReplacements = Collections.emptyMap(); |
|
1133 |
} |
|
1134 |
||
1135 |
if (this.annotationReader == null) { |
|
1136 |
this.annotationReader = new RuntimeInlineAnnotationReader(); |
|
1137 |
} |
|
1138 |
||
1139 |
if (this.typeRefs == null) { |
|
1140 |
this.typeRefs = Collections.<TypeReference>emptyList(); |
|
1141 |
} |
|
1142 |
||
1143 |
return new JAXBContextImpl(this); |
|
1144 |
} |
|
1145 |
||
1146 |
} |
|
1147 |
||
1148 |
} |