Fri, 24 Oct 2014 15:02:28 +0200
8054367: More references for endpoints
Summary: fix also reviewed by Iaroslav.Savytskyi@oracle.com, Alexander.Fomin@oracle.com
Reviewed-by: mullan, skoivu
1 /*
2 * Copyright (c) 1997, 2011, 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 */
26 package com.sun.xml.internal.bind.v2.model.impl;
28 import java.lang.annotation.Annotation;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.List;
33 import javax.activation.MimeType;
34 import javax.xml.bind.JAXBElement;
35 import javax.xml.bind.annotation.XmlAttachmentRef;
36 import javax.xml.bind.annotation.XmlElementDecl;
37 import javax.xml.bind.annotation.XmlID;
38 import javax.xml.bind.annotation.XmlIDREF;
39 import javax.xml.bind.annotation.XmlInlineBinaryData;
40 import javax.xml.bind.annotation.XmlSchema;
41 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
42 import javax.xml.namespace.QName;
44 import com.sun.istack.internal.FinalArrayList;
45 import com.sun.xml.internal.bind.v2.TODO;
46 import com.sun.xml.internal.bind.v2.model.annotation.AnnotationSource;
47 import com.sun.xml.internal.bind.v2.model.annotation.Locatable;
48 import com.sun.xml.internal.bind.v2.model.core.Adapter;
49 import com.sun.xml.internal.bind.v2.model.core.ClassInfo;
50 import com.sun.xml.internal.bind.v2.model.core.ElementInfo;
51 import com.sun.xml.internal.bind.v2.model.core.ElementPropertyInfo;
52 import com.sun.xml.internal.bind.v2.model.core.ID;
53 import com.sun.xml.internal.bind.v2.model.core.NonElement;
54 import com.sun.xml.internal.bind.v2.model.core.PropertyInfo;
55 import com.sun.xml.internal.bind.v2.model.core.PropertyKind;
56 import com.sun.xml.internal.bind.v2.model.core.TypeInfo;
57 import com.sun.xml.internal.bind.v2.model.core.TypeRef;
58 import com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationException;
59 import com.sun.xml.internal.bind.v2.runtime.Location;
60 import com.sun.xml.internal.bind.v2.runtime.SwaRefAdapter;
62 /**
63 * {@link ElementInfo} implementation.
64 *
65 * @author Kohsuke Kawaguchi
66 */
67 class ElementInfoImpl<T,C,F,M> extends TypeInfoImpl<T,C,F,M> implements ElementInfo<T,C> {
69 private final QName tagName;
71 private final NonElement<T,C> contentType;
73 private final T tOfJAXBElementT;
75 private final T elementType;
77 private final ClassInfo<T,C> scope;
79 /**
80 * Annotation that controls the binding.
81 */
82 private final XmlElementDecl anno;
84 /**
85 * If this element can substitute another element, the element name.
86 * @see #link()
87 */
88 private ElementInfoImpl<T,C,F,M> substitutionHead;
90 /**
91 * Lazily constructed list of {@link ElementInfo}s that can substitute this element.
92 * This could be null.
93 * @see #link()
94 */
95 private FinalArrayList<ElementInfoImpl<T,C,F,M>> substitutionMembers;
97 /**
98 * The factory method from which this mapping was created.
99 */
100 private final M method;
102 /**
103 * If the content type is adapter, return that adapter.
104 */
105 private final Adapter<T,C> adapter;
107 private final boolean isCollection;
109 private final ID id;
111 private final PropertyImpl property;
112 private final MimeType expectedMimeType;
113 private final boolean inlineBinary;
114 private final QName schemaType;
116 /**
117 * Singleton instance of {@link ElementPropertyInfo} for this element.
118 */
119 protected class PropertyImpl implements
120 ElementPropertyInfo<T,C>,
121 TypeRef<T,C>,
122 AnnotationSource {
123 //
124 // TypeRef impl
125 //
126 public NonElement<T,C> getTarget() {
127 return contentType;
128 }
129 public QName getTagName() {
130 return tagName;
131 }
133 public List<? extends TypeRef<T,C>> getTypes() {
134 return Collections.singletonList(this);
135 }
137 public List<? extends NonElement<T,C>> ref() {
138 return Collections.singletonList(contentType);
139 }
141 public QName getXmlName() {
142 return tagName;
143 }
145 public boolean isCollectionRequired() {
146 return false;
147 }
149 public boolean isCollectionNillable() {
150 return true;
151 }
153 public boolean isNillable() {
154 return true;
155 }
157 public String getDefaultValue() {
158 String v = anno.defaultValue();
159 if(v.equals("\u0000"))
160 return null;
161 else
162 return v;
163 }
165 public ElementInfoImpl<T,C,F,M> parent() {
166 return ElementInfoImpl.this;
167 }
169 public String getName() {
170 return "value";
171 }
173 public String displayName() {
174 return "JAXBElement#value";
175 }
177 public boolean isCollection() {
178 return isCollection;
179 }
181 /**
182 * For {@link ElementInfo}s, a collection always means a list of values.
183 */
184 public boolean isValueList() {
185 return isCollection;
186 }
188 public boolean isRequired() {
189 return true;
190 }
192 public PropertyKind kind() {
193 return PropertyKind.ELEMENT;
194 }
196 public Adapter<T,C> getAdapter() {
197 return adapter;
198 }
200 public ID id() {
201 return id;
202 }
204 public MimeType getExpectedMimeType() {
205 return expectedMimeType;
206 }
208 public QName getSchemaType() {
209 return schemaType;
210 }
212 public boolean inlineBinaryData() {
213 return inlineBinary;
214 }
216 public PropertyInfo<T,C> getSource() {
217 return this;
218 }
220 //
221 //
222 // AnnotationSource impl
223 //
224 //
225 public <A extends Annotation> A readAnnotation(Class<A> annotationType) {
226 return reader().getMethodAnnotation(annotationType,method,ElementInfoImpl.this);
227 }
229 public boolean hasAnnotation(Class<? extends Annotation> annotationType) {
230 return reader().hasMethodAnnotation(annotationType,method);
231 }
232 }
234 /**
235 * @param m
236 * The factory method on ObjectFactory that comes with {@link XmlElementDecl}.
237 */
238 public ElementInfoImpl(ModelBuilder<T,C,F,M> builder,
239 RegistryInfoImpl<T,C,F,M> registry, M m ) throws IllegalAnnotationException {
240 super(builder,registry);
242 this.method = m;
243 anno = reader().getMethodAnnotation( XmlElementDecl.class, m, this );
244 assert anno!=null; // the caller should check this
245 assert anno instanceof Locatable;
247 elementType = nav().getReturnType(m);
248 T baseClass = nav().getBaseClass(elementType,nav().asDecl(JAXBElement.class));
249 if(baseClass==null)
250 throw new IllegalAnnotationException(
251 Messages.XML_ELEMENT_MAPPING_ON_NON_IXMLELEMENT_METHOD.format(nav().getMethodName(m)),
252 anno );
254 tagName = parseElementName(anno);
255 T[] methodParams = nav().getMethodParameters(m);
257 // adapter
258 Adapter<T,C> a = null;
259 if(methodParams.length>0) {
260 XmlJavaTypeAdapter adapter = reader().getMethodAnnotation(XmlJavaTypeAdapter.class,m,this);
261 if(adapter!=null)
262 a = new Adapter<T,C>(adapter,reader(),nav());
263 else {
264 XmlAttachmentRef xsa = reader().getMethodAnnotation(XmlAttachmentRef.class,m,this);
265 if(xsa!=null) {
266 TODO.prototype("in Annotation Processing swaRefAdapter isn't avaialble, so this returns null");
267 a = new Adapter<T,C>(owner.nav.asDecl(SwaRefAdapter.class),owner.nav);
268 }
269 }
270 }
271 this.adapter = a;
273 // T of JAXBElement<T>
274 tOfJAXBElementT =
275 methodParams.length>0 ? methodParams[0] // this is more reliable, as it works even for ObjectFactory that sometimes have to return public types
276 : nav().getTypeArgument(baseClass,0); // fall back to infer from the return type if no parameter.
278 if(adapter==null) {
279 T list = nav().getBaseClass(tOfJAXBElementT,nav().asDecl(List.class));
280 if(list==null) {
281 isCollection = false;
282 contentType = builder.getTypeInfo(tOfJAXBElementT,this); // suck this type into the current set.
283 } else {
284 isCollection = true;
285 contentType = builder.getTypeInfo(nav().getTypeArgument(list,0),this);
286 }
287 } else {
288 // but if adapted, use the adapted type
289 contentType = builder.getTypeInfo(this.adapter.defaultType,this);
290 isCollection = false;
291 }
293 // scope
294 T s = reader().getClassValue(anno,"scope");
295 if(nav().isSameType(s, nav().ref(XmlElementDecl.GLOBAL.class)))
296 scope = null;
297 else {
298 // TODO: what happens if there's an error?
299 NonElement<T,C> scp = builder.getClassInfo(nav().asDecl(s),this);
300 if(!(scp instanceof ClassInfo)) {
301 throw new IllegalAnnotationException(
302 Messages.SCOPE_IS_NOT_COMPLEXTYPE.format(nav().getTypeName(s)),
303 anno );
304 }
305 scope = (ClassInfo<T,C>)scp;
306 }
308 id = calcId();
310 property = createPropertyImpl();
312 this.expectedMimeType = Util.calcExpectedMediaType(property,builder);
313 this.inlineBinary = reader().hasMethodAnnotation(XmlInlineBinaryData.class,method);
314 this.schemaType = Util.calcSchemaType(reader(),property,registry.registryClass,
315 getContentInMemoryType(),this);
316 }
318 final QName parseElementName(XmlElementDecl e) {
319 String local = e.name();
320 String nsUri = e.namespace();
321 if(nsUri.equals("##default")) {
322 // if defaulted ...
323 XmlSchema xs = reader().getPackageAnnotation(XmlSchema.class,
324 nav().getDeclaringClassForMethod(method),this);
325 if(xs!=null)
326 nsUri = xs.namespace();
327 else {
328 nsUri = builder.defaultNsUri;
329 }
330 }
332 return new QName(nsUri.intern(),local.intern());
333 }
335 protected PropertyImpl createPropertyImpl() {
336 return new PropertyImpl();
337 }
339 public ElementPropertyInfo<T,C> getProperty() {
340 return property;
341 }
343 public NonElement<T,C> getContentType() {
344 return contentType;
345 }
347 public T getContentInMemoryType() {
348 if(adapter==null) {
349 return tOfJAXBElementT;
350 } else {
351 return adapter.customType;
352 }
353 }
355 public QName getElementName() {
356 return tagName;
357 }
359 public T getType() {
360 return elementType;
361 }
363 /**
364 * Leaf-type cannot be referenced from IDREF.
365 *
366 * @deprecated
367 * why are you calling a method whose return value is always known?
368 */
369 public final boolean canBeReferencedByIDREF() {
370 return false;
371 }
373 private ID calcId() {
374 // TODO: share code with PropertyInfoImpl
375 if(reader().hasMethodAnnotation(XmlID.class,method)) {
376 return ID.ID;
377 } else
378 if(reader().hasMethodAnnotation(XmlIDREF.class,method)) {
379 return ID.IDREF;
380 } else {
381 return ID.NONE;
382 }
383 }
385 public ClassInfo<T, C> getScope() {
386 return scope;
387 }
389 public ElementInfo<T,C> getSubstitutionHead() {
390 return substitutionHead;
391 }
393 public Collection<? extends ElementInfoImpl<T,C,F,M>> getSubstitutionMembers() {
394 if(substitutionMembers==null)
395 return Collections.emptyList();
396 else
397 return substitutionMembers;
398 }
400 /**
401 * Called after all the {@link TypeInfo}s are collected into the {@link #owner}.
402 */
403 /*package*/ void link() {
404 // substitution head
405 if(anno.substitutionHeadName().length()!=0) {
406 QName name = new QName(
407 anno.substitutionHeadNamespace(), anno.substitutionHeadName() );
408 substitutionHead = owner.getElementInfo(null,name);
409 if(substitutionHead==null) {
410 builder.reportError(
411 new IllegalAnnotationException(Messages.NON_EXISTENT_ELEMENT_MAPPING.format(
412 name.getNamespaceURI(),name.getLocalPart()), anno));
413 // recover by ignoring this substitution declaration
414 } else
415 substitutionHead.addSubstitutionMember(this);
416 } else
417 substitutionHead = null;
418 super.link();
419 }
421 private void addSubstitutionMember(ElementInfoImpl<T,C,F,M> child) {
422 if(substitutionMembers==null)
423 substitutionMembers = new FinalArrayList<ElementInfoImpl<T,C,F,M>>();
424 substitutionMembers.add(child);
425 }
427 public Location getLocation() {
428 return nav().getMethodLocation(method);
429 }
430 }