src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/xmlschema/DefaultClassBinder.java

changeset 0
373ffda63c9a
equal deleted inserted replaced
-1:000000000000 0:373ffda63c9a
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 */
25
26 package com.sun.tools.internal.xjc.reader.xmlschema;
27 import static com.sun.tools.internal.xjc.reader.xmlschema.BGMBuilder.getName;
28
29 import java.util.Set;
30
31 import javax.xml.namespace.QName;
32
33 import com.sun.codemodel.internal.JJavaName;
34 import com.sun.codemodel.internal.JPackage;
35 import com.sun.istack.internal.NotNull;
36 import com.sun.istack.internal.Nullable;
37 import com.sun.tools.internal.xjc.ErrorReceiver;
38 import com.sun.tools.internal.xjc.model.CClassInfo;
39 import com.sun.tools.internal.xjc.model.CClassInfoParent;
40 import com.sun.tools.internal.xjc.model.CClassRef;
41 import com.sun.tools.internal.xjc.model.CCustomizations;
42 import com.sun.tools.internal.xjc.model.CElement;
43 import com.sun.tools.internal.xjc.model.CElementInfo;
44 import com.sun.tools.internal.xjc.model.Model;
45 import com.sun.tools.internal.xjc.reader.Ring;
46 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIClass;
47 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIGlobalBinding;
48 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BISchemaBinding;
49 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BindInfo;
50 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIXSubstitutable;
51 import com.sun.tools.internal.xjc.reader.xmlschema.ct.ComplexTypeFieldBuilder;
52 import com.sun.tools.internal.xjc.reader.xmlschema.ct.ComplexTypeBindingMode;
53 import com.sun.xml.internal.xsom.XSAnnotation;
54 import com.sun.xml.internal.xsom.XSAttGroupDecl;
55 import com.sun.xml.internal.xsom.XSAttributeDecl;
56 import com.sun.xml.internal.xsom.XSAttributeUse;
57 import com.sun.xml.internal.xsom.XSComplexType;
58 import com.sun.xml.internal.xsom.XSComponent;
59 import com.sun.xml.internal.xsom.XSContentType;
60 import com.sun.xml.internal.xsom.XSDeclaration;
61 import com.sun.xml.internal.xsom.XSElementDecl;
62 import com.sun.xml.internal.xsom.XSFacet;
63 import com.sun.xml.internal.xsom.XSIdentityConstraint;
64 import com.sun.xml.internal.xsom.XSModelGroup;
65 import com.sun.xml.internal.xsom.XSModelGroupDecl;
66 import com.sun.xml.internal.xsom.XSNotation;
67 import com.sun.xml.internal.xsom.XSParticle;
68 import com.sun.xml.internal.xsom.XSSchema;
69 import com.sun.xml.internal.xsom.XSSchemaSet;
70 import com.sun.xml.internal.xsom.XSSimpleType;
71 import com.sun.xml.internal.xsom.XSType;
72 import com.sun.xml.internal.xsom.XSWildcard;
73 import com.sun.xml.internal.xsom.XSXPath;
74
75 import org.xml.sax.Locator;
76
77 /**
78 * Default classBinder implementation. Honors <jaxb:class> customizations
79 * and default bindings.
80 */
81 final class DefaultClassBinder implements ClassBinder
82 {
83 private final SimpleTypeBuilder stb = Ring.get(SimpleTypeBuilder.class);
84 private final Model model = Ring.get(Model.class);
85
86 protected final BGMBuilder builder = Ring.get(BGMBuilder.class);
87 protected final ClassSelector selector = Ring.get(ClassSelector.class);
88
89 protected final XSSchemaSet schemas = Ring.get(XSSchemaSet.class);
90
91 public CElement attGroupDecl(XSAttGroupDecl decl) {
92 return allow(decl,decl.getName());
93 }
94
95 public CElement attributeDecl(XSAttributeDecl decl) {
96 return allow(decl,decl.getName());
97 }
98
99 public CElement modelGroup(XSModelGroup mgroup) {
100 return never();
101 }
102
103 public CElement modelGroupDecl(XSModelGroupDecl decl) {
104 return never();
105 }
106
107
108 public CElement complexType(XSComplexType type) {
109 CElement ci = allow(type,type.getName());
110 if(ci!=null) return ci;
111
112 // no customization is given -- do as the default binding.
113
114 BindInfo bi = builder.getBindInfo(type);
115
116 if(type.isGlobal()) {
117 QName tagName = null;
118 String className = deriveName(type);
119 Locator loc = type.getLocator();
120
121 if(getGlobalBinding().isSimpleMode()) {
122 // in the simple mode, we may optimize it away
123 XSElementDecl referer = getSoleElementReferer(type);
124 if(referer!=null && isCollapsable(referer)) {
125 // if a global element contains
126 // a collpsable complex type, we bind this element to a named one
127 // and collapses element and complex type.
128 tagName = getName(referer);
129 className = deriveName(referer);
130 loc = referer.getLocator();
131 }
132 }
133
134 // by default, global ones get their own classes.
135
136 JPackage pkg = selector.getPackage(type.getTargetNamespace());
137
138 return new CClassInfo(model,pkg,className, loc,getTypeName(type),tagName,type,bi.toCustomizationList());
139 } else {
140 XSElementDecl element = type.getScope();
141
142 if( element.isGlobal() && isCollapsable(element)) {
143 if(builder.getBindInfo(element).get(BIClass.class)!=null)
144 // the parent element was bound to a class. Don't bind this again to
145 // cause unnecessary wrapping
146 return null;
147
148 // generate one class from element and complex type together.
149 // this needs to be done before selector.isBound to avoid infinite recursion.
150
151 // but avoid doing so when the element is mapped to a class,
152 // which creates unnecessary classes
153 return new CClassInfo( model, selector.getClassScope(),
154 deriveName(element), element.getLocator(), null,
155 getName(element), element, bi.toCustomizationList() );
156 }
157
158
159 CElement parentType = selector.isBound(element,type);
160
161 String className;
162 CClassInfoParent scope;
163
164
165 if( parentType!=null
166 && parentType instanceof CElementInfo
167 && ((CElementInfo)parentType).hasClass() ) {
168 // special case where we put a nested 'Type' element
169 scope = (CElementInfo)parentType;
170 className = "Type";
171 } else {
172 // since the parent element isn't bound to a type, merge the customizations associated to it, too.
173 // custs = CCustomizations.merge( custs, builder.getBindInfo(type.getScope()).toCustomizationList());
174 className = builder.getNameConverter().toClassName(element.getName());
175
176 BISchemaBinding sb = builder.getBindInfo(
177 type.getOwnerSchema() ).get(BISchemaBinding.class);
178 if(sb!=null) className = sb.mangleAnonymousTypeClassName(className);
179 scope = selector.getClassScope();
180 }
181
182 return new CClassInfo(model, scope, className, type.getLocator(), null, null, type, bi.toCustomizationList() );
183 }
184 }
185
186 private QName getTypeName(XSComplexType type) {
187 if(type.getRedefinedBy()!=null)
188 return null;
189 else
190 return getName(type);
191 }
192
193 /**
194 * Returns true if the complex type of the given element can be "optimized away"
195 * and unified with its parent element decl to form a single class.
196 */
197 private boolean isCollapsable(XSElementDecl decl) {
198 XSType type = decl.getType();
199
200 if(!type.isComplexType())
201 return false; // not a complex type
202
203 if(decl.getSubstitutables().size()>1 || decl.getSubstAffiliation()!=null)
204 // because element substitution calls for a proper JAXBElement hierarchy
205 return false;
206
207 if(decl.isNillable())
208 // because nillable needs JAXBElement to represent correctly
209 return false;
210
211 BIXSubstitutable bixSubstitutable = builder.getBindInfo(decl).get(BIXSubstitutable.class);
212 if(bixSubstitutable !=null) {
213 // see https://jaxb.dev.java.net/issues/show_bug.cgi?id=289
214 // this customization forces non-collapsing behavior.
215 bixSubstitutable.markAsAcknowledged();
216 return false;
217 }
218
219 if( getGlobalBinding().isSimpleMode() && decl.isGlobal()) {
220 // in the simple mode, we do more aggressive optimization, and get rid of
221 // a complex type class if it's only used once from a global element
222 XSElementDecl referer = getSoleElementReferer(decl.getType());
223 if(referer!=null) {
224 assert referer==decl; // I must be the sole referer
225 return true;
226 }
227 }
228
229 if(!type.isLocal() || !type.isComplexType())
230 return false;
231
232 return true;
233 }
234
235 /**
236 * If only one global {@link XSElementDecl} is refering to {@link XSType},
237 * return that element, otherwise null.
238 */
239 private @Nullable XSElementDecl getSoleElementReferer(@NotNull XSType t) {
240 Set<XSComponent> referer = builder.getReferer(t);
241
242 XSElementDecl sole = null;
243 for (XSComponent r : referer) {
244 if(r instanceof XSElementDecl) {
245 XSElementDecl x = (XSElementDecl) r;
246 if(!x.isGlobal())
247 // local element references can be ignored, as their names are either given
248 // by the property, or by the JAXBElement (for things like mixed contents)
249 continue;
250 if(sole==null) sole=x;
251 else return null; // more than one
252 } else {
253 // if another type refers to this type, that means
254 // this type has a sub-type, so type substitution is possible now.
255 return null;
256 }
257 }
258
259 return sole;
260 }
261
262 public CElement elementDecl(XSElementDecl decl) {
263 CElement r = allow(decl,decl.getName());
264
265 if(r==null) {
266 QName tagName = getName(decl);
267 CCustomizations custs = builder.getBindInfo(decl).toCustomizationList();
268
269 if(decl.isGlobal()) {
270 if(isCollapsable(decl)) {
271 // we want the returned type to be built as a complex type,
272 // so the binding cannot be delayed.
273 return selector.bindToType(decl.getType().asComplexType(),decl,true);
274 } else {
275 String className = null;
276 if(getGlobalBinding().isGenerateElementClass())
277 className = deriveName(decl);
278
279 // otherwise map global elements to JAXBElement
280 CElementInfo cei = new CElementInfo(
281 model, tagName, selector.getClassScope(), className, custs, decl.getLocator());
282 selector.boundElements.put(decl,cei);
283
284 stb.refererStack.push(decl); // referer is element
285 cei.initContentType( selector.bindToType(decl.getType(),decl), decl, decl.getDefaultValue() );
286 stb.refererStack.pop();
287 r = cei;
288 }
289 }
290 }
291
292 // have the substitution member derive from the substitution head
293 XSElementDecl top = decl.getSubstAffiliation();
294 if(top!=null) {
295 CElement topci = selector.bindToType(top,decl);
296
297 if(r instanceof CClassInfo && topci instanceof CClassInfo)
298 ((CClassInfo)r).setBaseClass((CClassInfo)topci);
299 if (r instanceof CElementInfo && topci instanceof CElementInfo)
300 ((CElementInfo)r).setSubstitutionHead((CElementInfo)topci);
301 }
302
303 return r;
304 }
305
306 public CClassInfo empty( XSContentType ct ) { return null; }
307
308 public CClassInfo identityConstraint(XSIdentityConstraint xsIdentityConstraint) {
309 return never();
310 }
311
312 public CClassInfo xpath(XSXPath xsxPath) {
313 return never();
314 }
315
316 public CClassInfo attributeUse(XSAttributeUse use) {
317 return never();
318 }
319
320 public CElement simpleType(XSSimpleType type) {
321 CElement c = allow(type,type.getName());
322 if(c!=null) return c;
323
324 if(getGlobalBinding().isSimpleTypeSubstitution() && type.isGlobal()) {
325 return new CClassInfo(model,selector.getClassScope(),
326 deriveName(type), type.getLocator(), getName(type), null, type, null );
327 }
328
329 return never();
330 }
331
332 public CClassInfo particle(XSParticle particle) {
333 return never();
334 }
335
336 public CClassInfo wildcard(XSWildcard wc) {
337 return never();
338 }
339
340
341 // these methods won't be used
342 public CClassInfo annotation(XSAnnotation annon) {
343 assert false;
344 return null;
345 }
346
347 public CClassInfo notation(XSNotation not) {
348 assert false;
349 return null;
350 }
351
352 public CClassInfo facet(XSFacet decl) {
353 assert false;
354 return null;
355 }
356 public CClassInfo schema(XSSchema schema) {
357 assert false;
358 return null;
359 }
360
361
362
363
364
365 /**
366 * Makes sure that the component doesn't carry a {@link BIClass}
367 * customization.
368 *
369 * @return
370 * return value is unused. Since most of the caller needs to
371 * return null, to make the code a little bit shorter, this
372 * method always return null (so that the caller can always
373 * say <code>return never(sc);</code>.
374 */
375 private CClassInfo never() {
376 // all we need to do here is just not to acknowledge
377 // any class customization. Then this class customization
378 // will be reported as an error later when we check all
379 // unacknowledged customizations.
380
381
382 // BIDeclaration cust=owner.getBindInfo(component).get(BIClass.NAME);
383 // if(cust!=null) {
384 // // error
385 // owner.errorReporter.error(
386 // cust.getLocation(),
387 // "test {0}", NameGetter.get(component) );
388 // }
389 return null;
390 }
391
392 /**
393 * Checks if a component carries a customization to map it to a class.
394 * If so, make it a class.
395 *
396 * @param defaultBaseName
397 * The token which will be used as the basis of the class name
398 * if the class name is not specified in the customization.
399 * This is usually the name of an element declaration, and so on.
400 *
401 * This parameter can be null, in that case it would be an error
402 * if a name is not given by the customization.
403 */
404 private CElement allow( XSComponent component, String defaultBaseName ) {
405
406 BIClass decl = null;
407
408 if(component instanceof XSComplexType) {
409 XSType complexType = (XSType)component;
410
411 BIClass lastFoundRecursiveBiClass = null;
412
413 if(complexType.getName() != null) {
414 while( ! schemas.getAnyType().equals(complexType)) {
415 BindInfo bindInfo = builder.getBindInfo(complexType);
416 BIClass biClass = bindInfo.get(BIClass.class);
417
418 if(biClass != null && "true".equals(biClass.getRecursive()))
419 lastFoundRecursiveBiClass = biClass;
420
421 complexType = complexType.getBaseType();
422 }
423 }
424
425 // use this as biclass for current component
426 decl = lastFoundRecursiveBiClass;
427
428 }
429
430 BindInfo bindInfo = builder.getBindInfo(component);
431 if(decl == null) {
432 decl = bindInfo.get(BIClass.class);
433 if(decl==null) return null;
434 }
435
436 decl.markAsAcknowledged();
437
438 // first consider binding to the class reference.
439 String ref = decl.getExistingClassRef();
440 if(ref!=null) {
441 if(!JJavaName.isFullyQualifiedClassName(ref)) {
442 Ring.get(ErrorReceiver.class).error( decl.getLocation(),
443 Messages.format(Messages.ERR_INCORRECT_CLASS_NAME,ref) );
444 // recover by ignoring @ref
445 } else {
446 if(component instanceof XSComplexType) {
447 // UGLY UGLY UGLY
448 // since we are not going to bind this complex type, we need to figure out
449 // its binding mode without actually binding it (and also expose this otherwise
450 // hidden mechanism into this part of the code.)
451 //
452 // this code is potentially dangerous as the base class might have been bound
453 // in different ways. To be correct, we need to figure out how the content type
454 // would have been bound, from the schema.
455 Ring.get(ComplexTypeFieldBuilder.class).recordBindingMode(
456 (XSComplexType)component, ComplexTypeBindingMode.NORMAL
457 );
458 }
459 return new CClassRef(model, component, decl, bindInfo.toCustomizationList() );
460 }
461 }
462
463 String clsName = decl.getClassName();
464 if(clsName==null) {
465 // if the customiztion doesn't give us a name, derive one
466 // from the current component.
467 if( defaultBaseName==null ) {
468 Ring.get(ErrorReceiver.class).error( decl.getLocation(),
469 Messages.format(Messages.ERR_CLASS_NAME_IS_REQUIRED) );
470
471 // recover by generating a pseudo-random name
472 defaultBaseName = "undefined"+component.hashCode();
473 }
474 clsName = builder.deriveName( defaultBaseName, component );
475 } else {
476 if( !JJavaName.isJavaIdentifier(clsName) ) {
477 // not a valid Java class name
478 Ring.get(ErrorReceiver.class).error( decl.getLocation(),
479 Messages.format( Messages.ERR_INCORRECT_CLASS_NAME, clsName ));
480 // recover by a dummy name
481 clsName = "Undefined"+component.hashCode();
482 }
483 }
484
485 QName typeName = null;
486 QName elementName = null;
487
488 if(component instanceof XSType) {
489 XSType t = (XSType) component;
490 typeName = getName(t);
491 }
492
493 if (component instanceof XSElementDecl) {
494 XSElementDecl e = (XSElementDecl) component;
495 elementName = getName(e);
496 }
497
498 if (component instanceof XSElementDecl && !isCollapsable((XSElementDecl)component)) {
499 XSElementDecl e = ((XSElementDecl)component);
500
501 CElementInfo cei = new CElementInfo(model, elementName,
502 selector.getClassScope(), clsName,
503 bindInfo.toCustomizationList(), decl.getLocation() );
504 selector.boundElements.put(e,cei);
505
506 stb.refererStack.push(component); // referer is element
507 cei.initContentType(
508 selector.bindToType(e.getType(),e),
509 e,e.getDefaultValue());
510 stb.refererStack.pop();
511 return cei;
512 // TODO: support javadoc and userSpecifiedImplClass
513 } else {
514 CClassInfo bt = new CClassInfo(model,selector.getClassScope(),
515 clsName, decl.getLocation(), typeName, elementName, component, bindInfo.toCustomizationList() );
516
517 // set javadoc class comment.
518 if(decl.getJavadoc()!=null )
519 bt.javadoc = decl.getJavadoc()+"\n\n";
520 // add extra blank lines so that the schema fragment
521 // and user-specified javadoc would be separated
522
523
524 // if the implClass is given, set it to ClassItem
525 String implClass = decl.getUserSpecifiedImplClass();
526 if( implClass!=null )
527 bt.setUserSpecifiedImplClass( implClass );
528
529 return bt;
530 }
531 }
532
533 private BIGlobalBinding getGlobalBinding() {
534 return builder.getGlobalBinding();
535 }
536
537 /**
538 * Derives a name from a schema component.
539 * Use the name of the schema component as the default name.
540 */
541 private String deriveName( XSDeclaration comp ) {
542 return builder.deriveName( comp.getName(), comp );
543 }
544
545 /**
546 * Derives a name from a schema component.
547 * For complex types, we take redefinition into account when
548 * deriving a default name.
549 */
550 private String deriveName( XSComplexType comp ) {
551 String seed = builder.deriveName( comp.getName(), comp );
552 int cnt = comp.getRedefinedCount();
553 for( ; cnt>0; cnt-- )
554 seed = "Original"+seed;
555 return seed;
556 }
557
558 }

mercurial