Tue, 06 Mar 2012 16:09:35 -0800
7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom
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.util.Collections;
29 import java.util.LinkedHashSet;
30 import java.util.Set;
32 import javax.xml.bind.JAXBElement;
33 import javax.xml.bind.annotation.XmlAnyElement;
34 import javax.xml.bind.annotation.XmlElementRef;
35 import javax.xml.bind.annotation.XmlElementRefs;
36 import javax.xml.bind.annotation.XmlMixed;
37 import javax.xml.bind.annotation.XmlSchema;
38 import javax.xml.bind.annotation.XmlNsForm;
39 import javax.xml.namespace.QName;
41 import com.sun.xml.internal.bind.v2.model.annotation.AnnotationReader;
42 import com.sun.xml.internal.bind.v2.model.core.ClassInfo;
43 import com.sun.xml.internal.bind.v2.model.core.Element;
44 import com.sun.xml.internal.bind.v2.model.core.ElementInfo;
45 import com.sun.xml.internal.bind.v2.model.core.NonElement;
46 import com.sun.xml.internal.bind.v2.model.core.PropertyKind;
47 import com.sun.xml.internal.bind.v2.model.core.ReferencePropertyInfo;
48 import com.sun.xml.internal.bind.v2.model.core.WildcardMode;
49 import com.sun.xml.internal.bind.v2.model.nav.Navigator;
50 import com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationException;
51 import java.util.Iterator;
53 /**
54 * Implementation of {@link ReferencePropertyInfo}.
55 *
56 * @author Kohsuke Kawaguchi
57 */
58 class ReferencePropertyInfoImpl<T,C,F,M>
59 extends ERPropertyInfoImpl<T,C,F,M>
60 implements ReferencePropertyInfo<T,C>, DummyPropertyInfo<T, C, F, M>
61 {
62 /**
63 * Lazily computed.
64 * @see #getElements()
65 */
66 private Set<Element<T,C>> types;
67 private Set<PropertyInfoImpl<T,C,F,M>> subTypes = new LinkedHashSet<PropertyInfoImpl<T,C,F,M>>();
69 private final boolean isMixed;
71 private final WildcardMode wildcard;
72 private final C domHandler;
73 /**
74 * Lazily computed.
75 * @see #isRequired()
76 */
77 private Boolean isRequired;
79 public ReferencePropertyInfoImpl(
80 ClassInfoImpl<T,C,F,M> classInfo,
81 PropertySeed<T,C,F,M> seed) {
83 super(classInfo, seed);
85 isMixed = seed.readAnnotation(XmlMixed.class) != null;
87 XmlAnyElement xae = seed.readAnnotation(XmlAnyElement.class);
88 if(xae==null) {
89 wildcard = null;
90 domHandler = null;
91 } else {
92 wildcard = xae.lax()?WildcardMode.LAX:WildcardMode.SKIP;
93 domHandler = nav().asDecl(reader().getClassValue(xae,"value"));
94 }
95 }
97 public Set<? extends Element<T,C>> ref() {
98 return getElements();
99 }
101 public PropertyKind kind() {
102 return PropertyKind.REFERENCE;
103 }
105 public Set<? extends Element<T,C>> getElements() {
106 if(types==null)
107 calcTypes(false);
108 assert types!=null;
109 return types;
110 }
112 /**
113 * Compute {@link #types}.
114 *
115 * @param last
116 * if true, every {@link XmlElementRef} must yield at least one type.
117 */
118 private void calcTypes(boolean last) {
119 XmlElementRef[] ann;
120 types = new LinkedHashSet<Element<T,C>>();
121 XmlElementRefs refs = seed.readAnnotation(XmlElementRefs.class);
122 XmlElementRef ref = seed.readAnnotation(XmlElementRef.class);
124 if(refs!=null && ref!=null) {
125 parent.builder.reportError(new IllegalAnnotationException(
126 Messages.MUTUALLY_EXCLUSIVE_ANNOTATIONS.format(
127 nav().getClassName(parent.getClazz())+'#'+seed.getName(),
128 ref.annotationType().getName(), refs.annotationType().getName()),
129 ref, refs ));
130 }
132 if(refs!=null)
133 ann = refs.value();
134 else {
135 if(ref!=null)
136 ann = new XmlElementRef[]{ref};
137 else
138 ann = null;
139 }
141 isRequired = !isCollection(); // this is by default, to remain compatible with 2.1
143 if(ann!=null) {
144 Navigator<T,C,F,M> nav = nav();
145 AnnotationReader<T,C,F,M> reader = reader();
147 final T defaultType = nav.ref(XmlElementRef.DEFAULT.class);
148 final C je = nav.asDecl(JAXBElement.class);
150 for( XmlElementRef r : ann ) {
151 boolean yield;
152 T type = reader.getClassValue(r,"type");
153 if(nav().isSameType(type, defaultType))
154 type = nav.erasure(getIndividualType());
155 if(nav.getBaseClass(type,je)!=null)
156 yield = addGenericElement(r);
157 else
158 yield = addAllSubtypes(type);
160 // essentially "isRequired &= isRequired(r)" except that we'd like to skip evaluating isRequird(r)
161 // if the value is already false.
162 if(isRequired && !isRequired(r))
163 isRequired = false;
165 if(last && !yield) {
166 // a reference didn't produce any type.
167 // diagnose the problem
168 if(nav().isSameType(type, nav.ref(JAXBElement.class))) {
169 // no XmlElementDecl
170 parent.builder.reportError(new IllegalAnnotationException(
171 Messages.NO_XML_ELEMENT_DECL.format(
172 getEffectiveNamespaceFor(r), r.name()),
173 this
174 ));
175 } else {
176 parent.builder.reportError(new IllegalAnnotationException(
177 Messages.INVALID_XML_ELEMENT_REF.format(type),this));
178 }
180 // reporting one error would do.
181 // often the element ref field is using @XmlElementRefs
182 // to point to multiple JAXBElements.
183 // reporting one error for each @XmlElemetnRef is thus often redundant.
184 return;
185 }
186 }
187 }
189 Iterator<PropertyInfoImpl<T,C,F,M>> i = subTypes.iterator();
190 while (i.hasNext()) {
192 ReferencePropertyInfoImpl<T,C,F,M> info = (ReferencePropertyInfoImpl<T, C, F, M>) i.next();
193 PropertySeed sd = info.seed;
194 refs = sd.readAnnotation(XmlElementRefs.class);
195 ref = sd.readAnnotation(XmlElementRef.class);
197 if (refs != null && ref != null) {
198 parent.builder.reportError(new IllegalAnnotationException(
199 Messages.MUTUALLY_EXCLUSIVE_ANNOTATIONS.format(
200 nav().getClassName(parent.getClazz())+'#'+seed.getName(),
201 ref.annotationType().getName(), refs.annotationType().getName()),
202 ref, refs ));
203 }
205 if (refs != null) {
206 ann = refs.value();
207 } else {
208 if (ref != null) {
209 ann = new XmlElementRef[]{ref};
210 } else {
211 ann = null;
212 }
213 }
215 if (ann != null) {
216 Navigator<T,C,F,M> nav = nav();
217 AnnotationReader<T,C,F,M> reader = reader();
219 final T defaultType = nav.ref(XmlElementRef.DEFAULT.class);
220 final C je = nav.asDecl(JAXBElement.class);
222 for( XmlElementRef r : ann ) {
223 boolean yield;
224 T type = reader.getClassValue(r,"type");
225 if (nav().isSameType(type, defaultType)) {
226 type = nav.erasure(getIndividualType());
227 }
228 if (nav.getBaseClass(type,je) != null) {
229 yield = addGenericElement(r, info);
231 } else {
232 yield = addAllSubtypes(type);
233 }
235 if(last && !yield) {
236 // a reference didn't produce any type.
237 // diagnose the problem
238 if(nav().isSameType(type, nav.ref(JAXBElement.class))) {
239 // no XmlElementDecl
240 parent.builder.reportError(new IllegalAnnotationException(
241 Messages.NO_XML_ELEMENT_DECL.format(
242 getEffectiveNamespaceFor(r), r.name()),
243 this
244 ));
245 } else {
246 parent.builder.reportError(new IllegalAnnotationException(
247 Messages.INVALID_XML_ELEMENT_REF.format(),this));
248 }
250 // reporting one error would do.
251 // often the element ref field is using @XmlElementRefs
252 // to point to multiple JAXBElements.
253 // reporting one error for each @XmlElemetnRef is thus often redundant.
254 return;
255 }
256 }
257 }
258 }
260 types = Collections.unmodifiableSet(types);
261 }
263 public boolean isRequired() {
264 if(isRequired==null)
265 calcTypes(false);
266 return isRequired;
267 }
269 /**
270 * If we find out that we are working with 2.1 API, remember the fact so that
271 * we don't waste time generating exceptions every time we call {@link #isRequired(XmlElementRef)}.
272 */
273 private static boolean is2_2 = true;
275 /**
276 * Reads the value of {@code XmlElementRef.required()}.
277 *
278 * If we are working as 2.1 RI, this defaults to true.
279 */
280 private boolean isRequired(XmlElementRef ref) {
281 if(!is2_2) return true;
283 try {
284 return ref.required();
285 } catch(LinkageError e) {
286 is2_2 = false;
287 return true; // the value defaults to true
288 }
289 }
291 /**
292 * @return
293 * true if the reference yields at least one type
294 */
295 private boolean addGenericElement(XmlElementRef r) {
296 String nsUri = getEffectiveNamespaceFor(r);
297 // TODO: check spec. defaulting of localName.
298 return addGenericElement(parent.owner.getElementInfo(parent.getClazz(),new QName(nsUri,r.name())));
299 }
301 private boolean addGenericElement(XmlElementRef r, ReferencePropertyInfoImpl<T,C,F,M> info) {
302 String nsUri = info.getEffectiveNamespaceFor(r);
303 ElementInfo ei = parent.owner.getElementInfo(info.parent.getClazz(), new QName(nsUri, r.name()));
304 types.add(ei);
305 return true;
306 }
308 private String getEffectiveNamespaceFor(XmlElementRef r) {
309 String nsUri = r.namespace();
311 XmlSchema xs = reader().getPackageAnnotation( XmlSchema.class, parent.getClazz(), this );
312 if(xs!=null && xs.attributeFormDefault()== XmlNsForm.QUALIFIED) {
313 // JAX-RPC doesn't want the default namespace URI swapping to take effect to
314 // local "unqualified" elements. UGLY.
315 if(nsUri.length()==0)
316 nsUri = parent.builder.defaultNsUri;
317 }
319 return nsUri;
320 }
322 private boolean addGenericElement(ElementInfo<T,C> ei) {
323 if(ei==null)
324 return false;
325 types.add(ei);
326 for( ElementInfo<T,C> subst : ei.getSubstitutionMembers() )
327 addGenericElement(subst);
328 return true;
329 }
331 private boolean addAllSubtypes(T type) {
332 Navigator<T,C,F,M> nav = nav();
334 // this allows the explicitly referenced type to be sucked in to the model
335 NonElement<T,C> t = parent.builder.getClassInfo(nav.asDecl(type),this);
336 if(!(t instanceof ClassInfo))
337 // this is leaf.
338 return false;
340 boolean result = false;
342 ClassInfo<T,C> c = (ClassInfo<T,C>) t;
343 if(c.isElement()) {
344 types.add(c.asElement());
345 result = true;
346 }
348 // look for other possible types
349 for( ClassInfo<T,C> ci : parent.owner.beans().values() ) {
350 if(ci.isElement() && nav.isSubClassOf(ci.getType(),type)) {
351 types.add(ci.asElement());
352 result = true;
353 }
354 }
356 // don't allow local elements to substitute.
357 for( ElementInfo<T,C> ei : parent.owner.getElementMappings(null).values()) {
358 if(nav.isSubClassOf(ei.getType(),type)) {
359 types.add(ei);
360 result = true;
361 }
362 }
364 return result;
365 }
368 @Override
369 protected void link() {
370 super.link();
372 // until we get the whole thing into TypeInfoSet,
373 // we never really know what are all the possible types that can be assigned on this field.
374 // so recompute this value when we have all the information.
375 calcTypes(true);
377 }
379 public final void addType(PropertyInfoImpl<T,C,F,M> info) {
380 subTypes.add(info);
381 }
383 public final boolean isMixed() {
384 return isMixed;
385 }
387 public final WildcardMode getWildcard() {
388 return wildcard;
389 }
391 public final C getDOMHandler() {
392 return domHandler;
393 }
394 }