Hi Dmitry,
In your example:
>...one can simply write:
>
>Concept concept = new Concept();
>concept.getRelationsAsList().add(new Relation());"
But couldn't this be achieved via the existing fluent API, like below ?
Concept concept = new Concept().withRelations(
new Relations().withRelation(new Relation()));
Hanson
2009/9/14 Dmitry Katsubo <dma_k_at_mail.ru>
> Dear Hanson!
>
> I am writing to you because I have certain ideas about how to extend
> fluent API plugin with some functionality which I find interesting.
>
> I do attach a source code which express my ideas. JavaDoc includes some
> examples of what I want to be generated as the output.
>
> Please, let me know, if you find the idea interesting. I can also
> prepare a patch for XjcFluentApiPlugin.java if you agree to include it
> to this plugin.
>
> Also I face some problems, which I have mentioned here:
>
> http://forums.java.net/jive/thread.jspa?messageID=362952#268266
>
> and I also need this extension for JAXB API (which is very easy to add):
>
> https://jaxb.dev.java.net/issues/show_bug.cgi?id=561
>
> How can I influence the developers team?
>
> Any feedback is very welcome, as your opinion is important for me.
>
> Thanks in advance!
>
>
> package com.sun.tools.xjc.addon.list_getter;
>
> import java.util.Collection;
> import java.util.List;
> import java.util.logging.Level;
> import java.util.logging.Logger;
>
> import com.sun.codemodel.JClass;
> import com.sun.codemodel.JDefinedClass;
> import com.sun.codemodel.JExpr;
> import com.sun.codemodel.JFieldVar;
> import com.sun.codemodel.JMethod;
> import com.sun.codemodel.JMod;
> import com.sun.codemodel.JOp;
> import com.sun.codemodel.JType;
> import com.sun.tools.xjc.Options;
> import com.sun.tools.xjc.Plugin;
> import com.sun.tools.xjc.outline.ClassOutline;
> import com.sun.tools.xjc.outline.Outline;
>
> import org.xml.sax.ErrorHandler;
>
> /**
> * This plugin generates getters for the types, which contain collections.
> These types are usually nested classes, which
> * are handy to be instantiated in the getter. For example, for the XSD
> below:
> *
> * <pre>
> * <complexType name="concept">
> * <complexContent>
> * <sequence>
> * <element name="id" type="..." />
> * ...
> * <element name="relations">
> * <complexType>
> * <complexContent>
> * <sequence>
> * <element name="relation"
> type="{...}relation" maxOccurs="unbounded"/>
> * </sequence>
> * </complexContent>
> * </complexType>
> * </element>
> * </sequence>
> * </complexContent>
> * </complexType>
> * </pre>
> *
> * the following code will be generated:
> *
> * <pre>
> * public class Concept {
> * List<Relation> getRelationsAsList() {
> * if (relations == null) {
> * relations = new Concept.Relations();
> * }
> *
> * return relations.getRelation();
> * }
> * </pre>
> *
> * which makes the coding easier. Now instead of:
> *
> * <pre>
> * Concept concept = new Concept();
> * Concept.Relations relations = new Concept.Relations();
> * concept.setRelations(relations);
> * relations.getRelation().add(new Relation());
> * </pre>
> *
> * one can simply write:
> *
> * <pre>
> * Concept concept = new Concept();
> * concept.getRelationsAsList().add(new Relation());
> * </pre>
> *
> * @author <a href="mailto:dmitry.katsubo_at_gmail.com">Dmitry Katsubo</a>
> */
> public class ListGetterPlugin extends Plugin {
>
> private static final Logger logger =
> Logger.getLogger(ListGetterPlugin.class.getName());
>
> @Override
> public String getOptionName() {
> return "Xlist-getter";
> }
>
> @Override
> public String getUsage() {
> return " -Xlist-getter : generate getters for
> lists";
> }
>
> private static final String GETTER_METHOD_PREFIX = "get";
>
> private static final String GETTER_METHOD_SUFFIX = "AsList";
>
> @Override
> public boolean run(Outline outline, Options opt, ErrorHandler
> errorHandler) {
>
> logger.setLevel(opt.verbose ? Level.INFO : Level.WARNING);
>
> // For all generated classes:
> for (final ClassOutline classOutline : outline.getClasses())
> {
> final JDefinedClass targetClass =
> classOutline.implClass;
>
> // Check annotations for targetClass: name should
> not be empty for XmlType:
> // @XmlType(name = "someName")
>
> logger.info("Checking the outline class " +
> targetClass.name());
>
> for (final JFieldVar field :
> targetClass.fields().values()) {
>
> // If this class field is not type of class
> (e.g. primitive or array), then we skip it:
> if (!(field.type() instanceof
> JDefinedClass)) {
> continue;
> }
>
> if (field.name().startsWith("_")) {
> continue;
> }
>
> final JDefinedClass fieldType =
> (JDefinedClass) field.type();
>
> logger.info("Checking the class " +
> fieldType.fullName() + " of the field " + field.name());
>
> int count = 0;
>
> for (final JMethod fieldTypeMethod :
> fieldType.methods()) {
> // For each getter method of the
> field's class we
> JType methodReturnType =
> getReturnTypeOfListGetter(fieldTypeMethod);
>
> if (methodReturnType == null) {
> continue;
> }
>
> final JMethod jgetterMethod =
> targetClass.method(JMod.PUBLIC, methodReturnType,
> GETTER_METHOD_PREFIX
> + firstLetterToUpperCase(field.name()) + GETTER_METHOD_SUFFIX
> +
> (count++ == 0 ? "" : "_" + count));
>
>
> jgetterMethod.body()._if(JOp.eq(field,
> JExpr._null()))._then().assign(JExpr.ref(null, field),
>
> JExpr._new(fieldType));
>
> jgetterMethod.body()._return(JExpr.invoke(field, fieldTypeMethod));
> }
> }
> }
>
> return false;
> }
>
> private static String firstLetterToUpperCase(String name) {
> return name.substring(0, 1).toUpperCase() +
> name.substring(1);
> }
>
> /**
> * The same as {_at_link
> com.sun.tools.xjc.addon.fluent_api.XjcFluentApiPlugin#isListGetterMethod(JMethod)}
> but also
> * returns the return type of this method.
> */
> private static JType getReturnTypeOfListGetter(JMethod method) {
> final int mods = method.mods().getValue();
>
> // check if it is a non-static public method
> if ((mods & JMod.STATIC) == 1 || (mods & JMod.PUBLIC) == 0)
> {
> return null;
> }
>
> final String methodName = method.name();
>
> // See if the method name looks like a getter method
> if (methodName.length() <= GETTER_METHOD_PREFIX.length() ||
> !methodName.startsWith(GETTER_METHOD_PREFIX)) {
> return null;
> }
>
> // A list getter method will have no argument.
> if (method.listParams().length > 0) {
> return null;
> }
>
> // See if the return type of the method is a Collection:
> JType methodReturnType = method.type();
>
> if (!(methodReturnType instanceof JClass)) {
> return null;
> }
>
> JClass classType = (JClass) methodReturnType;
>
> do {
> logger.info("Checking return type " +
> classType.fullName() + " of the method " + method.name());
>
> if
> (classType.fullName().startsWith(Collection.class.getName())
> ||
> classType.fullName().startsWith(List.class.getName())) {
> return methodReturnType;
> }
>
> classType = classType._extends();
> } while (classType != null);
>
> return null;
> }
> }
>
>
>