XML Composite Object Mapping problem [message #537550] |
Wed, 02 June 2010 20:43 |
Den Messages: 2 Registered: June 2010 |
Junior Member |
|
|
Hi,
I'm new to Eclipselink and I'm having trouble getting an XML mapping working,
I have the following Java classes:
public class Response {
List<ResourceStatus> rs;
List<ResourceLocation> rl;
...
}
public class ResourceStatus {
private String id;
private String status;
...
}
public class ResourceLocation {
private String id;
private Point posn;
...
}
My XML doc is:
<remc:Response>
<remc:ResourceStatusLocations>
<remc:ID>AAA</remc:ID>
<remc:Status>0</remc:Status>
<remc:Location>
<common:Coordinate>
<common:X>5.0</common:X>
<common:y>5.0</common:y>
</common:Coordinate>
</remc:Location>
</remc:ResourceStatusLocations>
<remc:ResourceStatusLocations>
<remc:ID>BBB</remc:ID>
<remc:Status>2</remc:Status>
<remc:Location>
<common:Coordinate>
<common:X>7.0</common:X>
<common:y>7.0</common:y>
</remc:Coordinate>
</remc:Location>
</remc:ResourceStatusLocations>
</remc:Response>
and the equivalent objects should be
Response
rl ["AAA", (5.0, 5.0)], ["BBB", (7.0, 7.0)]
rs ["AAA", "0"], ["BBB", "2"]
In my workbench (EclipseLink Workbench v2.0.2), I have:
Descriptor Response --> context = schema::nnn//element::remc:Response
- Attribute ResourceLocation mapped as a composite collection:
- xpath = remc:ResourceStatusLocation
- Reference descriptor = ResourceLocation
Desciptor ResourceLocation --> context = schema::nnn//complexType:remc:ResourceStatusLocation
- Attribute coordinate mapped as composite object using customiser code
final XMLCompositeObjectMapping mapping = new XMLCompositeObjectMapping();
mapping.setAttributeName("coordinate");
mapping.setXPath("remc:Location/common:Coordinate");
mapping.setReferenceClass(Point.class);
descriptor.addMapping(mapping);
However, when marshalling the object to XML, I've got the id and statuses mapped ok but the locations are missing:.
<remc:Response>
<remc:ResourceStatusLocations>
<remc:Status>0</remc:Status>
<remc:ID>AAA</remc:ID>
</remc:ResourceStatusLocations>
<remc:ResourceStatusLocations>
<remc:Status>2</remc:Status>
<remc:ID>BBB</remc:ID>
</remc:ResourceStatusLocations>
</remc:Response>
I have verified that the customiser code is being called and that the Point.class matches the Coordinate element.
Is this the right approach to take, am I missing something obvious here?
Thanks
Den
|
|
|
Re: XML Composite Object Mapping problem [message #538844 is a reply to message #537550] |
Tue, 08 June 2010 18:36 |
David McCann Messages: 20 Registered: July 2009 |
Junior Member |
|
|
Hey Den,
The issue here is that you are attempting to map ResourceLocation in the context of a ResourceStatus, but these two objects aren't directly related in the object model. The way it is currently mapped would indicate to EclipseLink that ResourceStatus has a composite relationship to ResourceLocation, which is not the case. You can make use of our extended API to get this working, though. Here's one way to do it:
Use an object to hold on to the ResourceStatus/ResourceLocation pairs, like this:
public class ResourceStatusLocations {
public ResourceStatus rs;
public ResourceLocation rl;
}
Setup a mapping for a list of these ResourceStatusLocations on the Response descriptor like so:
XMLCompositeCollectionMapping rslmapping = new XMLCompositeCollectionMapping();
rslmapping.setXPath("remc:ResourceStatusLocations");
rslmapping.setReferenceClass(ResourceStatusLocations.class);
rslmapping.setAttributeAccessor(new RSLAttributeAccessor());
rslmapping.setContainerPolicy(new ListContainerPolicy(ArrayList.class));
This list doesn't really exist, i.e. there is no List<ResourseStatusLocations> attribute on Response, and that's okay.
Do not map List<ResourceStatus> and List<ResourceLocation> on the Response descriptor.
The mappings for the new ResourceStatusLocations would look like:
// mapping for ResourceStatus
XMLCompositeObjectMapping rsmapping = new XMLCompositeObjectMapping();
rsmapping.setAttributeName("rs");
rsmapping.setXPath(".");
rsmapping.setReferenceClass(ResourceStatus.class);
// mapping for ResourceLocation
XMLCompositeObjectMapping rlmapping = new XMLCompositeObjectMapping();
rlmapping.setAttributeName("rl");
rlmapping.setXPath("remc:Location");
rlmapping.setReferenceClass(ResourceLocation.class);
We will use a custom accessor that populates the ResourceStatusLocations objects based on List<ResourceStatus> and List<ResourceLocation> in the Response object (for marshalling), and populates List<ResourceStatus> and List<ResourceLocation> based on the ResourceStatusLocations objects during unmarshal. Something like this:
public class RSLAttributeAccessor extends AttributeAccessor {
@Override
public Object getAttributeValueFromObject(Object object) throws DescriptorException {
ArrayList<ResourceStatusLocations> rslList = new ArrayList<ResourceStatusLocations>();
Response resp = (Response) object;
// build a list of ResourceStatusLocations using the Response object's ResourceStatus and ResourceLocation lists
for (int i=0; i<resp.rs.size(); i++) {
rslList.add(new ResourceStatusLocations(resp.rs.get(i), resp.rl.get(i)));
}
return rslList;
}
@Override
public void setAttributeValueInObject(Object object, Object value) throws DescriptorException {
ArrayList<ResourceStatus> rsList = new ArrayList<ResourceStatus>();
ArrayList<ResourceLocation> rlList = new ArrayList<ResourceLocation>();
Response resp = (Response) object;
ArrayList<ResourceStatusLocations> rslList = (ArrayList<ResourceStatusLocations>) value;
// build ResourceStatus and ResourceLocation lists using the given ResourceStatusLocations
for (ResourceStatusLocations rsls : rslList) {
rsList.add(rsls.rs);
rlList.add(rsls.rl);
}
resp.rs = rsList;
resp.rl = rlList;
}
@Override
public void initializeAttributes(Class descriptorClass) throws DescriptorException {
// do nothing as the attribute doesn't really exist
}
}
Using this configuration I can successfully unmarshal from/marshal to this instance document:
<?xml version="1.0" encoding="UTF-8"?>
<remc:Response xmlns:common="mycommonuri" xmlns:remc="myuri">
<remc:ResourceStatusLocations>
<remc:ID>AAA</remc:ID>
<remc:Status>0</remc:Status>
<remc:Location>
<common:id>AAA</common:id>
<common:Coordinate>
<common:X>5.0</common:X>
<common:Y>5.0</common:Y>
</common:Coordinate>
</remc:Location>
</remc:ResourceStatusLocations>
<remc:ResourceStatusLocations>
<remc:ID>BBB</remc:ID>
<remc:Status>2</remc:Status>
<remc:Location>
<common:id>BBB</common:id>
<common:Coordinate>
<common:X>7.0</common:X>
<common:Y>7.0</common:Y>
</common:Coordinate>
</remc:Location>
</remc:ResourceStatusLocations>
</remc:Response>
--Dave
[Updated on: Tue, 08 June 2010 18:37] Report message to a moderator
|
|
|
Powered by
FUDForum. Page generated in 0.02879 seconds