MOXy JSON Serializer无法使用接口扩展其他超级接口来序列化Java代理类

时间:2014-12-03 03:18:17

标签: json eclipselink moxy

用例:

我们设计了一个基于JOOQ的调制框架,这是一个用于SQL的DSL。每个模块都有一个API子模块和IMPL子模块。在API级别,对于每个ReadOnly访问,我们只公开一个特定的“视图”界面,以避免产生混淆,其中只包含getter。

要桥接模型和ReadOnly View,我们使用java Proxy。

因此会有一些高级接口,具体级别可以扩展。然后我们遇到了错误:

Exception in thread "main" javax.xml.bind.JAXBException: 
Exception Description: The java interface example.json.demo2.IAddress can not be mapped by JAXB as    it has multiple mappable parent interfaces. Multiple inheritence is not supported
- with linked exception:
[Exception [EclipseLink-50089] (Eclipse Persistence Services - 2.6.0.v20140809-296a69f):      org.eclipse.persistence.exceptions.JAXBException
Exception Description: The java interface example.json.demo2.IAddress can not be mapped by JAXB as it has multiple mappable parent interfaces. Multiple inheritence is not supported]
at org.eclipse.persistence.jaxb.JAXBContext$TypeMappingInfoInput.createContextState(JAXBContext.java:1108)
at org.eclipse.persistence.jaxb.JAXBContext.<init>(JAXBContext.java:188)
at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:165)
at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:152)
at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:112)
at org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(JAXBContextFactory.java:102)
at example.json.demo2.Demo.main(Demo.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: Exception [EclipseLink-50089] (Eclipse Persistence Services - 2.6.0.v20140809-296a69f): org.eclipse.persistence.exceptions.JAXBException
Exception Description: The java interface example.json.demo2.IAddress can not be mapped by JAXB as it has multiple mappable parent interfaces. Multiple inheritence is not supported
at org.eclipse.persistence.exceptions.JAXBException.invalidInterface(JAXBException.java:1116)
at org.eclipse.persistence.jaxb.javamodel.reflection.JavaClassImpl.getSuperclass(JavaClassImpl.java:360)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.postProcessXmlAccessorType(AnnotationsProcessor.java:1626)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.buildTypeInfo(AnnotationsProcessor.java:844)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.postBuildTypeInfo(AnnotationsProcessor.java:773)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.processClassesAndProperties(AnnotationsProcessor.java:298)
at org.eclipse.persistence.jaxb.compiler.Generator.<init>(Generator.java:156)
at org.eclipse.persistence.jaxb.JAXBContext$TypeMappingInfoInput.createContextState(JAXBContext.java:1104)
... 11 more

ReadOnly View Interface:

@XmlRootElement
public interface IAddress extends A, B {

@XmlPath("/address/@streetAddress")
String getStreet();

void setStreet(String street);

@XmlPath("/address/city/@cityName")
String getCity();

void setCity(String city);

@XmlPath("/address/state/@stateCode")
String getState();

void setState(String state);
@XmlPath("/address/country/@countryCode")
String getCountry();

void setCountry(String country);

@XmlPath("/address/@postalCode")
String getPostalCode();

void setPostalCode(String postalCode);
}

两个超级界面:      public interface A {}      public interface B {}

Bean类:

@XmlType(propOrder = { "country", "state", "city", "street", "postalCode" })
public class Address implements IAddress {

@XmlPath("Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:Locality/ns:Thoroughfare/ns:ThoroughfareName/text()")
private String street;
@XmlPath("Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:Locality/ns:LocalityName/text()")
private String city;
@XmlPath("Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:AdministrativeAreaName/text()")
private String state;
@XmlPath("Placemark/ns:AddressDetails/ns:Country/ns:CountryNameCode/text()")
private String country;
@XmlPath("Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:Locality/ns:PostalCode/ns:PostalCodeNumber/text()")
private String postalCode;

@Override
public String getStreet() {
    return street;
}

@Override
public void setStreet(String street) {
    this.street = street;
}

@Override
public String getCity() {
    return city;
}

@Override
public void setCity(String city) {
    this.city = city;
}

@Override
public String getState() {
    return state;
}

@Override
public void setState(String state) {
    this.state = state;
}

@Override
public String getCountry() {
    return country;
}

@Override
public void setCountry(String country) {
    this.country = country;
}

@Override
public String getPostalCode() {
    return postalCode;
}

@Override
public void setPostalCode(String postalCode) {
    this.postalCode = postalCode;
}
}

亚军类:

public class Demo {


public static void main(String[] args) throws Exception {
    final FileReader xmlURL = new FileReader("src/main/java/example/json/demo2/response.xml");
    final FileReader jsonURL = new FileReader("src/main/java/example/json/demo2/response.json");

    JAXBContext jc = JAXBContextFactory.createContext(new Class[]{Address.class, IAddress.class}, new HashMap());
    Unmarshaller unmarshaller = jc.createUnmarshaller();
    Marshaller marshaller = jc.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

    // XML
    XMLInputFactory xif = XMLInputFactory.newInstance();
    StreamSource xml = new StreamSource(xmlURL);
    XMLStreamReader xsr = xif.createXMLStreamReader(xml);
    xsr.nextTag(); // Advance to kml tag
    xsr.nextTag(); // Advance to Response tag
    JAXBElement<Address> addressFromXML = unmarshaller.unmarshal(xsr, Address.class);
    marshaller.marshal(addressFromXML, System.out);

    // JSON
    unmarshaller.setProperty("eclipselink.media-type", "application/json");
    unmarshaller.setProperty("eclipselink.json.include-root", false);
    StreamSource json = new StreamSource(jsonURL);

    final JAXBElement<Address> addressFromJSON = unmarshaller.unmarshal(json, Address.class);
    marshaller.setProperty("eclipselink.media-type", "application/json");
    marshaller.setProperty("eclipselink.json.include-root", false);
    final IAddress value = (IAddress) Proxy.newProxyInstance(Demo.class.getClassLoader(), new Class[]{IAddress.class}, new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            final Address address = addressFromJSON.getValue();
            return method.invoke(address, args);
        }
    });
    marshaller.marshal(value, System.out);
}
}

顺便说一句,如果我评论为:

public interface IAddress {//extends A, B {

然后我可以得到:

{
  "address" : {
  "postalCode" : "94043",
  "streetAddress" : "1600 Amphitheatre Pkwy",
  "city" : {
     "cityName" : "Mountain View"
  },
  "country" : {
     "countryCode" : "US"
  },
  "state" : {
     "stateCode" : "CA"
  }
}
}

我尝试使用MOXy 2.6.0-M3,它仍然存在同样的问题。

1 个答案:

答案 0 :(得分:0)

以下是答案应该是什么,但它们似乎是一些妨碍它工作的问题:

选项#1 - 更改IAddress

的超级类型

您可以使用MOXy的外部映射文档来指定IAddress的超级类型java.lang.Object,或AB中的一个,而不是{{1} }和A

B

这种重写适用于类,但MOXy在接口上使用时似乎有问题,请参阅以下问题:

选项#2 - 删除<?xml version="1.0"?> <xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" package-name="example.json.demo2"> <java-types> <java-type name="IAddress" super-type="java.lang.Object"/> </java-types> </xml-bindings> &amp;继承层次结构中的A

或者,您可以使用B从继承层次结构中删除xml-transientA(请参阅:http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html)。

B

这种重写适用于类,但MOXy在接口上使用时似乎有问题,请参阅以下问题:

应用外部元数据

创建<?xml version="1.0"?> <xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" package-name="example.json.demo2"> <java-types> <java-type name="A" xml-transient="true"/> <java-type name="B" xml-transient="true"/> </java-types> </xml-bindings> 时应用映射文件,如下所示:

JAXBContext