I\'m hoping to have a flexible way of marshalling objects. A verbose version for single objects and a less-verbose version for multiple object versions.
For example, co
Note: I'm the EclipseLink JAXB (MOXy) lead, and a member of the JAXB 2 (JSR-222) expert group.
Your question is tagged EclipseLink
, if you are using EclipseLink JAXB (MOXy) you can take advantage of the external binding document to apply a second mapping to the Department
class.
ContextResolver
In a JAX-RS environment you can leverage MOXy's external binding document through a ContextResolver
:
import java.io.*;
import java.util.*;
import javax.ws.rs.Produces;
import javax.ws.rs.ext.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
@Provider
@Produces({"application/xml", "application/json"})
public class DepartmentContextResolver implements ContextResolver<JAXBContext> {
private JAXBContext jc;
public DepartmentContextResolver() {
try {
Map<String, Object> props = new HashMap<String, Object>(1);
props.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "example/bindings.xml");
jc = JAXBContext.newInstance(new Class[] {Department.class} , props);
} catch(JAXBException e) {
throw new RuntimeException(e);
}
}
public JAXBContext getContext(Class<?> clazz) {
if(Department.class == clazz) {
return jc;
}
return null;
}
}
For More Information
External Binding Document
By default MOXy's external binding document is used to augment the annotated model, but if you set the xml-mapping-metadata-complete
flag it will completely override the annotations allowing you to apply a completely different mapping:
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="example"
xml-mapping-metadata-complete="true">
...
</xml-bindings>
For More Information
UPDATE
This update is to address a number of questions you asked in one of your comments:
1 . Should/can each ContentResolver have its own binding file?
Yes each ContextResolver
should have its own binding file. The main reason for introducing a new ContextResolver
is to represent a secondary mapping.
2 . Can I have more than one for each ContentResolver (this would give me a number of renderings of the same class, creating a 'view' of sorts), perhaps specifying its location in the constructor?
For a single ContextResolver
you can express the metadata across multiple binding files, but they will be combined into a single set of mappings. This means that a single ContentResolver
cannot have multiple views of a single class. A separate ContextResolver
is used to represent a secondary mapping.
3 . Where should the binding files reside?
I recommend loading the metadata file from the class path.
4 . I can see how the ContentResolver could be easily specified in a Resource's GET method, but how would this be done if the object is embedded in another (JPA) object? In the embedded object's getter/setter?
Your JAX-RS implementation should pick up your ContextResolver
because it is annotated with @Provider
. The ContextResolver
used for a class will depend on how you implement the getContext
method:
public JAXBContext getContext(Class<?> clazz) {
if(Customer.class == clazz) {
return jc;
}
return null;
}
Here comes another idea. Could be a bad idea but somewhat easy.
class Department {
@XmlElement(required = true)
public Link getSelf() {
return self;
}
@XmlElement(required = false) // default
public Link getParent() {
if (verbose) {
return parent;
}
return null;
}
@XmlElement(required = false) // default
public String getSpecialty() {
if (verbose) {
return specialty;
}
return null;
}
@XmlTransient
private boolean verbose;
}