/*
 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.tools.internal.xjc.generator.bean;

import static com.sun.tools.internal.xjc.outline.Aspect.EXPOSED;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlAttachmentRef;
import javax.xml.bind.annotation.XmlID;
import javax.xml.bind.annotation.XmlIDREF;
import javax.xml.bind.annotation.XmlMimeType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.namespace.QName;

import com.sun.codemodel.internal.ClassType;
import com.sun.codemodel.internal.JAnnotatable;
import com.sun.codemodel.internal.JClass;
import com.sun.codemodel.internal.JClassAlreadyExistsException;
import com.sun.codemodel.internal.JClassContainer;
import com.sun.codemodel.internal.JCodeModel;
import com.sun.codemodel.internal.JDefinedClass;
import com.sun.codemodel.internal.JEnumConstant;
import com.sun.codemodel.internal.JExpr;
import com.sun.codemodel.internal.JExpression;
import com.sun.codemodel.internal.JFieldVar;
import com.sun.codemodel.internal.JForEach;
import com.sun.codemodel.internal.JInvocation;
import com.sun.codemodel.internal.JJavaName;
import com.sun.codemodel.internal.JMethod;
import com.sun.codemodel.internal.JMod;
import com.sun.codemodel.internal.JPackage;
import com.sun.codemodel.internal.JType;
import com.sun.codemodel.internal.JVar;
import com.sun.codemodel.internal.fmt.JStaticJavaFile;
import com.sun.tools.internal.xjc.AbortException;
import com.sun.tools.internal.xjc.ErrorReceiver;
import com.sun.tools.internal.xjc.api.SpecVersion;
import com.sun.tools.internal.xjc.generator.annotation.spec.XmlAnyAttributeWriter;
import com.sun.tools.internal.xjc.generator.annotation.spec.XmlEnumValueWriter;
import com.sun.tools.internal.xjc.generator.annotation.spec.XmlEnumWriter;
import com.sun.tools.internal.xjc.generator.annotation.spec.XmlJavaTypeAdapterWriter;
import com.sun.tools.internal.xjc.generator.annotation.spec.XmlMimeTypeWriter;
import com.sun.tools.internal.xjc.generator.annotation.spec.XmlRootElementWriter;
import com.sun.tools.internal.xjc.generator.annotation.spec.XmlSeeAlsoWriter;
import com.sun.tools.internal.xjc.generator.annotation.spec.XmlTypeWriter;
import com.sun.tools.internal.xjc.generator.bean.field.FieldRenderer;
import com.sun.tools.internal.xjc.model.CAdapter;
import com.sun.tools.internal.xjc.model.CAttributePropertyInfo;
import com.sun.tools.internal.xjc.model.CClassInfo;
import com.sun.tools.internal.xjc.model.CClassInfoParent;
import com.sun.tools.internal.xjc.model.CElementInfo;
import com.sun.tools.internal.xjc.model.CEnumConstant;
import com.sun.tools.internal.xjc.model.CEnumLeafInfo;
import com.sun.tools.internal.xjc.model.CPropertyInfo;
import com.sun.tools.internal.xjc.model.CTypeRef;
import com.sun.tools.internal.xjc.model.Model;
import com.sun.tools.internal.xjc.model.CClassRef;
import com.sun.tools.internal.xjc.outline.Aspect;
import com.sun.tools.internal.xjc.outline.ClassOutline;
import com.sun.tools.internal.xjc.outline.EnumConstantOutline;
import com.sun.tools.internal.xjc.outline.EnumOutline;
import com.sun.tools.internal.xjc.outline.FieldOutline;
import com.sun.tools.internal.xjc.outline.Outline;
import com.sun.tools.internal.xjc.outline.PackageOutline;
import com.sun.tools.internal.xjc.util.CodeModelClassFactory;
import com.sun.xml.internal.bind.v2.model.core.PropertyInfo;
import com.sun.xml.internal.bind.v2.runtime.SwaRefAdapterMarker;
import com.sun.xml.internal.xsom.XmlString;
import com.sun.istack.internal.NotNull;
import com.sun.tools.internal.xjc.model.CReferencePropertyInfo;

Generates fields and accessors.
/** * Generates fields and accessors. */
public final class BeanGenerator implements Outline {
JAXB module name. JAXB dependency is mandatory in generated Java module.
/** JAXB module name. JAXB dependency is mandatory in generated Java module. */
private static final String JAXB_PACKAGE = "java.xml.bind";
Simplifies class/interface creation and collision detection.
/** Simplifies class/interface creation and collision detection. */
private final CodeModelClassFactory codeModelClassFactory; private final ErrorReceiver errorReceiver; /** all {@link PackageOutline}s keyed by their {@link PackageOutline#_package}. */ private final Map<JPackage, PackageOutlineImpl> packageContexts = new LinkedHashMap<JPackage, PackageOutlineImpl>();
all ClassOutlines keyed by their ClassOutline.target.
/** all {@link ClassOutline}s keyed by their {@link ClassOutline#target}. */
private final Map<CClassInfo, ClassOutlineImpl> classes = new LinkedHashMap<CClassInfo, ClassOutlineImpl>();
all EnumOutlines keyed by their EnumOutline.target.
/** all {@link EnumOutline}s keyed by their {@link EnumOutline#target}. */
private final Map<CEnumLeafInfo, EnumOutline> enums = new LinkedHashMap<CEnumLeafInfo, EnumOutline>();
Generated runtime classes.
/** * Generated runtime classes. */
private final Map<Class, JClass> generatedRuntime = new LinkedHashMap<Class, JClass>();
the model object which we are processing.
/** the model object which we are processing. */
private final Model model; private final JCodeModel codeModel;
for each property, the information about the generated field.
/** * for each property, the information about the generated field. */
private final Map<CPropertyInfo, FieldOutline> fields = new LinkedHashMap<CPropertyInfo, FieldOutline>();
elements that generate classes to the generated classes.
/** * elements that generate classes to the generated classes. */
/*package*/ final Map<CElementInfo, ElementOutlineImpl> elements = new LinkedHashMap<CElementInfo, ElementOutlineImpl>();
Generates beans into code model according to the BGM, and produces the reflection model.
Params:
  • _errorReceiver – This object will receive all the errors discovered during the back-end stage.
Returns: returns a Outline which will in turn be used to further generate marshaller/unmarshaller, or null if the processing fails (errors should have been reported to the error recevier.)
/** * Generates beans into code model according to the BGM, * and produces the reflection model. * * @param _errorReceiver * This object will receive all the errors discovered * during the back-end stage. * * @return * returns a {@link Outline} which will in turn * be used to further generate marshaller/unmarshaller, * or null if the processing fails (errors should have been * reported to the error recevier.) */
public static Outline generate(Model model, ErrorReceiver _errorReceiver) { try { return new BeanGenerator(model, _errorReceiver); } catch (AbortException e) { return null; } } private BeanGenerator(Model _model, ErrorReceiver _errorReceiver) { this.model = _model; this.codeModel = model.codeModel; this.errorReceiver = _errorReceiver; this.codeModelClassFactory = new CodeModelClassFactory(errorReceiver); // build enum classes for (CEnumLeafInfo p : model.enums().values()) { enums.put(p, generateEnumDef(p)); } JPackage[] packages = getUsedPackages(EXPOSED); // generates per-package code and remember the results as contexts. for (JPackage pkg : packages) { getPackageContext(pkg); } // create the class definitions for all the beans first. // this should also fill in PackageContext#getClasses for (CClassInfo bean : model.beans().values()) { getClazz(bean); } // compute the package-level setting for (PackageOutlineImpl p : packageContexts.values()) { p.calcDefaultValues(); } JClass OBJECT = codeModel.ref(Object.class); // inheritance relationship needs to be set before we generate fields, or otherwise // we'll fail to compute the correct type signature (namely the common base type computation) for (ClassOutlineImpl cc : getClasses()) { // setup inheritance between implementation hierarchy. CClassInfo superClass = cc.target.getBaseClass(); if (superClass != null) { // use the specified super class model.strategy._extends(cc, getClazz(superClass)); } else { CClassRef refSuperClass = cc.target.getRefBaseClass(); if (refSuperClass != null) { cc.implClass._extends(refSuperClass.toType(this, EXPOSED)); } else { // use the default one, if any if (model.rootClass != null && cc.implClass._extends().equals(OBJECT)) { cc.implClass._extends(model.rootClass); } if (model.rootInterface != null) { cc.ref._implements(model.rootInterface); } } } // if serialization support is turned on, generate // [RESULT] // class ... implements Serializable { // private static final long serialVersionUID = <id>; // .... // } if (model.serializable) { cc.implClass._implements(Serializable.class); if (model.serialVersionUID != null) { cc.implClass.field( JMod.PRIVATE | JMod.STATIC | JMod.FINAL, codeModel.LONG, "serialVersionUID", JExpr.lit(model.serialVersionUID)); } } CClassInfoParent base = cc.target.parent(); if ((base != null) && (base instanceof CClassInfo)) { String pkg = base.getOwnerPackage().name(); String shortName = base.fullName().substring(base.fullName().indexOf(pkg)+pkg.length()+1); if (cc.target.shortName.equals(shortName)) { getErrorReceiver().error(cc.target.getLocator(), Messages.ERR_KEYNAME_COLLISION.format(shortName)); } } } // fill in implementation classes for (ClassOutlineImpl co : getClasses()) { generateClassBody(co); } for (EnumOutline eo : enums.values()) { generateEnumBody(eo); } // create factories for the impl-less elements for (CElementInfo ei : model.getAllElements()) { getPackageContext(ei._package()).objectFactoryGenerator().populate(ei); } if (model.options.getModuleName() != null) { codeModel._prepareModuleInfo(model.options.getModuleName(), JAXB_PACKAGE); } if (model.options.debugMode) { generateClassList(); } }
Generates a class that knows how to create an instance of JAXBContext

This is used in the debug mode so that a new properly configured JAXBContext object can be used.

/** * Generates a class that knows how to create an instance of JAXBContext * * <p> * This is used in the debug mode so that a new properly configured * {@link JAXBContext} object can be used. */
@SuppressWarnings("CallToThreadDumpStack") private void generateClassList() { try { JDefinedClass jc = codeModel.rootPackage()._class("JAXBDebug"); JMethod m = jc.method(JMod.PUBLIC | JMod.STATIC, JAXBContext.class, "createContext"); JVar $classLoader = m.param(ClassLoader.class, "classLoader"); m._throws(JAXBException.class); JInvocation inv = codeModel.ref(JAXBContext.class).staticInvoke("newInstance"); m.body()._return(inv); switch (model.strategy) { case INTF_AND_IMPL: { StringBuilder buf = new StringBuilder(); for (PackageOutlineImpl po : packageContexts.values()) { if (buf.length() > 0) { buf.append(':'); } buf.append(po._package().name()); } inv.arg(buf.toString()).arg($classLoader); break; } case BEAN_ONLY: for (ClassOutlineImpl cc : getClasses()) { inv.arg(cc.implRef.dotclass()); } for (PackageOutlineImpl po : packageContexts.values()) { inv.arg(po.objectFactory().dotclass()); } break; default: throw new IllegalStateException(); } } catch (JClassAlreadyExistsException e) { e.printStackTrace(); // after all, we are in the debug mode. a little sloppiness is OK. // this error is not fatal. just continue. } } public Model getModel() { return model; } public JCodeModel getCodeModel() { return codeModel; } public JClassContainer getContainer(CClassInfoParent parent, Aspect aspect) { CClassInfoParent.Visitor<JClassContainer> v; switch (aspect) { case EXPOSED: v = exposedContainerBuilder; break; case IMPLEMENTATION: v = implContainerBuilder; break; default: assert false; throw new IllegalStateException(); } return parent.accept(v); } public final JType resolve(CTypeRef ref, Aspect a) { return ref.getTarget().getType().toType(this, a); } private final CClassInfoParent.Visitor<JClassContainer> exposedContainerBuilder = new CClassInfoParent.Visitor<JClassContainer>() { public JClassContainer onBean(CClassInfo bean) { return getClazz(bean).ref; } public JClassContainer onElement(CElementInfo element) { // hmm... return getElement(element).implClass; } public JClassContainer onPackage(JPackage pkg) { return model.strategy.getPackage(pkg, EXPOSED); } }; private final CClassInfoParent.Visitor<JClassContainer> implContainerBuilder = new CClassInfoParent.Visitor<JClassContainer>() { public JClassContainer onBean(CClassInfo bean) { return getClazz(bean).implClass; } public JClassContainer onElement(CElementInfo element) { return getElement(element).implClass; } public JClassContainer onPackage(JPackage pkg) { return model.strategy.getPackage(pkg, Aspect.IMPLEMENTATION); } };
Returns all used JPackages. A JPackage is considered as "used" if a ClassItem or a InterfaceItem resides in that package. This value is dynamically calculated every time because one can freely remove ClassItem/InterfaceItem.
Returns: Given the same input, the order of packages in the array is always the same regardless of the environment.
/** * Returns all <i>used</i> JPackages. * * A JPackage is considered as "used" if a ClassItem or * a InterfaceItem resides in that package. * * This value is dynamically calculated every time because * one can freely remove ClassItem/InterfaceItem. * * @return * Given the same input, the order of packages in the array * is always the same regardless of the environment. */
public final JPackage[] getUsedPackages(Aspect aspect) { Set<JPackage> s = new TreeSet<JPackage>(); for (CClassInfo bean : model.beans().values()) { JClassContainer cont = getContainer(bean.parent(), aspect); if (cont.isPackage()) { s.add((JPackage) cont); } } for (CElementInfo e : model.getElementMappings(null).values()) { // at the first glance you might think we should be iterating all elements, // not just global ones, but if you think about it, local ones live inside // another class, so those packages are already enumerated when we were // walking over CClassInfos. s.add(e._package()); } return s.toArray(new JPackage[s.size()]); } public ErrorReceiver getErrorReceiver() { return errorReceiver; } public CodeModelClassFactory getClassFactory() { return codeModelClassFactory; } public PackageOutlineImpl getPackageContext(JPackage p) { PackageOutlineImpl r = packageContexts.get(p); if (r == null) { r = new PackageOutlineImpl(this, model, p); packageContexts.put(p, r); } return r; }
Generates the minimum JDefinedClass skeleton without filling in its body.
/** * Generates the minimum {@link JDefinedClass} skeleton * without filling in its body. */
private ClassOutlineImpl generateClassDef(CClassInfo bean) { ImplStructureStrategy.Result r = model.strategy.createClasses(this, bean); JClass implRef; if (bean.getUserSpecifiedImplClass() != null) { // create a place holder for a user-specified class. JDefinedClass usr; try { usr = codeModel._class(bean.getUserSpecifiedImplClass()); // but hide that file so that it won't be generated. usr.hide(); } catch (JClassAlreadyExistsException e) { // it's OK for this to collide. usr = e.getExistingClass(); } usr._extends(r.implementation); implRef = usr; } else { implRef = r.implementation; } return new ClassOutlineImpl(this, bean, r.exposed, r.implementation, implRef); } public Collection<ClassOutlineImpl> getClasses() { // make sure that classes are fully populated assert model.beans().size() == classes.size(); return classes.values(); } public ClassOutlineImpl getClazz(CClassInfo bean) { ClassOutlineImpl r = classes.get(bean); if (r == null) { classes.put(bean, r = generateClassDef(bean)); } return r; } public ElementOutlineImpl getElement(CElementInfo ei) { ElementOutlineImpl def = elements.get(ei); if (def == null && ei.hasClass()) { // create one. in the constructor it adds itself to the elements. def = new ElementOutlineImpl(this, ei); } return def; } public EnumOutline getEnum(CEnumLeafInfo eli) { return enums.get(eli); } public Collection<EnumOutline> getEnums() { return enums.values(); } public Iterable<? extends PackageOutline> getAllPackageContexts() { return packageContexts.values(); } public FieldOutline getField(CPropertyInfo prop) { return fields.get(prop); }
Generates the body of a class.
/** * Generates the body of a class. * */
private void generateClassBody(ClassOutlineImpl cc) { CClassInfo target = cc.target; // used to simplify the generated annotations String mostUsedNamespaceURI = cc._package().getMostUsedNamespaceURI(); // [RESULT] // @XmlType(name="foo", targetNamespace="bar://baz") XmlTypeWriter xtw = cc.implClass.annotate2(XmlTypeWriter.class); writeTypeName(cc.target.getTypeName(), xtw, mostUsedNamespaceURI); if (model.options.target.isLaterThan(SpecVersion.V2_1)) { // @XmlSeeAlso Iterator<CClassInfo> subclasses = cc.target.listSubclasses(); if (subclasses.hasNext()) { XmlSeeAlsoWriter saw = cc.implClass.annotate2(XmlSeeAlsoWriter.class); while (subclasses.hasNext()) { CClassInfo s = subclasses.next(); saw.value(getClazz(s).implRef); } } } if (target.isElement()) { String namespaceURI = target.getElementName().getNamespaceURI(); String localPart = target.getElementName().getLocalPart(); // [RESULT] // @XmlRootElement(name="foo", targetNamespace="bar://baz") XmlRootElementWriter xrew = cc.implClass.annotate2(XmlRootElementWriter.class); xrew.name(localPart); if (!namespaceURI.equals(mostUsedNamespaceURI)) // only generate if necessary { xrew.namespace(namespaceURI); } } if (target.isOrdered()) { for (CPropertyInfo p : target.getProperties()) { if (!(p instanceof CAttributePropertyInfo)) { if (!((p instanceof CReferencePropertyInfo) && ((CReferencePropertyInfo) p).isDummy())) { xtw.propOrder(p.getName(false)); } } } } else { // produce empty array xtw.getAnnotationUse().paramArray("propOrder"); } for (CPropertyInfo prop : target.getProperties()) { generateFieldDecl(cc, prop); } if (target.declaresAttributeWildcard()) { generateAttributeWildcard(cc); } // generate some class level javadoc cc.ref.javadoc().append(target.javadoc); cc._package().objectFactoryGenerator().populate(cc); } private void writeTypeName(QName typeName, XmlTypeWriter xtw, String mostUsedNamespaceURI) { if (typeName == null) { xtw.name(""); } else { xtw.name(typeName.getLocalPart()); final String typeNameURI = typeName.getNamespaceURI(); if (!typeNameURI.equals(mostUsedNamespaceURI)) // only generate if necessary { xtw.namespace(typeNameURI); } } }
Generates an attribute wildcard property on a class.
/** * Generates an attribute wildcard property on a class. */
private void generateAttributeWildcard(ClassOutlineImpl cc) { String FIELD_NAME = "otherAttributes"; String METHOD_SEED = model.getNameConverter().toClassName(FIELD_NAME); JClass mapType = codeModel.ref(Map.class).narrow(QName.class, String.class); JClass mapImpl = codeModel.ref(HashMap.class).narrow(QName.class, String.class); // [RESULT] // Map<QName,String> m = new HashMap<QName,String>(); JFieldVar $ref = cc.implClass.field(JMod.PRIVATE, mapType, FIELD_NAME, JExpr._new(mapImpl)); $ref.annotate2(XmlAnyAttributeWriter.class); MethodWriter writer = cc.createMethodWriter(); JMethod $get = writer.declareMethod(mapType, "get" + METHOD_SEED); $get.javadoc().append( "Gets a map that contains attributes that aren't bound to any typed property on this class.\n\n" + "<p>\n" + "the map is keyed by the name of the attribute and \n" + "the value is the string value of the attribute.\n" + "\n" + "the map returned by this method is live, and you can add new attribute\n" + "by updating the map directly. Because of this design, there's no setter.\n"); $get.javadoc().addReturn().append("always non-null"); $get.body()._return($ref); }
Generates the minimum JDefinedClass skeleton without filling in its body.
/** * Generates the minimum {@link JDefinedClass} skeleton * without filling in its body. */
private EnumOutline generateEnumDef(CEnumLeafInfo e) { JDefinedClass type; type = getClassFactory().createClass( getContainer(e.parent, EXPOSED), e.shortName, e.getLocator(), ClassType.ENUM); type.javadoc().append(e.javadoc); return new EnumOutline(e, type) { @Override public @NotNull Outline parent() { return BeanGenerator.this; } }; } private void generateEnumBody(EnumOutline eo) { JDefinedClass type = eo.clazz; CEnumLeafInfo e = eo.target; XmlTypeWriter xtw = type.annotate2(XmlTypeWriter.class); writeTypeName(e.getTypeName(), xtw, eo._package().getMostUsedNamespaceURI()); JCodeModel cModel = model.codeModel; // since constant values are never null, no point in using the boxed types. JType baseExposedType = e.base.toType(this, EXPOSED).unboxify(); JType baseImplType = e.base.toType(this, Aspect.IMPLEMENTATION).unboxify(); XmlEnumWriter xew = type.annotate2(XmlEnumWriter.class); xew.value(baseExposedType); boolean needsValue = e.needsValueField(); // for each member <m>, // [RESULT] // <EnumName>(<deserializer of m>(<value>)); Set<String> enumFieldNames = new HashSet<String>(); // record generated field names to detect collision for (CEnumConstant mem : e.members) { String constName = mem.getName(); if (!JJavaName.isJavaIdentifier(constName)) { // didn't produce a name. getErrorReceiver().error(e.getLocator(), Messages.ERR_UNUSABLE_NAME.format(mem.getLexicalValue(), constName)); } if (!enumFieldNames.add(constName)) { getErrorReceiver().error(e.getLocator(), Messages.ERR_NAME_COLLISION.format(constName)); } // [RESULT] // <Const>(...) // ASSUMPTION: datatype is outline-independent JEnumConstant constRef = type.enumConstant(constName); if (needsValue) { constRef.arg(e.base.createConstant(this, new XmlString(mem.getLexicalValue()))); } if (!mem.getLexicalValue().equals(constName)) { constRef.annotate2(XmlEnumValueWriter.class).value(mem.getLexicalValue()); } // set javadoc if (mem.javadoc != null) { constRef.javadoc().append(mem.javadoc); } eo.constants.add(new EnumConstantOutline(mem, constRef) { }); } if (needsValue) { // [RESULT] // final <valueType> value; JFieldVar $value = type.field(JMod.PRIVATE | JMod.FINAL, baseExposedType, "value"); // [RESULT] // public <valuetype> value() { return value; } type.method(JMod.PUBLIC, baseExposedType, "value").body()._return($value); // [RESULT] // <constructor>(<valueType> v) { // this.value=v; // } { JMethod m = type.constructor(0); m.body().assign($value, m.param(baseImplType, "v")); } // [RESULT] // public static <Const> fromValue(<valueType> v) { // for( <Const> c : <Const>.values() ) { // if(c.value == v) // or equals // return c; // } // throw new IllegalArgumentException(...); // } { JMethod m = type.method(JMod.PUBLIC | JMod.STATIC, type, "fromValue"); JVar $v = m.param(baseExposedType, "v"); JForEach fe = m.body().forEach(type, "c", type.staticInvoke("values")); JExpression eq; if (baseExposedType.isPrimitive()) { eq = fe.var().ref($value).eq($v); } else { eq = fe.var().ref($value).invoke("equals").arg($v); } fe.body()._if(eq)._then()._return(fe.var()); JInvocation ex = JExpr._new(cModel.ref(IllegalArgumentException.class)); JExpression strForm; if (baseExposedType.isPrimitive()) { strForm = cModel.ref(String.class).staticInvoke("valueOf").arg($v); } else if (baseExposedType == cModel.ref(String.class)) { strForm = $v; } else { strForm = $v.invoke("toString"); } m.body()._throw(ex.arg(strForm)); } } else { // [RESULT] // public String value() { return name(); } type.method(JMod.PUBLIC, String.class, "value").body()._return(JExpr.invoke("name")); // [RESULT] // public <Const> fromValue(String v) { return valueOf(v); } JMethod m = type.method(JMod.PUBLIC | JMod.STATIC, type, "fromValue"); m.body()._return(JExpr.invoke("valueOf").arg(m.param(String.class, "v"))); } }
Determines the FieldRenderer used for the given FieldUse, then generates the field declaration and accessor methods. The fields map will be updated with the newly created FieldRenderer.
/** * Determines the FieldRenderer used for the given FieldUse, * then generates the field declaration and accessor methods. * * The <code>fields</code> map will be updated with the newly * created FieldRenderer. */
private FieldOutline generateFieldDecl(ClassOutlineImpl cc, CPropertyInfo prop) { FieldRenderer fr = prop.realization; if (fr == null) // none is specified. use the default factory { fr = model.options.getFieldRendererFactory().getDefault(); } FieldOutline field = fr.generate(cc, prop); fields.put(prop, field); return field; }
Generates XmlJavaTypeAdapter from PropertyInfo if necessary. Also generates other per-property annotations (such as XmlID, XmlIDREF, and XmlMimeType if necessary.
/** * Generates {@link XmlJavaTypeAdapter} from {@link PropertyInfo} if necessary. * Also generates other per-property annotations * (such as {@link XmlID}, {@link XmlIDREF}, and {@link XmlMimeType} if necessary. */
public final void generateAdapterIfNecessary(CPropertyInfo prop, JAnnotatable field) { CAdapter adapter = prop.getAdapter(); if (adapter != null) { if (adapter.getAdapterIfKnown() == SwaRefAdapterMarker.class) { field.annotate(XmlAttachmentRef.class); } else { // [RESULT] // @XmlJavaTypeAdapter( Foo.class ) XmlJavaTypeAdapterWriter xjtw = field.annotate2(XmlJavaTypeAdapterWriter.class); xjtw.value(adapter.adapterType.toType(this, EXPOSED)); } } switch (prop.id()) { case ID: field.annotate(XmlID.class); break; case IDREF: field.annotate(XmlIDREF.class); break; } if (prop.getExpectedMimeType() != null) { field.annotate2(XmlMimeTypeWriter.class).value(prop.getExpectedMimeType().toString()); } } public final JClass addRuntime(Class clazz) { JClass g = generatedRuntime.get(clazz); if (g == null) { // put code into a separate package to avoid name conflicts. JPackage implPkg = getUsedPackages(Aspect.IMPLEMENTATION)[0].subPackage("runtime"); g = generateStaticClass(clazz, implPkg); generatedRuntime.put(clazz, g); } return g; } public JClass generateStaticClass(Class src, JPackage out) { JStaticJavaFile sjf = new JStaticJavaFile(out, getShortName(src), src, null); out.addResourceFile(sjf); return sjf.getJClass(); } private String getShortName(Class src) { String name = src.getName(); return name.substring(name.lastIndexOf('.') + 1); } }