JXB How to use different strategies of code generation - jaxb

usually, JAXB is used to generate code from an xsd, which generates java classes for xsd complexType with annotations to convert it to xml and vice-versa.
I am trying to achieve something different. I want, to generate a data mapper class for each such xsd element. The mapper will map each field of the generated class with values from another datatype (say from database, or other stream)
so i need to: for every user-defined datatype in xsd, add a method in a DataMapper class map-<XSD-ComplexDataType-Class>() and generate method body.
to achieve this, i think it is not possible to generate this class in a Plugin extending com.sun.tools.internal.xjc.Plugin as in the run method, i wont be able to create a new JDefinedClass
is there any way to add a hook method before Model invokes Plugins ?
thanks,

There are a few things you can do. In my other answer I specificaly meant these:
In a plugin you can write and set your own com.sun.tools.xjc.generator.bean.field.FieldRendererFactory. Field renderers generate a FieldOutlines from CPropertyInfos. This is a step between the model and the outline. So if you want different code generated out of the model, consider implementing your own FieldRendererFactory. You can register a FieldRendererFactory via XJC plugin (see Options.setFieldRendererFactory(...)).
On the class level, you can write your own com.sun.tools.xjc.generator.bean.BeanGenerator and use it for code generation.
You can just use model and generate the code completely on your own. I do this in Jsonix when I produce JavaScript mappings for XML<->JSON.
As for your specific task, I would actually just postprocess the code model in the run method of your plugin. You have everything there - the model, the outline and also the code model (see outline.getCodeModel()). And you can definitely create your JDefinedClasses there, the code model exists already.

Related

How/When is the Groovy MetaClassRegistry populated?

I read that every POJO used in Groovy gets a MetaClass associated with it. These meta-classes are stored in the application wide metaclass registry. How are these meta-classes generated and placed in the meta-class registry? If each POJO gets its own meta-class, is there some sort of template that is used to generate these meta-classes?
I read that every POJO used in Groovy gets a MetaClass associated with
it.
FYI... It isn't just POJO. Every class has a meta class associate with it.
These meta-classes are stored in the application wide metaclass
registry.
That registry is represented in groovy.lang.MetaClassRegistry. You can get a reference to the registry from GroovySystem.html#getMetaClassRegistry().
How are these meta-classes generated and placed in the meta-class
registry?
There is no one way. You can write your own custom meta class and register it, Groovy registers default meta classes, you could replace a metaClass in the registry momentarily (while a unit test runs, for example) and then replace it with the original one after.
At runtime you could use methods like MetaClassRegistry.html#getMetaClass(java.lang.Class), MetaClassRegistry.html#setMetaClass(java.lang.Class,groovy.lang.MetaClass), and MetaClassRegistry.html#removeMetaClass(java.lang.Class) to manipulate the registry.
If each POJO gets its own meta-class, is there some sort of template
that is used to generate these meta-classes?
docs.groovy-lang.org/latest/html/api/groovy/lang/MetaClass is the closest thing to a template but aside from satisfying standard compile time restrictions of having to implement all the abstract methods, there could be any arbitrary logic in a meta class one might write.

Unmarshall to an existing model

Based on this example Keep child-parent relationship after unmarshalling I'd like to know if it's possible to unmarshall xml file into an existing model (not having the JAXB annotations). My idea is to directly unmarshall into Primefaces Menu Model (https://www.primefaces.org/docs/api/6.0/org/primefaces/model/menu/package-summary.html). Is it possible?
JAXB is configuration by exception, so if your model matches the xml, annotations are not necessary.
Here a blog post and a stackoverflow answer by Blaise Doughan on the topic.
It is possible (if your model is straightforward enough to be JAXB-compatible or with MOXy external mappings), but I would really not recommend it.
If you map to existing model, your XML representation becomes dependent on this existing model. And should the existing model change (like, you update the version of the library you use), you won't be able to unmarshal existing XML and will need migration mechanisms.
From my point of view, it is better to write an XML Schema and compile it to schema-derived classes. Then have a conversion routine to transfrom unmarshalled object structure to the target existing model.

JAXB how to remove anything from JDefinedClass

i am using jaxb to generate code from an xsd.
The generated code contains a lot of annotations; for classes and fields.
I am trying to use com.sun.tools.internal.xjc.Plugin to modify the generated code.
In the plugin run() method we are given an Outline class from which we can get ClassOutline. ClassOutline has an JDefinedClass final member which has the info about actual class which will be generated.
If i want to add anything, there are apis in JDefinedClass which can be used. But if i want to remove something, there is no way.
e.g. i cannot clear annotations, because the JDefinedClass.annotations() method returns an UnmodifiableCollection. so i cannot clear it or remove anything from it.
i tried to create another JDefinedClass by invoking the _class method but the ClassOutline.implClass variable is final, so i cannot set it.
how to get a JDefinedClass which does not have any annotations?
is there another phase of code generation which i can trap into to really control the generation of JDefinedClass?
The code model is, indeed mostly "write only". But, speaking of annotations, you have probably missed the methods like com.sun.codemodel.JDefinedClass.removeAnnotation(JAnnotationUse) and com.sun.codemodel.JMethod.removeAnnotation(JAnnotationUse) (implemented from com.sun.codemodel.JAnnotatable.removeAnnotation(JAnnotationUse)).
So they're there. You can remove annotations with the normal CodeModel API.
As I can see, you can also remove fields and methods from classes. So what exactly are you missing?
JDefinedClass.annotations() It return an unmodifiable collection object and you cannot modify them.
So work around for this, you can restrict annotation addition/deletion at class and field level before building JCodeModel.
You need to create a custom Jackson2Annotator class which extends Jackson2Annotator and override their methods according to your requirement.
Following are few methods which are being used for specific type of annotation property:
propertyOrder(OTB JsonPropertyOrder)
propertyInclusion(OTB JsonInclude)
propertyField(can be used for custom defined annotation at field level)
More you can discover by looking Jackson2Annotator class what fit into your need.

How to document a type in enunciate?

How to get the description field on a type populated in the generated enunciate documentation?
We are generating classes from jaxb using jaxb2-maven-plugin. No matter how I document a element either using the <xsd:documentation></xsd:documentation> or the
<xsd:appinfo>
<jaxb:class>
<jaxb:javadoc>
</jaxb:javadoc>
</jaxb:class>
</xsd:appinfo>
it is overwritten in the generated classes. Can I somehow disable the this auto-generated javadoc from this plugin? Or what does enunciate really expect me to do let me document on a field level?
Note that the comment I write on class-level/type does show up in the generated class and in the enunciated generated documentation.
We are using enunciate (v.1.26.2) and jaxb2-maven-plugin (v. 1.5)
So you're wondering how to get Enunciate to not use the Javadocs on the class?
One way might be to compile the JAXB-generated classes and run Enunciate against the compiled classes instead of the source code.

Using SubSonic, how to add a field to a pre-defined class?

I've got a SubSonic DAL - works great.
Two classes: TblReceipt and TblReceiptLineItems.
I can create a parallel class of TblReceipt, but seems like a waste, so here's what I need to do:
Have a Class TblReceipt with one additional member, "ReceiptLineItems" - which is simply an ArrayList. This array list will be populated with TblReceiptLineItems types.
So for each Receipt, there are 1..* ReceiptLineItems stored in the array, then the whole thing is serialized.
How can I accomplish this with my existing SubSonic DAL?
A quick code sample would be useful too.
Thank you.
Use a partial class. All classes in Subsonic are defined as partial. What you do is (in a separate file than the one that is generated by Subsonic), you create another part of the partial class with the additional property.
Option 2 here:
http://jamesewelch.wordpress.com/2008/09/24/how-to-use-custom-audit-fields-with-subsonic/

Resources