tutorial - xmlrootelement annotation not generated by jaxb




Jaxb marshalling with custom annotations (5)

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

Below is an example of how you could use MOXy's @XmlNamedObjectGraphs extension to map your use case.

Java Model

Foo

The @XmlNamedObjectGraphs extension allows you to specify multiple subsets of mappings identified by a key.

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

import org.eclipse.persistence.oxm.annotations.XmlNamedAttributeNode;
import org.eclipse.persistence.oxm.annotations.XmlNamedObjectGraph;
import org.eclipse.persistence.oxm.annotations.XmlNamedObjectGraphs;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlNamedObjectGraphs({
    @XmlNamedObjectGraph(
        name="v1",
        attributeNodes = { 
            @XmlNamedAttributeNode("field1"),
            @XmlNamedAttributeNode("field2")}),
    @XmlNamedObjectGraph(
        name="v2",
        attributeNodes = { 
            @XmlNamedAttributeNode("field2"),
            @XmlNamedAttributeNode("field3")})
})
public class Foo {

    private String field1 = "ONE";
    private String field2 = "TWO";
    private String field3 = "THREE";

}

jaxb.properties

To use MOXy as your JAXB provider you need to include a file called jaxb.properties with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Demo Code

Demo

You can specify the key corresponding to the object graph to have that subset applied to the object you are marshalling.

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import org.eclipse.persistence.jaxb.MarshallerProperties;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Foo.class);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        Foo foo = new Foo();

        // Marshal Everything
        marshaller.marshal(foo, System.out);

        // Marshal "v1" Data
        marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, "v1");
        marshaller.marshal(foo, System.out);

        // Marshal "v2" Data
        marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, "v2");
        marshaller.marshal(foo, System.out);
    }

}

Output

<?xml version="1.0" encoding="UTF-8"?>
<foo>
   <field1>ONE</field1>
   <field2>TWO</field2>
   <field3>THREE</field3>
</foo>
<?xml version="1.0" encoding="UTF-8"?>
<foo>
   <field1>ONE</field1>
   <field2>TWO</field2>
</foo>
<?xml version="1.0" encoding="UTF-8"?>
<foo>
   <field2>TWO</field2>
   <field3>THREE</field3>
</foo>

For More Information

I have a requirement, to marshall/unmarshall some elements of java pojo depending upon a custom annotation marked on the field. suppose there are 3 fields in my java pojp

@CustomVersion("v1")
private String field1;
@CustomVersion("v1","v2")
private String field2;
@CustomVersion("v2")
private String field3;

i would like to marshall only the fields with v1 if i pass version="v1" parameter while conversion in jaxb. if i pass v2, all fields with v2 annotation should only be marshalled.

is that even possible using jaxb? i am sure selective marshalling would be supported through some library or way, am not still able to figure it out after quite some searching. any help or advice or pointers are highly appreciated.


Even if this is not really an answer, I had not enough characters to put it in a comment :)

If you're really new to REST, I think you're beginning probably in the wrong way. I don't know exactly your requirements, but if you only want to learn, begin with an easy REST service, use Web API from .net or something similar in Java (a simple servlet would be enough) and try to implement a service which only uses the tools delivered by http (the verbs, the request header and payload, the response message). REST API design rulebook from Marc Massé could be a good reference to learn. Create your own communication protocol with POJOs or POCOs and once you really what you can do REST and how it works, you can use a framework to ease your work.

If you begin with a framework you may miss the essence of the concept...

I hope it helps!


It's very little that's required to adhere to HAL. I suggest you roll your own mini-library where you wrap your POJOs in HAL-objects. This way you get the code the way you like it and it will be way simpler than HalBuilder.


Implement HATEOAS with HAL in Jersey

I can't find any direct support for this in Jersey, but there should be ways to customize the marshaller that Jersey uses to convert your POJO's to JSON. (either by using HalBuilder, or create some HAL-compatible code of your own)

If you use Jerseys JAXB based JSON support, take a look at BootstrapTypeConverterTest in the jettison source code which demonstrates how a converter can be used to cusomize JSON output. Unit-testing conversions to/from JSON should be a simple task and jettison-project has good examples to look at.

If you use Jerseys "POJO Support"-method, take a look at JacksonHowToCustomSerializers for a similar example on how to create your custom serializers.

(If JAXB is involved, you can also do cool things like processing custom annotations.)

You probably have a pretty good idea of how your objects (input) looks like and what JSON code (output) you expect, so creating unit tests for these conversions should be a relatively simple task.


enable/disable fields for moxy serialization with default being disabled

If you specify an object graph name when you create the JAXBContext it will be set by default on all the Marshaller and Unmarshaller instances created from it.

Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextProperties.OBJECT_GRAPH, "yourGraphName");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Foo.class}, properties);