Reputation: 889
I have a third party library that is providing a set of classes. These classes comprise an object graph for an XML structure and use JAXB for XML (un)marshaling. Let's say I have classes Car, Axle and Tire.
Car contains a list of Axle and Axle contains a list of Tire.
Tire looks like
public class Tire {
private double width;
private double radius;
public double getWidth() {
return width;
}
public double getRadius() {
return radius;
}
}
Now I want to add a property called pressure to Tire
public class PressurizedTire extends Tire {
private double pressure;
public PressurizedTire(Tire t, double pressure) {
this.width = t.getWidth();
this.radius = t.getRadius();
this.pressure = pressure;
}
}
I'd like to deserialize an xml document containing the car using JAXB, find all the tires and add the pressure data to each tire. I'd then like to reserialize the message to XML. Currently the extra property pressure gets dropped upon marshalling and the object structure goes back to it's original form.
What's the best way to accomplish adding properties to an existing JAXB model class? I don't want to extend every class, and I'm unsure about rebuilding and modifying the .xsd to accomplish this?
Upvotes: 1
Views: 1256
Reputation: 3504
I think this should work
I have just tried with the following classes:
@XmlAccessorType( XmlAccessType.FIELD )
public class Tire
{
double width;
double radius;
}
@XmlRootElement
@XmlAccessorType( XmlAccessType.FIELD )
public class Axle
{
@XmlElement( name = "tire" )
List<Tire> tires = new ArrayList<>();
}
@XmlAccessorType( XmlAccessType.FIELD )
public class PressurizedTire extends Tire
{
double pressure;
public PressurizedTire( Tire t, double pressure )
{
this.width = t.width;
this.radius = t.radius;
this.pressure = pressure;
}
}
and the following code
JAXBContext context = JAXBContext.newInstance( Axle.class, PressurizedTire.class );
Unmarshaller unmarshaller = context.createUnmarshaller();
String xml = "<axle><tire><width>2.0</width><radius>1.5</radius></tire><tire><width>2.5</width><radius>1.5</radius></tire></axle>";
Axle axle = (Axle) unmarshaller.unmarshal( new StringReader( xml ) );
List<Tire> pressurizedTires = new ArrayList<>();
for ( Tire tire : axle.tires )
{
pressurizedTires.add( new PressurizedTire( tire, 1.0 ) );
}
axle.tires = pressurizedTires;
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, true );
marshaller.marshal( axle, System.out );
and got this output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<axle>
<tire xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="pressurizedTire">
<width>2.0</width>
<radius>1.5</radius>
<pressure>1.0</pressure>
</tire>
<tire xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="pressurizedTire">
<width>2.5</width>
<radius>1.5</radius>
<pressure>1.0</pressure>
</tire>
</axle>
Upvotes: 1
Reputation: 3669
Yes, you can do that, and it is called Adding behavior
to existing JAXB classes.
Below example taken from above link: (All you need to do is @Override the object creation also. If you miss it, it won't work).
package org.acme.foo.impl;
class PersonEx extends Person {
@Override
public void setName(String name) {
if(name.length()<3) throw new IllegalArgumentException();
super.setName(name);
}
}
@XmlRegistry
class ObjectFactoryEx extends ObjectFactory {
@Override
Person createPerson() {
return new PersonEx();
}
}
Upvotes: 1