| Summary: | Binder - Relationship between Object and Node should be based on identity and not equality | ||||||
|---|---|---|---|---|---|---|---|
| Product: | z_Archived | Reporter: | Blaise Doughan <blaise.doughan> | ||||
| Component: | Eclipselink | Assignee: | 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
Blaise Doughan
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. 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); ... Created attachment 196779 [details]
Proposed fix and test case
Above patch fixes the issue by switching the hashmaps used to store the object->node and node->object associations to be IdentityHashMaps. 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. The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink |