Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » XML Composite Object Mapping problem
XML Composite Object Mapping problem [message #537550] Wed, 02 June 2010 20:43 Go to next message
Den is currently offline 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 Go to previous message
David McCann is currently offline 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

Previous Topic:eclipselink doesn't find my persistence.xml
Next Topic:Problem on EclipseLink JPA Weaving using Toplink session.xml, project.xml as JPA Source
Goto Forum:
  


Current Time: Thu Oct 30 19:08:16 GMT 2014

Powered by FUDForum. Page generated in 0.03124 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software