Insert additional fields in JAXB marshalling - jaxb

When marshaling some objects into XML, I need to insert an additional field in each of the resulting XML objects - sort of flag. The purpose is not modifying the source objects but inserting that information in the output XML.
Any ideas if this is possible?

There are a few possible approaches:
1. Use an XmlAdapter
You could leverage JAXB's XmlAdapter. Here you would create a version of the classes with the extra field (the adapted classes could extend the original). Then convert between them in the adapter. Since the alternate version of the class would contain the extra field it would marshal out.
http://bdoughan.blogspot.com/2010/07/xmladapter-jaxbs-secret-weapon.html
2. Use Binder
If you marshal target is DOM, then you could leverage JAXB's Binder. It is intended for infoset preservation, but after a marshal it does maintain a link between the objects and the DOM nodes. Once the marshal is complete you could use the binder to find an object's associated node and update it.
http://bdoughan.blogspot.com/2010/09/jaxb-xml-infoset-preservation.html
3. Wrap the Output Target
If your output target is something like a ContentHandler or XMLStreamWriter then when the appropriate state is reached you could trigger additional events to be called on the nested marshal target.

The easiest way I can think of would be to use JAXB to marshal to a DOM, and then programmatically insert your extra information into that DOM, then re-marshal the DOM to XML.
Ugly and inefficient, but that's the best I can think of.

Related

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.

JXB How to use different strategies of code generation

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.

Can we get declared properties of a Groovy class by its order?

I created a plain Groovy class (i.e Person class)with some properties. Now I want to get those declared attributes (which I've defined in my class) with their order, but I don't know how to do it.
I've tried to use Person.metaClass.getProperties() but it retrieves not only declared properties but also built-in Groovy ones.
Could you please help me on this: just get declared properties by its order when declaring.
Thank you so much!
I can't see a use case, but the compiler could reorder all fields declaration while creating bytecode. I'm pretty sure ordering is not a constraint on fields though it should mostly be the case for not modified/enhanced class
As per the JVM spec, generated fields should be marked SYNTHETIC (like generated methods) in the bytecode, so you can test with :
Person.getDeclaredFields().grep { !it.synthetic }
and filter the base Groovy fields like ClassInfo,metaClass and others beginning by __timestamp
But I'm not a specialist, there could be another way I don't think of
There was a question about this on the mailing list back in February of this year
The answer is, no. There is no way to get properties in the order they are declared in the class without doing some extra work.
You could parse the source file for the class, and generate an ordered list of property names from that
You could write a custom annotation, and annotate the fields with this annotation ie: #Order(1) String prop
You could make all of the classes where this matters implement an interface which forces them to have a method that returns the names of the properties in order.
Other than that, you probably want to have a re-think :-(

JAXB marshaling: how to include exceptions info into xml output file?

I have a very basic application that uses JAXB marshaller to validate input information against an xsd schema. I register a validation event handler to obtain information about the exceptions. What I would like to achieve is the ability to include this information into xml output structure I receive as a result of marshaling. I’ve included exception collection section into my xsd and now I can instantiate the corresponding exception object once an exception is encountered. The question is how do I attach this object to the rest of my JAXB generated Java objects structure considering the fact that marshaling process had already started? Is it even possible? Or should I try and modify the xml result after the marshaling is done? Any advice would be highly appreciated.
Thanks!
There a couple of ways to do this:
Option #1 - Add an "exceptions" Property to You Root Object
Ensure that the exceptions property is marshalled last, this can be configured using propOrder on the #XmlType annotation.
Create a validation handler that holds onto the root object.
When the validation handler encounters an exception, add that exception to the exceptions property on the root object.
Option #2 - Use an XMLStreamWriter
Create an XMLStreamWriter
Write out a root element
Set the validation handler on the marshaller, ensure that it will store the exceptions encountered.
Marshal the root object to the XMLStreamWriter.
Marshal the individual exceptions encountered to the XMLStreamWriter.
Write out the close for the root element.
Short answer: no. JAXB is intended to take an object graph and produce XML. it's not intended to do this.
Longer answer: You could inject the exception representation into the graph after JAXB is done the first time.
Even longer answer: There are a number of plugin and customization technologies for JAX-B, and it's possible that you could use one of them. However, it's very hard to conceptualize this at the abstract level of your question.

Resources