Search code examples
jaxbeclipselinkjax-rsglassfish-3moxy

after/before (Un)Marshal event fires twice and for xml only


A simple class, that is being marshalled for output:

@XmlRootElement
public class Foobar {
    // ...

    void beforeMarshal(Marshaller m) {
        System.out.println("beforeMarshal fired");
    }
}

The JAX-RS is also very simple:

@GET
public Response getResponse() {
    Foobar fb = new Foobar();
    // ...
    return Response.ok(fb).build();
}

The expected output would be "beforeMarshal fired" once, but it fires twice?
Is this normal? I don't think using an extra flag is a good idea ..

@XmlTransient
private boolean marshalled;

void beforeMarshal(Marshaller m) {
    if (!this.marshalled) {
        System.out.println("beforeMarshal");
        this.marshalled = true;
    }
}

Also, when querying the resource for json output, it doesn't fire the marshal event at all.


Solution

  • UPDATE

    There was a bug (see: http://bugs.eclipse.org/412417) in MOXy that would prevent the calling of marshal/unmarshal methods in OSGi environments such as GlassFish. This is now fixed in the EclipseLink 2.3.3, 2.4.3, 2.5.1, and 2.6.0 streams. You can download a nightly build from the following link starting July 10, 2013:

    I have not been able to reproduce the issue where the same event is called twice. If you have a code example that demonstrates this issue please start an email conversation with me through my blog:


    XML BINDING

    If you are seeing that the beforeMarshal method is being called twice instead of once then you are using the reference implementation and not EclipseLink MOXy as your JAXB (JSR-222) provider.

    Demo Code

    import javax.xml.bind.*;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Foobar.class);
            System.out.println(jc.getClass());
    
            Foobar foobar = new Foobar();
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.marshal(foobar, System.out);
        }
    
    }
    

    Output - JAXB Reference Implementation

    class com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl
    beforeMarshal fired
    beforeMarshal fired
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><foobar/>
    

    Output - EclipseLink MOXy

    class org.eclipse.persistence.jaxb.JAXBContext
    beforeMarshal fired
    <?xml version="1.0" encoding="UTF-8"?>
    <foobar/>
    

    To enable MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model 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
    

    JSON BINDING

    MOXy uses the same plumbing for XML and JSON binding. This means that you will see the same event behaviour for both. If you are not seeing events then a JSON binding provider other than MOXy.