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