3

I want to selectively serialize fields based on the request and the user.

For example, an admin user would be served an XML with some additional fields. Whereas a normal user would get an XML without those fields.

Secondly, at present I use @XmlIDREF to prevent unnecessary expansion of referenced objects or collections.

But sometimes the user might want those details. Making a second request for the referenced object is not be desirable. I want to let the user tell the server that XYZ attribute should be expanded (i.e. include the complete object and not just its reference)

Given a user and a request, based on business logic I can tell which fields should be serialized. Now how do I communicate this information to JAXB?

As far as possible, I do not want to create an XSD. Note that request parameters are dynamic. Which fields to serialize is decided at run-time. So I cannot use something that has to be hard coded - like @Transient or @XmlIDREF annotations.

Dojo
  • 5,374
  • 4
  • 49
  • 79

2 Answers2

2

I will not try to dig into the XSD too. Here my advice :

1- By default, JAXB shall not serialize null fields. So you can simply nullify fields, you don't want to serialize.

To be a bit more clean, I would recommend you to nullify copies of your business objects. Just to be sure that you won't have side effects in the applications.


2- You can also make your fields dynamic using a map and storing <String, Object>. This will let you have a full control of your fields life cycle.

Edit : The key will be your variable name and the value will be your object reference. If your value was supposed to be a primitive then you can auto-boxing your value into the associated object container. JAXB will then serialized all the existing values from the map.

If you had to share the key definition across several classes, I would recommend you to encapsulated the creation/destruction of (key, value) into another class.


3- If you want to enforce a specific set of attributes that can either be null or not at the same time and if the following abstraction make sense for your application. You can also define a subset of children class with different attributes. The parent class will have the must have attributes.

Good luck

Cyril
  • 537
  • 4
  • 11
  • Thanks. I was thinking of doing something similar to Point 1. But its not very neat. Say, object A references B. I obviously won't use XmlIDREF on reference to B as it would prevent B from ever being expanded. But now when I don't want to expand B, I have to set all fields of B to null except field holding the ID. Not very pretty but can be done and so far looks like the best option. Could you elaborate point 2? – Dojo May 11 '13 at 10:48
  • I did elaborate point 2, just below it. It is also a very basic approach. If you are interested, you can search other ways to implement "dynamic fields" (http://stackoverflow.com/questions/3127189/java-classes-with-dynamic-fields) – Cyril May 11 '13 at 11:07
2

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

In EclipseLink 2.5 (get it here: http://www.eclipse.org/eclipselink/downloads/milestones.php) we added a new feature to MOXy JAXB called Object Graphs. Object Graphs allow to programatically or through metadata select a subset of properties that you want to marshal/unmarshal. Below is an example of creating an object graph to get a subset of data from a Customer, Address, and PhoneNumber model.

    // Create the Object Graph
    ObjectGraph contactInfo = JAXBHelper.getJAXBContext(jc).createObjectGraph(Customer.class);
    contactInfo.addAttributeNodes("name");
    Subgraph location = contactInfo.addSubgraph("billingAddress");
    location.addAttributeNodes("city", "province");
    Subgraph simple = contactInfo.addSubgraph("phoneNumbers");
    simple.addAttributeNodes("value");

    // Output XML - Based on Object Graph
    marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, contactInfo);
    marshaller.marshal(customer, System.out);

For More Information

bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • Thanks, this is nice. Works well. However I have some problem with marshaling of ID fields in subgraph. I have a list of objects of class A (wrapped in a JaxbList). Each object of class A in turn has a list of objects of class B. I create object graph by passing to JaxbList.class . From that I create a Subgraph for B. A is serialized as expected, but the ID field of subgraph is not serialized. If I try marshaling by keeping B as the main graph (instead of subgraph), then ID field is serialized as expected. Any idea what could be wrong? I tried commenting out XmlID annotation. It still happens. – Dojo May 14 '13 at 13:43