我了解所有关于如何使用
XMLAdapters到
convert unmappable types,或者只是改变某些对象如何序列化/反序列化为XML.如果我使用注释(包级别或其他方式),一切都会很好.问题是我正在尝试更改第三方对象的表示,我不能将源代码更改为(即为了注入注释).
这不应该是一个问题,考虑到Marshaller对象有一个方法manually adding adapters.不幸的是,无论我做什么,我不能得到这样的方式设置为“踢”.例如,我有一个类代表XYZ空间中的一个点(地心坐标).在我生产的XML中,我希望将其转换为lat / long / altitude(大地坐标).这是我的课程:
地心
package testJaxb; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class GeocentricCoordinate { // Units are in meters; see http://en.wikipedia.org/wiki/Geocentric_coordinates private double x; private double y; private double z; @XmlAttribute public double getX() { return x; } public void setX(double x) { this.x = x; } @XmlAttribute public double getY() { return y; } public void setY(double y) { this.y = y; } @XmlAttribute public double getZ() { return z; } public void setZ(double z) { this.z = z; } }
大地
package testJaxb; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; /** * @see http://en.wikipedia.org/wiki/Geodetic_system */ @XmlRootElement public class GeodeticCoordinate { private double latitude; private double longitude; // Meters private double altitude; public GeodeticCoordinate() { this(0,0); } public GeodeticCoordinate(double latitude,double longitude,double altitude) { super(); this.latitude = latitude; this.longitude = longitude; this.altitude = altitude; } @XmlAttribute public double getLatitude() { return latitude; } public void setLatitude(double latitude) { this.latitude = latitude; } @XmlAttribute public double getLongitude() { return longitude; } public void setLongitude(double longitude) { this.longitude = longitude; } @XmlAttribute public double getAltitude() { return altitude; } public void setAltitude(double altitude) { this.altitude = altitude; } }
GeocentricToGeodeticLocationAdapter
package testJaxb; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.annotation.adapters.XmlAdapter; /** * One of our systems uses xyz coordinates to represent locations. Consumers of our XML would much * prefer lat/lon/altitude. This handles converting between xyz and lat lon alt. * * @author ndunn * */ public class GeocentricToGeodeticLocationAdapter extends XmlAdapter<GeodeticCoordinate,GeocentricCoordinate> { @Override public GeodeticCoordinate marshal(GeocentricCoordinate arg0) throws Exception { // TODO: do a real coordinate transformation GeodeticCoordinate coordinate = new GeodeticCoordinate(); coordinate.setLatitude(45); coordinate.setLongitude(45); coordinate.setAltitude(1000); return coordinate; } @Override public GeocentricCoordinate unmarshal(GeodeticCoordinate arg0) throws Exception { // TODO do a real coordinate transformation GeocentricCoordinate gcc = new GeocentricCoordinate(); gcc.setX(100); gcc.setY(200); gcc.setZ(300); return gcc; } }
ObjectWithLocation字段
package testJaxb; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class ObjectWithLocation { private GeocentricCoordinate location = new GeocentricCoordinate(); public GeocentricCoordinate getLocation() { return location; } public void setLocation(GeocentricCoordinate location) { this.location = location; } public static void main(String[] args) { ObjectWithLocation object = new ObjectWithLocation(); try { JAXBContext context = JAXBContext.newInstance(ObjectWithLocation.class,GeodeticCoordinate.class,GeocentricCoordinate.class); Marshaller marshaller = context.createMarshaller(); marshaller.setAdapter(new GeocentricToGeodeticLocationAdapter()); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,true); marshaller.marshal(object,System.out); } catch (JAXBException jaxb) { jaxb.printStackTrace(); } } }
输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <objectWithLocation> <location z="0.0" y="0.0" x="0.0"/> </objectWithLocation>
通过使用注释(在我的package-info.java文件中):
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters ({ @javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(value=GeocentricToGeodeticLocationAdapter.class,type=GeocentricCoordinate.class),}) package package testJaxb;
我得到以下(所需)xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <objectWithLocation> <location longitude="45.0" latitude="45.0" altitude="1000.0"/> </objectWithLocation>
所以我的问题是双重的.
>为什么适配器在注释时工作,但是通过setAdapter方法显式设置时不适用?
>如果我有类不能注释的类,并且我的package-info.java我不能修改以添加注释,我该如何解决这个问题?
解决方法
Marshaller上的setAdapter(XmlAdapter)用于传递已经使用@XmlJavaTypeAdapter注释的属性的初始化XmlAdapter.下面的链接是一个我利用这个行为的答案:
> Using JAXB to cross reference XmlIDs from two XML files
如果你想映射第三方类,你可以使用EclipseLink JAXB (MOXy)的XML映射文件(我是MOXy的主管):
> http://bdoughan.blogspot.com/2010/12/extending-jaxb-representing-annotations.html