MOXy - xlink reference to previously marshalled objects [message #661234] |
Wed, 23 March 2011 16:08 |
Matti Hansson Messages: 68 Registered: July 2009 |
Member |
|
|
Hi!
I'm making a service that returns an Owner. The Owner can own Land and Buildings and each Building stands on a piece of Land, so the XML tree looks something like this:
Owner
Land
Land
Building
Land
Building
Land
Now, many Buildings may stand on the same piece of Land and the Land may or may not be owned by the Owner. I don't want to have several instances of the same Land object in my response. Instead, I'd like it if only the first instance was marshalled in full and the rest was only an xlink reference to the first.
Is this possible?
[Updated on: Thu, 24 March 2011 13:46] Report message to a moderator
|
|
|
Re: MOXy - xlink reference to previously marshalled objects [message #661615 is a reply to message #661234] |
Fri, 25 March 2011 15:07 |
|
You could leverage @XmlID/@XmlIDREF to do the following:
Land
Land will need an id property annotated with @XmlID:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlID;
public class Land {
private String id;
@XmlID
@XmlAttribute
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Building
The land property on building will be annotated with @XmlIDREF:
import javax.xml.bind.annotation.XmlIDREF;
public class Building {
private Land land;
@XmlIDREF
public Land getLand() {
return land;
}
public void setLand(Land land) {
this.land = land;
}
}
B]Owner[/B]
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlRootElement
@XmlType(propOrder={"building", "land"})
public class Owner {
private List<Land> land = new ArrayList<Land>();
private List<Building> building = new ArrayList<Building>();
public List<Land> getLand() {
return land;
}
public void setLand(List<Land> land) {
this.land = land;
}
public List<Building> getBuilding() {
return building;
}
public void setBuilding(List<Building> building) {
this.building = building;
}
}
Demo
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
Owner owner = new Owner();
Land land1 = new Land();
land1.setId("1");
Building building1 = new Building();
building1.setLand(land1);
owner.getBuilding().add(building1);
owner.getLand().add(land1);
Land land2 = new Land();
land2.setId("2");
Building building2 = new Building();
building2.setLand(land2);
owner.getBuilding().add(building2);
owner.getLand().add(land2);
JAXBContext jc = JAXBContext.newInstance(Owner.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(owner, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<owner>
<building>
<land>1</land>
</building>
<building>
<land>2</land>
</building>
<land id="1"/>
<land id="2"/>
</owner>
-Blaise
|
|
|
|
Re: MOXy - xlink reference to previously marshalled objects [message #661661 is a reply to message #661234] |
Fri, 25 March 2011 20:11 |
|
Hello Again,
I apologize for missing that part of your question. The following will give you the type of behaviour you are looking for:
Land
Nothing special needs to be done for the Land class:
public class Land {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Building
The land property on Building is where all the magic happens. We will use an XmlAdapter on this property.
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
public class Building {
private Land land;
@XmlJavaTypeAdapter(MarshalAdapter.class)
public Land getLand() {
return land;
}
public void setLand(Land land) {
this.land = land;
}
}
MarshalAdapter
This is what the XmlAdapter will look like. This XmlAdapter requires the land list from the Owner object be set on it. You will see how this is done in the code for Demo.
import java.util.List;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class MarshalAdapter extends XmlAdapter<AdaptedLand, Land> {
private List<Land> ownersLand;
public MarshalAdapter() {
}
public MarshalAdapter(List<Land> ownersLand) {
this.ownersLand = ownersLand;
}
@Override
public Land unmarshal(AdaptedLand v) throws Exception {
return null;
}
@Override
public AdaptedLand marshal(Land v) throws Exception {
AdaptedLand adaptedLand = new AdaptedLand();
if(ownersLand.contains(v)) {
adaptedLand.setOwnerLandIndex(String.valueOf(ownersLand.indexOf(v)));
} else {
adaptedLand.setLand(v);
}
return adaptedLand;
}
}
AdaptedLand
This class is leveraged by the XmlAdapter:
import javax.xml.bind.annotation.XmlAttribute;
import org.eclipse.persistence.oxm.annotations.XmlPath;
public class AdaptedLand {
private Land land;
private String ownerLandIndex;
@XmlPath(".")
public Land getLand() {
return land;
}
public void setLand(Land land) {
this.land = land;
}
@XmlAttribute
public String getOwnerLandIndex() {
return ownerLandIndex;
}
public void setOwnerLandIndex(String id) {
this.ownerLandIndex = id;
}
}
Owner
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlRootElement
@XmlType(propOrder={"building", "land"})
public class Owner {
private List<Land> land = new ArrayList<Land>();
private List<Building> building = new ArrayList<Building>();
public List<Land> getLand() {
return land;
}
public void setLand(List<Land> land) {
this.land = land;
}
public List<Building> getBuilding() {
return building;
}
public void setBuilding(List<Building> building) {
this.building = building;
}
}
Demo
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
Owner owner = new Owner();
Land land1 = new Land();
land1.setAddress("123 Any Street");
Building building1 = new Building();
building1.setLand(land1);
owner.getBuilding().add(building1);
owner.getLand().add(land1);
Land land2 = new Land();
land2.setAddress("456 Another Road");
Building building2 = new Building();
building2.setLand(land2);
owner.getBuilding().add(building2);
//owner.getLand().add(land2);
JAXBContext jc = JAXBContext.newInstance(Owner.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setAdapter(new MarshalAdapter(owner.getLand()));
marshaller.marshal(owner, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<owner>
<building>
<land ownerLandIndex="0"/>
</building>
<building>
<land>
<address>456 Another Road</address>
</land>
</building>
<land>
<address>123 Any Street</address>
</land>
</owner>
-Blaise
|
|
|
|
Powered by
FUDForum. Page generated in 0.08161 seconds