Keep child-parent relationship after unmarshalling - jaxb

Here is an example of what I'm trying to unmarshall with JAXB:
<?xml version="1.0" encoding="UTF-8"?>
<menus>
<menu>
<name>main</name>
<subMenu>
<name>mainMenu</name>
<!-- Transfer / Versement -->
<subMenu>
<name>transfer</name>
<label>MENU_TRANSFER</label>
<icon>call-received</icon>
<menuItem>
<name>record</name>
<label>MENU_RECORD</label>
<url>/pages/record/search/recordListSearchResult.jsf</url>
</menuItem>
<menuItem>
<name>transferInput</name>
<label>MENU_TRANSFER_OPEN</label>
<url>/pages/transfer/open/transferListOpen.jsf</url>
</menuItem>
</subMenu>
</menu>
</menus>
Once unmarshalled, with java generated code, I want to be able to retrieve the submenu parent of a menuItem (without having to use loop etc.) Basically, I want to generate a getter getParent on MenuItem returning his parent. Is there an easy way to do this?

You can use Unmarshal Event Callbacks to receive parent object in the instance of your mapped class after unmarshalling. To do this simply add a method with the following signature:
void afterUnmarshal(Unmarshaller unmarshaller, Object parent);
Thus you'll get the parent submenu in the child submenu after unmarshalling.
If your mapped classes are schema-derived (for example you compile some XML schema with XJC), you can use the code injector plugin to add code to generated classes.
I also think there should be XJC plugins for handling parent objects (google XJC or JAXB parent plugin).

Related

Generating JAXB classes for XML having same parent tag

I am getting xml input where parent tag is same but other tags are different.
every parent tag has attribute type which tells what content you should read.
i have created jaxb classes under different packages based on xml content ,
now problem is as parent class name is same for all ,so while making instance of JAXBContext ,which parent class should i passed ?
while marshelling we can specify if this is my tag then renamed to abc tag by passing annotation {name="abc"} , in same fashion what if i changed parent class name and based on annotation jaxb will unmarshel the xml
I got answer of this. i used binding file. where we can mentioned what should be name of generated class for particular tag.
<jxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jxb:bindings schemaLocation="attribute.xsd">
<jxb:bindings node="//xs:element[#name='component']">
<jxb:class name="MyOwnClass"/>
</jxb:bindings>
</jxb:bindings>

jsf custom component declaring mandatory attribute

I want to create a custom component in JSF and have created it already.Now I want to create attributes for that custom tag that i use in the XHTML file and make them as mandatory.
I have created a component MyJSFComponent extending from UIOutput class. How can i mandate certain attributes?
You don't do that in the UIComponent side, but in the .taglib.xml or TagHandler side.
In the .taglib.xml file you can just add a <required>true</required> entry to the attribute.
<attribute>
<name>foo</name>
<required>true</required>
<type>java.lang.String</type>
</attribute>
You're however dependent on the tooling (the editor) whether this will cause an error or not. JSF/Facelets namely won't check it during runtime. Eclipse for example will automatically inline the attribute when autocompleting the tag in the editor, however it's possible to remove it afterwards and it'll run without errors.
A more solid enforcement is using a ComponentHandler class which offers the getRequiredAttribute() method which would throw TagException when absent. You can then register this handler in .taglib.xml file as follows:
<component>
<component-type>com.example.SomeComponent</component-type>
<handler-class>com.example.SomeComponentHandler</handler-class>
</component>
Whereby the handler class basically look like this:
public class SomeComponentHandler extends ComponentHandler {
public SomeComponentHandler(ComponentConfig config) {
super(config);
getRequiredAttribute("foo");
}
}
This does a real runtime check on the presence of the attribute.

EclipseLink MOXy: Suppress xsi:type when marshalling

I have a bindings file with the following content:
<java-type name="JavaType">
<xml-root-element name="root"/>
<java-attributes>
...
</java-attributes>
</java-type>
When I marshall the JavaType class using this binding, the XML looks like this
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="JavaType">
I don't want the xsi:type to be there, how can I suppress this when marshalling?
The xsi:type attribute will appear when you are marshalling a subclass. You can have it be suppressed by wrapping your object in a JAXBElement that supplies information about the root element including type.
JAXBElement<JavaType> je = new JAXBElement(new QName(), JavaType.class javaType);
marshaller.marshal(je, System.out);
Example
Is there a possibility to hide the "#type" entry when marshalling subclasses to JSON using EclipseLink MOXy (JAXB)?
UPDATE
Thanks. I now made the superclass XmlTransient, which makes the
xsi:type disapear as well. I used the annotation to do that. Is there
actually a way to use to make a java-type be
transient? I could only make it work for java-attributes.
You are correct. You can use #XmlTransient at the class level to have it removed from the inheritance hierarchy. Below is how this can be done using MOXy's external mapping document.
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
package-name="com.example.foo">
<java-types>
<java-type name="Foo" xml-transient="true"></java-type>
</java-types>
</xml-bindings>
For More Information
http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html
I tried #blaise-doughan's suggestion and added the #XmlTransient annotation to top of my abstract base class.
With my environment (so my product depends something strictly), the jaxb-api library says "The annotation #XmlTransient is disallowed for this location" because of the version of it high probably older than 2.1. I realized that when I tried to adding the annotation with a new test class-path which contains version >=2.1, so it allows to defining it top of a class.
So let me get straight to the point, I suggest below method in order to get rid of the type fields which appears on responses which are building and marshaling from extended classes.
I only added #XmlDiscriminatorNode("") to top of my base class and I supposed that you are using the EclipseLink MOXy:
import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorNode;
#XmlDiscriminatorNode("")
public abstract class Base {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
As a summary you can use #XmlTransient if you have the jaxb-api version greater than 2.1 or use my method if you have EclipseLink MOXy.

Mule ESB JAXB XML To Object Transformer Better Way?

Mule 3.3 can automatically unmarshall an XML string to an object using JAXB given that:
1. you first register your jaxb annotated classes with spring.
2. there is a component that requires such type as input
So I have managed to do the transformation, but I had to create a "DumbTransformer" that does nothing. It has a method that returns the same object it receives. I need it in order to trigger the XML to Object conversion so that I can further process the message.
Flow Example:
<spring:beans>
<spring:bean id="dumbTransformer" class="foo.bar.DumbTransformer"/>
</spring:beans>
<flow name="main" doc:name="main">
<vm:inbound-endpoint path="in" doc:name="VM" />
<component doc:name="Java">
<spring-object bean="dumbTransformer"/>
</component>
<splitter expression="#[payload.items]" doc:name="Split Items"/>
<logger message="#[payload]" level="INFO" doc:name="Log Item"/>
<vm:outbound-endpoint path="out" doc:name="VM" />
</flow>
DumbTransformer.java
package foo.bar;
#ContainsTransformerMethods
public class InvoiceUnmarshaller extends AbstractTransformer {
#Transformer
public MyJaxbAnnotatedClass foo(#Payload MyJaxbAnnotatedClass i) {
return i;
}
}
Is there a way to acomplish this without having to create such DumbTransformers?
Thanks.
As you guessed it, the JAXB deserialization doesn't occur because there is no component to satisfy:
there is a component that requires such type as input
So what if you had an auto-transformer to do just that:
<auto-transformer returnClass="foo.bar.MyJaxbAnnotatedClass" />
The Mule XML Module provides OOTB a JAXB Transformer. I would rather leverage mule capabilities whenever possible rather than writing custom code

JAXB Marshalling - extending an existing class

I am in need of creating a series of Java objects via XML using JAXB that all extend a common base class that is already created (not using JAXB). For example, let's say I have following JAXB classes that I am trying to generate:
Penguin.xml -> Penguin.java
Robin.xml -> Robin.java
Cardinal.xml -> Cardinal.java
I already have an existing base class called Bird.java that I wish the three classes above to extend.
What is the best way to do this?
Thanks for your help!
That is very simple: you need to to create a JAXB binding file with following contents:
<jaxb:bindings version="1.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
>
<jaxb:globalBindings>
<!-- All beans should extend this base class: -->
<xjc:superClass name="org.mycompany.common.Bird" />
</jaxb:globalBindings>
</jaxb:bindings>
More information on this option (and other sweet things) you can find here.

Resources