Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 347466

Summary: Binder - Relationship between Object and Node should be based on identity and not equality
Product: z_Archived Reporter: Blaise Doughan <blaise.doughan>
Component: EclipselinkAssignee: Matt MacIvor <matt.macivor>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: eclipselink.oxm-inbox, marcusgy
Version: unspecified   
Target Milestone: ---   
Hardware: PC   
OS: Windows XP   
Whiteboard:
Attachments:
Description Flags
Proposed fix and test case none

Description Blaise Doughan CLA 2011-05-27 10:54:02 EDT
Currently in the MOXy implementation of Binder we are maintaining a relationship between objects and nodes based on equality, this relationship should be based on identity.

This issue was raised on Stack Overflow:
- http://stackoverflow.com/questions/6146572/can-i-use-the-jaxb2-basics-plugin-with-the-moxy-jaxb-implementation-from-eclipsel
Comment 1 marcusgy CLA 2011-05-27 11:23:28 EDT
Blaise is right. Ultimately the problem is that the XMLBinderPolicy.objectsToNodes map uses the generated JAXB objects (I generated them from an xsd) directly as keys. If equals is implemented in the JAXB class with the implementation based on the state of the object, and you then change that state, then later the object with not be found in the map and the xml node lookup will fail generating the exception:

java.lang.IllegalArgumentException
	at org.eclipse.persistence.jaxb.JAXBBinder.updateXML(JAXBBinder.java:131)
	at org.eclipse.persistence.jaxb.JAXBBinder.updateXML(JAXBBinder.java:126)

I think the solution is something like wrapping the JAXB objects with another class which then references the JAXB objects and using that as the keys to XMLBinderPolicy.objectsToNodes.

An example will follow.
Comment 2 marcusgy CLA 2011-05-27 11:32:34 EDT
Referencing the example Blaise gave me at:
http://stackoverflow.com/questions/6059575/does-jaxb-support-modification-of-existing-xml-documents-without-marshalling-unma

(I haven't tried the code, just wrote it now, but it should work or should be easily modifiable to make it work).

In the Customer class, override equals and hashCode as:

public boolean equals(Object o) {
    return o != null && o.getClass().equals(getClass()) && ((Customer)o).getName().equals(getName());
}

Override hashCode as:
public int hashCode() {
    return 7;
}

Now the following code should generate the exception:

import java.io.File;
import javax.xml.bind.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.*;

public class BinderDemo {

    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        File xml = new File("input.xml");
        Document document = db.parse(xml);

        JAXBContext jc = JAXBContext.newInstance(Customer.class);

        Binder<Node> binder = jc.createBinder();
        Customer customer = (Customer) binder.unmarshal(document);
        customer.setName("something else");
        binder.updateXML(customer);

...
Comment 3 Matt MacIvor CLA 2011-05-27 11:44:17 EDT
Created attachment 196779 [details]
Proposed fix and test case
Comment 4 Matt MacIvor CLA 2011-05-27 11:45:30 EDT
Above patch fixes the issue by switching the hashmaps used to store the object->node and node->object associations to be IdentityHashMaps.
Comment 5 Matt MacIvor CLA 2011-05-27 13:18:54 EDT
Attached patch has been checked in to SVN
Reviewed by Blaise Doughan

The fix will be available in the next EclipseLink 2.3 nightly build.
Comment 6 Eclipse Webmaster CLA 2022-06-09 10:09:47 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink