001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.tools.xjc.generator.bean;
038:
039: import static com.sun.tools.xjc.outline.Aspect.EXPOSED;
040:
041: import java.io.Serializable;
042: import java.net.URL;
043: import java.util.Collection;
044: import java.util.HashMap;
045: import java.util.HashSet;
046: import java.util.Iterator;
047: import java.util.Map;
048: import java.util.Set;
049: import java.util.TreeSet;
050:
051: import javax.xml.bind.JAXBContext;
052: import javax.xml.bind.JAXBException;
053: import javax.xml.bind.annotation.XmlAttachmentRef;
054: import javax.xml.bind.annotation.XmlID;
055: import javax.xml.bind.annotation.XmlIDREF;
056: import javax.xml.bind.annotation.XmlMimeType;
057: import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
058: import javax.xml.namespace.QName;
059:
060: import com.sun.codemodel.ClassType;
061: import com.sun.codemodel.JAnnotatable;
062: import com.sun.codemodel.JClass;
063: import com.sun.codemodel.JClassAlreadyExistsException;
064: import com.sun.codemodel.JClassContainer;
065: import com.sun.codemodel.JCodeModel;
066: import com.sun.codemodel.JDefinedClass;
067: import com.sun.codemodel.JEnumConstant;
068: import com.sun.codemodel.JExpr;
069: import com.sun.codemodel.JExpression;
070: import com.sun.codemodel.JFieldVar;
071: import com.sun.codemodel.JForEach;
072: import com.sun.codemodel.JInvocation;
073: import com.sun.codemodel.JJavaName;
074: import com.sun.codemodel.JMethod;
075: import com.sun.codemodel.JMod;
076: import com.sun.codemodel.JPackage;
077: import com.sun.codemodel.JType;
078: import com.sun.codemodel.JVar;
079: import com.sun.codemodel.fmt.JStaticJavaFile;
080: import com.sun.tools.xjc.AbortException;
081: import com.sun.tools.xjc.ErrorReceiver;
082: import com.sun.tools.xjc.api.SpecVersion;
083: import com.sun.tools.xjc.generator.annotation.spec.XmlAnyAttributeWriter;
084: import com.sun.tools.xjc.generator.annotation.spec.XmlEnumValueWriter;
085: import com.sun.tools.xjc.generator.annotation.spec.XmlEnumWriter;
086: import com.sun.tools.xjc.generator.annotation.spec.XmlJavaTypeAdapterWriter;
087: import com.sun.tools.xjc.generator.annotation.spec.XmlMimeTypeWriter;
088: import com.sun.tools.xjc.generator.annotation.spec.XmlRootElementWriter;
089: import com.sun.tools.xjc.generator.annotation.spec.XmlSeeAlsoWriter;
090: import com.sun.tools.xjc.generator.annotation.spec.XmlTypeWriter;
091: import com.sun.tools.xjc.generator.bean.field.FieldRenderer;
092: import com.sun.tools.xjc.model.CAdapter;
093: import com.sun.tools.xjc.model.CAttributePropertyInfo;
094: import com.sun.tools.xjc.model.CClassInfo;
095: import com.sun.tools.xjc.model.CClassInfoParent;
096: import com.sun.tools.xjc.model.CElementInfo;
097: import com.sun.tools.xjc.model.CEnumConstant;
098: import com.sun.tools.xjc.model.CEnumLeafInfo;
099: import com.sun.tools.xjc.model.CPropertyInfo;
100: import com.sun.tools.xjc.model.CTypeRef;
101: import com.sun.tools.xjc.model.Model;
102: import com.sun.tools.xjc.model.CClassRef;
103: import com.sun.tools.xjc.outline.Aspect;
104: import com.sun.tools.xjc.outline.ClassOutline;
105: import com.sun.tools.xjc.outline.EnumConstantOutline;
106: import com.sun.tools.xjc.outline.EnumOutline;
107: import com.sun.tools.xjc.outline.FieldOutline;
108: import com.sun.tools.xjc.outline.Outline;
109: import com.sun.tools.xjc.outline.PackageOutline;
110: import com.sun.tools.xjc.util.CodeModelClassFactory;
111: import com.sun.xml.bind.v2.model.core.PropertyInfo;
112: import com.sun.xml.bind.v2.runtime.SwaRefAdapter;
113: import com.sun.xml.xsom.XmlString;
114: import com.sun.istack.NotNull;
115:
116: /**
117: * Generates fields and accessors.
118: */
119: public final class BeanGenerator implements Outline {
120: /** Simplifies class/interface creation and collision detection. */
121: private final CodeModelClassFactory codeModelClassFactory;
122:
123: private final ErrorReceiver errorReceiver;
124:
125: /** all {@link PackageOutline}s keyed by their {@link PackageOutline#_package}. */
126: private final Map<JPackage, PackageOutlineImpl> packageContexts = new HashMap<JPackage, PackageOutlineImpl>();
127:
128: /** all {@link ClassOutline}s keyed by their {@link ClassOutline#target}. */
129: private final Map<CClassInfo, ClassOutlineImpl> classes = new HashMap<CClassInfo, ClassOutlineImpl>();
130:
131: /** all {@link EnumOutline}s keyed by their {@link EnumOutline#target}. */
132: private final Map<CEnumLeafInfo, EnumOutline> enums = new HashMap<CEnumLeafInfo, EnumOutline>();
133:
134: /**
135: * Generated runtime classes.
136: */
137: private final Map<Class, JClass> generatedRuntime = new HashMap<Class, JClass>();
138:
139: /** the model object which we are processing. */
140: private final Model model;
141:
142: private final JCodeModel codeModel;
143:
144: /**
145: * for each property, the information about the generated field.
146: */
147: private final Map<CPropertyInfo, FieldOutline> fields = new HashMap<CPropertyInfo, FieldOutline>();
148:
149: /**
150: * elements that generate classes to the generated classes.
151: */
152: /*package*/final Map<CElementInfo, ElementOutlineImpl> elements = new HashMap<CElementInfo, ElementOutlineImpl>();
153:
154: /**
155: * Generates beans into code model according to the BGM,
156: * and produces the reflection model.
157: *
158: * @param _errorReceiver
159: * This object will receive all the errors discovered
160: * during the back-end stage.
161: *
162: * @return
163: * returns a {@link Outline} which will in turn
164: * be used to further generate marshaller/unmarshaller,
165: * or null if the processing fails (errors should have been
166: * reported to the error recevier.)
167: */
168: public static Outline generate(Model model,
169: ErrorReceiver _errorReceiver) {
170:
171: try {
172: return new BeanGenerator(model, _errorReceiver);
173: } catch (AbortException e) {
174: return null;
175: }
176: }
177:
178: private BeanGenerator(Model _model, ErrorReceiver _errorReceiver) {
179:
180: this .model = _model;
181: this .codeModel = model.codeModel;
182: this .errorReceiver = _errorReceiver;
183: this .codeModelClassFactory = new CodeModelClassFactory(
184: errorReceiver);
185:
186: // build enum classes
187: for (CEnumLeafInfo p : model.enums().values())
188: enums.put(p, generateEnumDef(p));
189:
190: JPackage[] packages = getUsedPackages(EXPOSED);
191:
192: // generates per-package code and remember the results as contexts.
193: for (JPackage pkg : packages)
194: getPackageContext(pkg);
195:
196: // create the class definitions for all the beans first.
197: // this should also fill in PackageContext#getClasses
198: for (CClassInfo bean : model.beans().values())
199: getClazz(bean);
200:
201: // compute the package-level setting
202: for (PackageOutlineImpl p : packageContexts.values())
203: p.calcDefaultValues();
204:
205: JClass OBJECT = codeModel.ref(Object.class);
206:
207: // inheritance relationship needs to be set before we generate fields, or otherwise
208: // we'll fail to compute the correct type signature (namely the common base type computation)
209: for (ClassOutlineImpl cc : getClasses()) {
210:
211: // setup inheritance between implementation hierarchy.
212: CClassInfo super Class = cc.target.getBaseClass();
213: if (super Class != null) {
214: // use the specified super class
215: model.strategy._extends(cc, getClazz(super Class));
216: } else {
217: CClassRef refSuperClass = cc.target.getRefBaseClass();
218: if (refSuperClass != null) {
219: cc.implClass._extends(refSuperClass.toType(this ,
220: EXPOSED));
221: } else {
222: // use the default one, if any
223: if (model.rootClass != null
224: && cc.implClass._extends().equals(OBJECT))
225: cc.implClass._extends(model.rootClass);
226: if (model.rootInterface != null)
227: cc.ref._implements (model.rootInterface);
228: }
229: }
230: }
231:
232: // fill in implementation classes
233: for (ClassOutlineImpl co : getClasses())
234: generateClassBody(co);
235:
236: for (EnumOutline eo : enums.values())
237: generateEnumBody(eo);
238:
239: // create factories for the impl-less elements
240: for (CElementInfo ei : model.getAllElements())
241: getPackageContext(ei._package()).objectFactoryGenerator()
242: .populate(ei);
243:
244: if (model.options.debugMode)
245: generateClassList();
246: }
247:
248: /**
249: * Generates a class that knows how to create an instance of JAXBContext
250: *
251: * <p>
252: * This is used in the debug mode so that a new properly configured
253: * {@link JAXBContext} object can be used.
254: */
255: private void generateClassList() {
256: try {
257: JDefinedClass jc = codeModel.rootPackage()._class(
258: "JAXBDebug");
259: JMethod m = jc.method(JMod.PUBLIC | JMod.STATIC,
260: JAXBContext.class, "createContext");
261: JVar $classLoader = m.param(ClassLoader.class,
262: "classLoader");
263: m._throws(JAXBException.class);
264: JInvocation inv = codeModel.ref(JAXBContext.class)
265: .staticInvoke("newInstance");
266: m.body()._return(inv);
267:
268: switch (model.strategy) {
269: case INTF_AND_IMPL: {
270: StringBuilder buf = new StringBuilder();
271: for (PackageOutlineImpl po : packageContexts.values()) {
272: if (buf.length() > 0)
273: buf.append(':');
274: buf.append(po._package().name());
275: }
276: inv.arg(buf.toString()).arg($classLoader);
277: break;
278: }
279: case BEAN_ONLY:
280: for (ClassOutlineImpl cc : getClasses())
281: inv.arg(cc.implRef.dotclass());
282: for (PackageOutlineImpl po : packageContexts.values())
283: inv.arg(po.objectFactory().dotclass());
284: break;
285: default:
286: throw new IllegalStateException();
287: }
288: } catch (JClassAlreadyExistsException e) {
289: e.printStackTrace();
290: // after all, we are in the debug mode. a little sloppiness is OK.
291: // this error is not fatal. just continue.
292: }
293: }
294:
295: public Model getModel() {
296: return model;
297: }
298:
299: public JCodeModel getCodeModel() {
300: return codeModel;
301: }
302:
303: public JClassContainer getContainer(CClassInfoParent parent,
304: Aspect aspect) {
305: CClassInfoParent.Visitor<JClassContainer> v;
306: switch (aspect) {
307: case EXPOSED:
308: v = exposedContainerBuilder;
309: break;
310: case IMPLEMENTATION:
311: v = implContainerBuilder;
312: break;
313: default:
314: assert false;
315: throw new IllegalStateException();
316: }
317: return parent.accept(v);
318: }
319:
320: public final JType resolve(CTypeRef ref, Aspect a) {
321: return ref.getTarget().getType().toType(this , a);
322: }
323:
324: private final CClassInfoParent.Visitor<JClassContainer> exposedContainerBuilder = new CClassInfoParent.Visitor<JClassContainer>() {
325: public JClassContainer onBean(CClassInfo bean) {
326: return getClazz(bean).ref;
327: }
328:
329: public JClassContainer onElement(CElementInfo element) {
330: // hmm...
331: return getElement(element).implClass;
332: }
333:
334: public JClassContainer onPackage(JPackage pkg) {
335: return model.strategy.getPackage(pkg, EXPOSED);
336: }
337: };
338:
339: private final CClassInfoParent.Visitor<JClassContainer> implContainerBuilder = new CClassInfoParent.Visitor<JClassContainer>() {
340: public JClassContainer onBean(CClassInfo bean) {
341: return getClazz(bean).implClass;
342: }
343:
344: public JClassContainer onElement(CElementInfo element) {
345: return getElement(element).implClass;
346: }
347:
348: public JClassContainer onPackage(JPackage pkg) {
349: return model.strategy
350: .getPackage(pkg, Aspect.IMPLEMENTATION);
351: }
352: };
353:
354: /**
355: * Returns all <i>used</i> JPackages.
356: *
357: * A JPackage is considered as "used" if a ClassItem or
358: * a InterfaceItem resides in that package.
359: *
360: * This value is dynamically calculated every time because
361: * one can freely remove ClassItem/InterfaceItem.
362: *
363: * @return
364: * Given the same input, the order of packages in the array
365: * is always the same regardless of the environment.
366: */
367: public final JPackage[] getUsedPackages(Aspect aspect) {
368: Set<JPackage> s = new TreeSet<JPackage>();
369:
370: for (CClassInfo bean : model.beans().values()) {
371: JClassContainer cont = getContainer(bean.parent(), aspect);
372: if (cont.isPackage())
373: s.add((JPackage) cont);
374: }
375:
376: for (CElementInfo e : model.getElementMappings(null).values()) {
377: // at the first glance you might think we should be iterating all elements,
378: // not just global ones, but if you think about it, local ones live inside
379: // another class, so those packages are already enumerated when we were
380: // walking over CClassInfos.
381: s.add(e._package());
382: }
383:
384: return s.toArray(new JPackage[s.size()]);
385: }
386:
387: public ErrorReceiver getErrorReceiver() {
388: return errorReceiver;
389: }
390:
391: public CodeModelClassFactory getClassFactory() {
392: return codeModelClassFactory;
393: }
394:
395: public PackageOutlineImpl getPackageContext(JPackage p) {
396: PackageOutlineImpl r = packageContexts.get(p);
397: if (r == null) {
398: r = new PackageOutlineImpl(this , model, p);
399: packageContexts.put(p, r);
400: }
401: return r;
402: }
403:
404: /**
405: * Generates the minimum {@link JDefinedClass} skeleton
406: * without filling in its body.
407: */
408: private ClassOutlineImpl generateClassDef(CClassInfo bean) {
409: ImplStructureStrategy.Result r = model.strategy.createClasses(
410: this , bean);
411: JClass implRef;
412:
413: if (bean.getUserSpecifiedImplClass() != null) {
414: // create a place holder for a user-specified class.
415: JDefinedClass usr;
416: try {
417: usr = codeModel
418: ._class(bean.getUserSpecifiedImplClass());
419: // but hide that file so that it won't be generated.
420: usr.hide();
421: } catch (JClassAlreadyExistsException e) {
422: // it's OK for this to collide.
423: usr = e.getExistingClass();
424: }
425: usr._extends(r.implementation);
426: implRef = usr;
427: } else
428: implRef = r.implementation;
429:
430: return new ClassOutlineImpl(this , bean, r.exposed,
431: r.implementation, implRef);
432: }
433:
434: public Collection<ClassOutlineImpl> getClasses() {
435: // make sure that classes are fully populated
436: assert model.beans().size() == classes.size();
437: return classes.values();
438: }
439:
440: public ClassOutlineImpl getClazz(CClassInfo bean) {
441: ClassOutlineImpl r = classes.get(bean);
442: if (r == null)
443: classes.put(bean, r = generateClassDef(bean));
444: return r;
445: }
446:
447: public ElementOutlineImpl getElement(CElementInfo ei) {
448: ElementOutlineImpl def = elements.get(ei);
449: if (def == null && ei.hasClass()) {
450: // create one. in the constructor it adds itself to the elements.
451: def = new ElementOutlineImpl(this , ei);
452: }
453: return def;
454: }
455:
456: public EnumOutline getEnum(CEnumLeafInfo eli) {
457: return enums.get(eli);
458: }
459:
460: public Collection<EnumOutline> getEnums() {
461: return enums.values();
462: }
463:
464: public Iterable<? extends PackageOutline> getAllPackageContexts() {
465: return packageContexts.values();
466: }
467:
468: public FieldOutline getField(CPropertyInfo prop) {
469: return fields.get(prop);
470: }
471:
472: /**
473: * Generates the body of a class.
474: *
475: */
476: private void generateClassBody(ClassOutlineImpl cc) {
477: CClassInfo target = cc.target;
478:
479: // if serialization support is turned on, generate
480: // [RESULT]
481: // class ... implements Serializable {
482: // private static final long serialVersionUID = <id>;
483: // ....
484: // }
485: if (model.serializable) {
486: cc.implClass._implements (Serializable.class);
487: if (model.serialVersionUID != null) {
488: cc.implClass.field(JMod.PRIVATE | JMod.STATIC
489: | JMod.FINAL, codeModel.LONG,
490: "serialVersionUID", JExpr
491: .lit(model.serialVersionUID));
492: }
493: }
494:
495: // used to simplify the generated annotations
496: String mostUsedNamespaceURI = cc._package()
497: .getMostUsedNamespaceURI();
498:
499: // [RESULT]
500: // @XmlType(name="foo", targetNamespace="bar://baz")
501: XmlTypeWriter xtw = cc.implClass.annotate2(XmlTypeWriter.class);
502: writeTypeName(cc.target.getTypeName(), xtw,
503: mostUsedNamespaceURI);
504:
505: if (model.options.target.isLaterThan(SpecVersion.V2_1)) {
506: // @XmlSeeAlso
507: Iterator<CClassInfo> subclasses = cc.target
508: .listSubclasses();
509: if (subclasses.hasNext()) {
510: XmlSeeAlsoWriter saw = cc.implClass
511: .annotate2(XmlSeeAlsoWriter.class);
512: while (subclasses.hasNext()) {
513: CClassInfo s = subclasses.next();
514: saw.value(getClazz(s).implRef);
515: }
516: }
517: }
518:
519: if (target.isElement()) {
520: String namespaceURI = target.getElementName()
521: .getNamespaceURI();
522: String localPart = target.getElementName().getLocalPart();
523:
524: // [RESULT]
525: // @XmlRootElement(name="foo", targetNamespace="bar://baz")
526: XmlRootElementWriter xrew = cc.implClass
527: .annotate2(XmlRootElementWriter.class);
528: xrew.name(localPart);
529: if (!namespaceURI.equals(mostUsedNamespaceURI)) // only generate if necessary
530: xrew.namespace(namespaceURI);
531: }
532:
533: if (target.isOrdered()) {
534: for (CPropertyInfo p : target.getProperties()) {
535: if (!(p instanceof CAttributePropertyInfo)) {
536: xtw.propOrder(p.getName(false));
537: }
538: }
539: } else {
540: // produce empty array
541: xtw.getAnnotationUse().paramArray("propOrder");
542: }
543:
544: for (CPropertyInfo prop : target.getProperties()) {
545: generateFieldDecl(cc, prop);
546: }
547:
548: if (target.declaresAttributeWildcard()) {
549: generateAttributeWildcard(cc);
550: }
551:
552: // generate some class level javadoc
553: cc.ref.javadoc().append(target.javadoc);
554:
555: cc._package().objectFactoryGenerator().populate(cc);
556: }
557:
558: private void writeTypeName(QName typeName, XmlTypeWriter xtw,
559: String mostUsedNamespaceURI) {
560: if (typeName == null) {
561: xtw.name("");
562: } else {
563: xtw.name(typeName.getLocalPart());
564: final String typeNameURI = typeName.getNamespaceURI();
565: if (!typeNameURI.equals(mostUsedNamespaceURI)) // only generate if necessary
566: xtw.namespace(typeNameURI);
567: }
568: }
569:
570: /**
571: * Generates an attribute wildcard property on a class.
572: */
573: private void generateAttributeWildcard(ClassOutlineImpl cc) {
574: String FIELD_NAME = "otherAttributes";
575: String METHOD_SEED = model.getNameConverter().toClassName(
576: FIELD_NAME);
577:
578: JClass mapType = codeModel.ref(Map.class).narrow(QName.class,
579: String.class);
580: JClass mapImpl = codeModel.ref(HashMap.class).narrow(
581: QName.class, String.class);
582:
583: // [RESULT]
584: // Map<QName,String> m = new HashMap<QName,String>();
585: JFieldVar $ref = cc.implClass.field(JMod.PRIVATE, mapType,
586: FIELD_NAME, JExpr._new(mapImpl));
587: $ref.annotate2(XmlAnyAttributeWriter.class);
588:
589: MethodWriter writer = cc.createMethodWriter();
590:
591: JMethod $get = writer.declareMethod(mapType, "get"
592: + METHOD_SEED);
593: $get
594: .javadoc()
595: .append(
596: "Gets a map that contains attributes that aren't bound to any typed property on this class.\n\n"
597: + "<p>\n"
598: + "the map is keyed by the name of the attribute and \n"
599: + "the value is the string value of the attribute.\n"
600: + "\n"
601: + "the map returned by this method is live, and you can add new attribute\n"
602: + "by updating the map directly. Because of this design, there's no setter.\n");
603: $get.javadoc().addReturn().append("always non-null");
604:
605: $get.body()._return($ref);
606: }
607:
608: /**
609: * Generates the minimum {@link JDefinedClass} skeleton
610: * without filling in its body.
611: */
612: private EnumOutline generateEnumDef(CEnumLeafInfo e) {
613: JDefinedClass type;
614:
615: type = getClassFactory().createClass(
616: getContainer(e.parent, EXPOSED), e.shortName,
617: e.getLocator(), ClassType.ENUM);
618: type.javadoc().append(e.javadoc);
619:
620: return new EnumOutline(e, type) {
621: @Override
622: public @NotNull
623: Outline parent() {
624: return BeanGenerator.this ;
625: }
626: };
627: }
628:
629: private void generateEnumBody(EnumOutline eo) {
630: JDefinedClass type = eo.clazz;
631: CEnumLeafInfo e = eo.target;
632:
633: XmlTypeWriter xtw = type.annotate2(XmlTypeWriter.class);
634: writeTypeName(e.getTypeName(), xtw, eo._package()
635: .getMostUsedNamespaceURI());
636:
637: JCodeModel codeModel = model.codeModel;
638:
639: // since constant values are never null, no point in using the boxed types.
640: JType baseExposedType = e.base.toType(this , EXPOSED).unboxify();
641: JType baseImplType = e.base.toType(this , Aspect.IMPLEMENTATION)
642: .unboxify();
643:
644: XmlEnumWriter xew = type.annotate2(XmlEnumWriter.class);
645: xew.value(baseExposedType);
646:
647: boolean needsValue = e.needsValueField();
648:
649: // for each member <m>,
650: // [RESULT]
651: // <EnumName>(<deserializer of m>(<value>));
652:
653: Set<String> enumFieldNames = new HashSet<String>(); // record generated field names to detect collision
654:
655: for (CEnumConstant mem : e.members) {
656: String constName = mem.getName();
657:
658: if (!JJavaName.isJavaIdentifier(constName)) {
659: // didn't produce a name.
660: getErrorReceiver().error(
661: e.getLocator(),
662: Messages.ERR_UNUSABLE_NAME.format(mem
663: .getLexicalValue(), constName));
664: }
665:
666: if (!enumFieldNames.add(constName))
667: getErrorReceiver().error(e.getLocator(),
668: Messages.ERR_NAME_COLLISION.format(constName));
669:
670: // [RESULT]
671: // <Const>(...)
672: // ASSUMPTION: datatype is outline-independent
673: JEnumConstant constRef = type.enumConstant(constName);
674: if (needsValue)
675: constRef.arg(e.base.createConstant(this , new XmlString(
676: mem.getLexicalValue())));
677:
678: if (!mem.getLexicalValue().equals(constName))
679: constRef.annotate2(XmlEnumValueWriter.class).value(
680: mem.getLexicalValue());
681:
682: // set javadoc
683: if (mem.javadoc != null)
684: constRef.javadoc().append(mem.javadoc);
685:
686: eo.constants.add(new EnumConstantOutline(mem, constRef) {
687: });
688: }
689:
690: if (needsValue) {
691: // [RESULT]
692: // final <valueType> value;
693: JFieldVar $value = type.field(JMod.PRIVATE | JMod.FINAL,
694: baseExposedType, "value");
695:
696: // [RESULT]
697: // public <valuetype> value() { return value; }
698: type.method(JMod.PUBLIC, baseExposedType, "value").body()
699: ._return($value);
700:
701: // [RESULT]
702: // <constructor>(<valueType> v) {
703: // this.value=v;
704: // }
705: {
706: JMethod m = type.constructor(0);
707: m.body().assign($value, m.param(baseImplType, "v"));
708: }
709:
710: // [RESULT]
711: // public static <Const> fromValue(<valueType> v) {
712: // for( <Const> c : <Const>.values() ) {
713: // if(c.value == v) // or equals
714: // return c;
715: // }
716: // throw new IllegalArgumentException(...);
717: // }
718: {
719: JMethod m = type.method(JMod.PUBLIC | JMod.STATIC,
720: type, "fromValue");
721: JVar $v = m.param(baseExposedType, "v");
722: JForEach fe = m.body().forEach(type, "c",
723: type.staticInvoke("values"));
724: JExpression eq;
725: if (baseExposedType.isPrimitive())
726: eq = fe.var().ref($value).eq($v);
727: else
728: eq = fe.var().ref($value).invoke("equals").arg($v);
729:
730: fe.body()._if(eq)._then()._return(fe.var());
731:
732: JInvocation ex = JExpr._new(codeModel
733: .ref(IllegalArgumentException.class));
734:
735: JExpression strForm;
736: if (baseExposedType.isPrimitive()) {
737: strForm = codeModel.ref(String.class).staticInvoke(
738: "valueOf").arg($v);
739: } else if (baseExposedType == codeModel
740: .ref(String.class)) {
741: strForm = $v;
742: } else {
743: strForm = $v.invoke("toString");
744: }
745: m.body()._throw(ex.arg(strForm));
746: }
747: } else {
748: // [RESULT]
749: // public String value() { return name(); }
750: type.method(JMod.PUBLIC, String.class, "value").body()
751: ._return(JExpr.invoke("name"));
752:
753: // [RESULT]
754: // public <Const> fromValue(String v) { return valueOf(v); }
755: JMethod m = type.method(JMod.PUBLIC | JMod.STATIC, type,
756: "fromValue");
757: m.body()._return(
758: JExpr.invoke("valueOf").arg(
759: m.param(String.class, "v")));
760: }
761: }
762:
763: /**
764: * Determines the FieldRenderer used for the given FieldUse,
765: * then generates the field declaration and accessor methods.
766: *
767: * The <code>fields</code> map will be updated with the newly
768: * created FieldRenderer.
769: */
770: private FieldOutline generateFieldDecl(ClassOutlineImpl cc,
771: CPropertyInfo prop) {
772: FieldRenderer fr = prop.realization;
773: if (fr == null)
774: // none is specified. use the default factory
775: fr = model.options.getFieldRendererFactory().getDefault();
776:
777: FieldOutline field = fr.generate(cc, prop);
778: fields.put(prop, field);
779:
780: return field;
781: }
782:
783: /**
784: * Generates {@link XmlJavaTypeAdapter} from {@link PropertyInfo} if necessary.
785: * Also generates other per-property annotations
786: * (such as {@link XmlID}, {@link XmlIDREF}, and {@link XmlMimeType} if necessary.
787: */
788: public final void generateAdapterIfNecessary(CPropertyInfo prop,
789: JAnnotatable field) {
790: CAdapter adapter = prop.getAdapter();
791: if (adapter != null) {
792: if (adapter.getAdapterIfKnown() == SwaRefAdapter.class) {
793: field.annotate(XmlAttachmentRef.class);
794: } else {
795: // [RESULT]
796: // @XmlJavaTypeAdapter( Foo.class )
797: XmlJavaTypeAdapterWriter xjtw = field
798: .annotate2(XmlJavaTypeAdapterWriter.class);
799: xjtw.value(adapter.adapterType.toType(this , EXPOSED));
800: }
801: }
802:
803: switch (prop.id()) {
804: case ID:
805: field.annotate(XmlID.class);
806: break;
807: case IDREF:
808: field.annotate(XmlIDREF.class);
809: break;
810: }
811:
812: if (prop.getExpectedMimeType() != null)
813: field.annotate2(XmlMimeTypeWriter.class).value(
814: prop.getExpectedMimeType().toString());
815: }
816:
817: public final JClass addRuntime(Class clazz) {
818: JClass g = generatedRuntime.get(clazz);
819: if (g == null) {
820: // put code into a separate package to avoid name conflicts.
821: JPackage implPkg = getUsedPackages(Aspect.IMPLEMENTATION)[0]
822: .subPackage("runtime");
823: g = generateStaticClass(clazz, implPkg);
824: generatedRuntime.put(clazz, g);
825: }
826: return g;
827: }
828:
829: public JClass generateStaticClass(Class src, JPackage out) {
830: String shortName = getShortName(src.getName());
831:
832: // some people didn't like our jars to contain files with .java extension,
833: // so when we build jars, we'' use ".java_". But when we run from the workspace,
834: // we want the original source code to be used, so we check both here.
835: // see bug 6211503.
836: URL res = src.getResource(shortName + ".java");
837: if (res == null)
838: res = src.getResource(shortName + ".java_");
839: if (res == null)
840: throw new InternalError("Unable to load source code of "
841: + src.getName() + " as a resource");
842:
843: JStaticJavaFile sjf = new JStaticJavaFile(out, shortName, res,
844: null);
845: out.addResourceFile(sjf);
846: return sjf.getJClass();
847: }
848:
849: private String getShortName(String name) {
850: return name.substring(name.lastIndexOf('.') + 1);
851: }
852: }
|