2

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, consider my department model:

GET /locations/1:

  <location id='1'>
    <link rel="self" href="http://example.com/locations/1"/>
    <link rel="parent" href="http://example.com/serviceareas/1"/>
    <name>location 01</name>
    <departments>
      <department id='1'>
        <link rel="self" href="http://example.com/departments/1"/>
        <name>department 01</name>
      </department>
      <department id='2'>
        <link rel="self" href="http://example.com/departments/2"/>
        <name>department 02</name>
      </department>
      <department id='3'>
        <link rel="self" href="http://example.com/departments/3"/>
        <name>department 03</name>
      </department>
    </departments>
  </location>

GET /department/1:

<department id='1'>
  <link rel="self" href="http://example.com/departments/1"/>
  <link rel="parent" href="http://example.com/locations/1"/>
  <name>department 01</name>
  <abbr>dept 01</abbr>
  ....
  <specialty>critical care</specialty>
</department>

Is there a way to do this? Would I need to have separate entity objects? One that references the table for CRUD operations and another for lists?

craig
  • 25,664
  • 27
  • 119
  • 205

2 Answers2

3

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;
}
Pyves
  • 6,333
  • 7
  • 41
  • 59
bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • I'm referencing three, 'EclipseLink(JPA 2.0)' JARs: eclipselink-2.3.0.jar, javax.persistence-2.0.jar, org.eclipse.persistence.jpa.jpql_1.0.0.jar. Is MOXy included in any of these? – craig Feb 01 '12 at 11:50
  • 1
    @craig - MOXy is included in eclipselink-2.3.0.jar. Here is an article that explains how to configure MOXy as the JAXB provider: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html If you are using GlassFish the following article explains how the MOXy can be configured: http://blog.bdoughan.com/2010/08/creating-restful-web-service-part-35.html – bdoughan Feb 01 '12 at 11:54
  • I have a number of n00bish, JABX-related questions. Would you have time for a chat in one of the SO rooms? – craig Feb 01 '12 at 11:57
  • @craig - We could use the Java room. – bdoughan Feb 01 '12 at 14:09
  • OK, this makes sense, but I have a few questions. 1. Should/can each ContentResolver have its own binding file? 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? 3. Where should the binding files reside? 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? – craig Feb 02 '12 at 20:21
  • @craig - I have updated my answer to address your new questions. – bdoughan Feb 03 '12 at 20:09
  • wow, super helpful +1. In addition to the implicit ContentResolver (enabled by the class' annotation), I can create additional, custom ContentResolvers. Each of these ContentResolver has its own binding file. It seems that a custom ContentResolver will be chosen before the implicit one. Is this accurate? If I have multiple, custom ContentResolvers that *could* be applied to a given class, is there a way to specify which one to use? – craig Feb 03 '12 at 20:37
  • Should have written ContextResolver instead of ContentResolver. – craig Feb 03 '12 at 21:10
0

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;
}
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
Jin Kwon
  • 20,295
  • 14
  • 115
  • 184