Wednesday, July 14, 2010

GlassFish - JPA & Jaxb

So I am preparing a major rewriting of our last Major App in Delphi. The client side will be in Java - we need at least one Java component for text manipulation. I will come back later on the client as I looked at a lot of nice stuff.

One the server side things are also difficult. My intention is to go to JPA as it is now the standard ORM and will give us portability between DB and probably also a much cleaner code.

The JPA classes were created automatically by Netbeans. Next I created a stateless session bean and finally a Soap Web service (Netbeans created that one from the session bean). It is a lot of artifact... A good thing again, I suppose done by Netbeans, your web service also generate a small web base tester for the service.

Unfortunately I hitted the first issue yesterday...

Caused by: javax.xml.bind.MarshalException
 - with linked exception:
[com.sun.istack.SAXException2: A cycle is detected in the object graph. This will cause infinitely deep XML: com.adins.testNISFusion.jpa.Patient[id=1] -> com.adins.testNISFusion.jpa.Actor[id=1] -> com.adins.testNISFusion.jpa.Patient[id=1]]
        at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:269)
        at com.sun.xml.bind.v2.runtime.BridgeImpl.marshal(BridgeImpl.java:110)
        at com.sun.xml.bind.api.Bridge.marshal(Bridge.java:178)
        at com.sun.xml.ws.message.jaxb.JAXBMessage.writePayloadTo(JAXBMessage.java:297)
        ... 56 more


So the session bean works fine but the web service cannot serialize the answer properly because there is a loop in the references (which by the way is the most common things you get in a relational database and these references have been created by Netbeans/JPA).


The solutions are listed here ...

https://jaxb.dev.java.net/guide/Mapping_cyclic_references_to_XML.html

The first one is to make the referenced entity XmlTransient  so basically not referenced any more. It is difficult for me to see this as a solution. May be if your DB is made of non used entities...

The second is to use XMLID and XMLIDREF directive. So instead of serializing recursively JAXB will point to the ID of the other entity.

In my case - I think a common one. The entity being passed through the web service are in fact my JPA entities. So your JPA entitiy gets fields annotated with@ID and @XmlID.

Unfortunately combining JPA and JAXB   creates another issue.

Caused by: java.security.PrivilegedActionException: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "id"

Strange...

I foud a solution here : http://www.objectpartners.com/2010/01/25/using-jpa-and-jaxb-annotations-in-the-same-object/

Basically, you will put the JAXB annotation on the accessor not on the variable where you put the JPA ones.


So something like :

....

@XmlRootElement
public class Patient implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)

....
@XmlID
    public String getId() {
        return id;
    }


Conclusion at this time...
1) It works for now.
2) Netbeans is great and generates plenty of stuff that I will have to modify by hands... :-(
3) JPA stuff is very static but JAXB builds XML at runtime. So you get the worst combination : modification requires compiling and compiling does not shield you from syntax error...
4) I don't like that much annotation. The syntax is ugly. In the case of the transient 'solution', it is hard to imagine that you can solve all the real cases statically. Sometines you need the element, sometines not...
5) A stack is just a stack of boxes as drawn on the marketing docs. It seems little people spend time to make these boxes working really together.  
6) I have been trough a lot of readings, an entire stack of books... Building a web service to pass persistent entity is just basic and yet nobody mentions this issue...This is in my opinion the key drama of this industry. Book writers (as tools builder) rarely  build appications,...
7) It would be great to have a single option for JAXB to tell that we want to use ID and REF...Who knows...

No comments: