Inheritance eclipselink/Moxy:基于类型的继承和属性名称加载
我面临一个编组/解编问题,涉及使用MOXy的JAXB实现和外部元数据绑定文件的继承和多态性 我无法控制XML文件或模型类 模型中有多个继承其他DTO类的类。 这是我工作环境的一个例子。此示例仅用于某些语法目的,实际环境涉及嵌套继承、集合等: 下面是将被继承的类Inheritance eclipselink/Moxy:基于类型的继承和属性名称加载,inheritance,jaxb,polymorphism,eclipselink,moxy,Inheritance,Jaxb,Polymorphism,Eclipselink,Moxy,我面临一个编组/解编问题,涉及使用MOXy的JAXB实现和外部元数据绑定文件的继承和多态性 我无法控制XML文件或模型类 模型中有多个继承其他DTO类的类。 这是我工作环境的一个例子。此示例仅用于某些语法目的,实际环境涉及嵌套继承、集合等: 下面是将被继承的类 class A { private String name; public String getName(){ return name; }
class A {
private String name;
public String getName(){
return name;
}
public void setName(String value){
name = value;
}
}
下面是一个继承的类
class B extends A {
private String attrFromB;
public String getAttrFromB(){
return attrFromB;
}
public void setAttrFromB(String value){
attrFromB = value;
}
}
还有一个
class C extends A {
private String attrFromC;
public String getAttrFromC(){
return attrFromC;
}
public void setAttrFromC(String value){
attrFromC= value;
}
}
这是一个容器类
class MyContainerClass{
private A myObject;
public A getMyObject(){
return myObject;
}
public void setMyObject(A value){
myObject = value;
}
}
下面是在MyContainer包含
<MyContainer>
<MyObject nameA="foo" />
</MyContainer>
第一个问题:我知道这是正常的,Jaxb需要某种方法来确定myContainer.myObject属性的类型。问题是我无法访问传入的XML文件,因此无法向其中添加xsi:type字段。有没有一种方法可以根据类中特定属性的存在来确定类?不管它的价值如何。如果源xml包含@attrFromC属性,我知道该对象的类型应该是C。如果它包含attrFromB,则为B
第二个问题是“name”属性在B和C中不存在,因此jaxb忽略了em
--Ignoring attribute [name] on class [com.test.example.B] as no Property was generated for it.
--Ignoring attribute [name] on class [com.test.example.C] as no Property was generated for it.
第二个问题:另一个问题是,我不知道Jaxb是否能够像xml文件中预期的那样覆盖xml属性名(@nameA、@nameB和nameC都指A.name),有没有办法做到这一点
提前感谢您的时间。以下是您问题的答案。问题2的答案也是问题1的答案
第一个问题:我理解这是正常的,Jaxb需要一些方法 确定myContainer.myObject属性的类型。问题 我无法访问传入的XML文件,因此无法添加 xsi:为它们键入字段。有没有一种方法可以根据 其中是否存在特定属性?不管它的价值如何。 如果源xml包含@attrFromC属性,则我知道该对象 应该是C类型。如果它包含attrFromB,则为B 对于此用例,您可以利用中的
ClassExtractor
扩展:
MyClassExtractor
package com.test.example;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class AAdapter extends XmlAdapter<AAdapter.AdaptedA, A> {
@Override
public AdaptedA marshal(A a) throws Exception {
if(null == a) {
return null;
}
AdaptedA adaptedA = new AdaptedA();
if(a instanceof C) {
C c = (C) a;
adaptedA.nameC = c.getName();
adaptedA.attrFromC = c.getAttrFromC();
} else if(a instanceof B) {
B b = (B) a;
adaptedA.nameB = b.getName();
adaptedA.attrFromB = b.getAttrFromB();
} else if(a instanceof A) {
adaptedA.nameA = a.getName();
}
return adaptedA;
}
@Override
public A unmarshal(AdaptedA adaptedA) throws Exception {
if(null == adaptedA) {
return null;
}
if(null != adaptedA.attrFromC) {
C c = new C();
c.setName(adaptedA.nameC);
c.setAttrFromC(adaptedA.attrFromC);
return c;
} else if(null != adaptedA.attrFromB) {
B b = new B();
b.setName(adaptedA.nameB);
b.setAttrFromB(adaptedA.attrFromB);
return b;
}
A a = new A();
a.setName(adaptedA.nameA);
return a;
}
public static class AdaptedA {
@XmlAttribute public String nameA;
@XmlAttribute public String nameB;
@XmlAttribute public String nameC;
@XmlAttribute public String attrFromB;
@XmlAttribute public String attrFromC;
}
}
ClassExtractor
是一些代码,您可以实现这些代码来帮助MOXy确定它应该实例化哪个类。将向您传递一条记录
,您可以通过XPath请求当前元素中是否存在属性,以确定应该实例化哪个类
package com.test.example;
import org.eclipse.persistence.descriptors.ClassExtractor;
import org.eclipse.persistence.sessions.*;
public class MyClassExtractor extends ClassExtractor{
@Override
public Class<?> extractClassFromRow(Record record, Session session) {
if(null != record.get("@attrFromB")) {
return B.class;
} else if(null != record.get("@attrFromC")) {
return C.class;
} else {
return A.class;
}
}
}
演示
下面的演示代码从您的问题中解组每个XML文档,并输出由myObject
属性持有的类型:
package com.test.example;
import java.io.StringReader;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "com/test/example/oxm.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {MyContainerClass.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StringReader aXml = new StringReader("<MyContainer><MyObject nameA='foo'/></MyContainer>");
MyContainerClass myContainerA = (MyContainerClass) unmarshaller.unmarshal(aXml);
System.out.println(myContainerA.getMyObject().getClass());
StringReader bXml = new StringReader("<MyContainer><MyObject nameB='foo' attrFromB='bar'/></MyContainer>");
MyContainerClass myContainerB = (MyContainerClass) unmarshaller.unmarshal(bXml);
System.out.println(myContainerB.getMyObject().getClass());
StringReader cXml = new StringReader("<MyContainer><MyObject nameC='foo' attrFromC='bar'/></MyContainer>");
MyContainerClass myContainerC = (MyContainerClass) unmarshaller.unmarshal(cXml);
System.out.println(myContainerC.getMyObject().getClass());
}
}
第二个问题:另一个问题是我不知道Jaxb是否正确 能够覆盖xml属性名称,就像内部所期望的那样 XML文件(@nameA、@nameB和nameC都指A.name)是 有办法吗 对于这个问题,您可以使用
XmlAdapter
。此方法也可用于回答您的第一个问题:
a适应
package com.test.example;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class AAdapter extends XmlAdapter<AAdapter.AdaptedA, A> {
@Override
public AdaptedA marshal(A a) throws Exception {
if(null == a) {
return null;
}
AdaptedA adaptedA = new AdaptedA();
if(a instanceof C) {
C c = (C) a;
adaptedA.nameC = c.getName();
adaptedA.attrFromC = c.getAttrFromC();
} else if(a instanceof B) {
B b = (B) a;
adaptedA.nameB = b.getName();
adaptedA.attrFromB = b.getAttrFromB();
} else if(a instanceof A) {
adaptedA.nameA = a.getName();
}
return adaptedA;
}
@Override
public A unmarshal(AdaptedA adaptedA) throws Exception {
if(null == adaptedA) {
return null;
}
if(null != adaptedA.attrFromC) {
C c = new C();
c.setName(adaptedA.nameC);
c.setAttrFromC(adaptedA.attrFromC);
return c;
} else if(null != adaptedA.attrFromB) {
B b = new B();
b.setName(adaptedA.nameB);
b.setAttrFromB(adaptedA.attrFromB);
return b;
}
A a = new A();
a.setName(adaptedA.nameA);
return a;
}
public static class AdaptedA {
@XmlAttribute public String nameA;
@XmlAttribute public String nameB;
@XmlAttribute public String nameC;
@XmlAttribute public String attrFromB;
@XmlAttribute public String attrFromC;
}
}
package com.test.example;
导入javax.xml.bind.annotation.XmlAttribute;
导入javax.xml.bind.annotation.adapters.XmlAdapter;
公共类AAdapter扩展了XmlAdapter{
@凌驾
公共适配器封送处理程序(A)引发异常{
如果(null==a){
返回null;
}
AdaptedA AdaptedA=新AdaptedA();
if(C的一个实例){
C=(C)a;
adaptedA.nameC=c.getName();
adaptedA.attrFromC=c.getAttrFromC();
}else if(B的a实例){
B=(B)a;
adaptedA.nameB=b.getName();
adaptedA.attrFromB=b.getAttrFromB();
}else if(a的实例){
adaptedA.nameA=a.getName();
}
返回自适应a;
}
@凌驾
公共解组(AdaptedA AdaptedA)引发异常{
if(null==adaptedA){
返回null;
}
if(null!=adaptedA.attrFromC){
C=新的C();
c、 setName(adaptedA.nameC);
c、 setAttrFromC(adaptedA.attrFromC);
返回c;
}else if(null!=adaptedA.attrFromB){
B=新的B();
b、 setName(adaptedA.nameB);
b、 setAttrFromB(adaptedA.attrFromB);
返回b;
}
A=新的A();
a、 setName(adaptedA.nameA);
返回a;
}
公共静态类Adapted{
@XmlAttribute公共字符串名称a;
@XmlAttribute公共字符串nameB;
@XmlAttribute公共字符串nameC;
@XmlAttribute公共字符串attrFromB;
@xmldattribute公共字符串attrFromC;
}
}
元数据(oxm-2.xml)
Demo2
package com.test.example;
import java.io.StringReader;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class Demo2 {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "com/test/example/oxm-2.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {MyContainerClass.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringReader aXml = new StringReader("<MyContainer><MyObject nameA='foo'/></MyContainer>");
MyContainerClass myContainerA = (MyContainerClass) unmarshaller.unmarshal(aXml);
System.out.println(myContainerA.getMyObject().getClass());
marshaller.marshal(myContainerA, System.out);
StringReader bXml = new StringReader("<MyContainer><MyObject nameB='foo' attrFromB='bar'/></MyContainer>");
MyContainerClass myContainerB = (MyContainerClass) unmarshaller.unmarshal(bXml);
System.out.println(myContainerB.getMyObject().getClass());
marshaller.marshal(myContainerB, System.out);
StringReader cXml = new StringReader("<MyContainer><MyObject nameC='foo' attrFromC='bar'/></MyContainer>");
MyContainerClass myContainerC = (MyContainerClass) unmarshaller.unmarshal(cXml);
System.out.println(myContainerC.getMyObject().getClass());
marshaller.marshal(myContainerC, System.out);
}
}
package com.test.example;
导入java.io.StringReader;
导入java.util.*;
导入javax.xml.bind.*;
导入org.eclipse.persistence.jaxb.JAXBContextFactory;
公开课演示2{
公共静态void main(字符串[]args)引发异常{
映射属性=新的HashMap();
put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY,“com/test/example/OXM-2.XML”);
JAXBContext jc=JAXBContext.newInstance(新类[]{MyContainerClass.Class},属性);
Unmarshaller Unmarshaller=jc.createUnmarshaller();
Marshaller=jc.createMarshaller();
setProperty(marshaller.JAXB_格式化的_输出,true);
StringReader aXml=新的StringReader(“”);
MyContainerClass myContainerA=(MyContainerClass)解组器.解组器(aXml);
系统输出打印LN(myContainerA.getMyOb
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="com.test.example"
version="2.3">
<java-types>
<java-type name="A" xml-accessor-type="NONE">
<xml-class-extractor class="com.test.example.MyClassExtractor"/>
<xml-root-element name="MyObject" />
<java-attributes>
<xml-attribute java-attribute="name" name="nameA" />
</java-attributes>
</java-type>
<java-type name="B" xml-accessor-type="NONE">
<xml-root-element name="MyObject" />
<java-attributes>
<xml-attribute java-attribute="name" name="nameB" />
<xml-attribute java-attribute="attrFromB"/>
</java-attributes>
</java-type>
<java-type name="C" xml-accessor-type="NONE">
<xml-root-element name="MyObject" />
<java-attributes>
<xml-attribute java-attribute="name" name="nameC" />
<xml-attribute java-attribute="attrFromC"/>
</java-attributes>
</java-type>
<java-type name="MyContainerClass" xml-accessor-type="NONE">
<xml-root-element name="MyContainer" />
<java-attributes>
<xml-element java-attribute="myObject" name="MyObject" />
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
package com.test.example;
import java.io.StringReader;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "com/test/example/oxm.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {MyContainerClass.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StringReader aXml = new StringReader("<MyContainer><MyObject nameA='foo'/></MyContainer>");
MyContainerClass myContainerA = (MyContainerClass) unmarshaller.unmarshal(aXml);
System.out.println(myContainerA.getMyObject().getClass());
StringReader bXml = new StringReader("<MyContainer><MyObject nameB='foo' attrFromB='bar'/></MyContainer>");
MyContainerClass myContainerB = (MyContainerClass) unmarshaller.unmarshal(bXml);
System.out.println(myContainerB.getMyObject().getClass());
StringReader cXml = new StringReader("<MyContainer><MyObject nameC='foo' attrFromC='bar'/></MyContainer>");
MyContainerClass myContainerC = (MyContainerClass) unmarshaller.unmarshal(cXml);
System.out.println(myContainerC.getMyObject().getClass());
}
}
[EL Warning]: 2012-01-20 10:36:41.828--Ignoring attribute [name] on class [com.test.example.B] as no Property was generated for it.
[EL Warning]: 2012-01-20 10:36:41.828--Ignoring attribute [name] on class [com.test.example.C] as no Property was generated for it.
class com.test.example.A
class com.test.example.B
class com.test.example.C
package com.test.example;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class AAdapter extends XmlAdapter<AAdapter.AdaptedA, A> {
@Override
public AdaptedA marshal(A a) throws Exception {
if(null == a) {
return null;
}
AdaptedA adaptedA = new AdaptedA();
if(a instanceof C) {
C c = (C) a;
adaptedA.nameC = c.getName();
adaptedA.attrFromC = c.getAttrFromC();
} else if(a instanceof B) {
B b = (B) a;
adaptedA.nameB = b.getName();
adaptedA.attrFromB = b.getAttrFromB();
} else if(a instanceof A) {
adaptedA.nameA = a.getName();
}
return adaptedA;
}
@Override
public A unmarshal(AdaptedA adaptedA) throws Exception {
if(null == adaptedA) {
return null;
}
if(null != adaptedA.attrFromC) {
C c = new C();
c.setName(adaptedA.nameC);
c.setAttrFromC(adaptedA.attrFromC);
return c;
} else if(null != adaptedA.attrFromB) {
B b = new B();
b.setName(adaptedA.nameB);
b.setAttrFromB(adaptedA.attrFromB);
return b;
}
A a = new A();
a.setName(adaptedA.nameA);
return a;
}
public static class AdaptedA {
@XmlAttribute public String nameA;
@XmlAttribute public String nameB;
@XmlAttribute public String nameC;
@XmlAttribute public String attrFromB;
@XmlAttribute public String attrFromC;
}
}
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="com.test.example"
version="2.3">
<java-types>
<java-type name="MyContainerClass" xml-accessor-type="NONE">
<xml-root-element name="MyContainer" />
<java-attributes>
<xml-element java-attribute="myObject" name="MyObject">
<xml-java-type-adapter value="com.test.example.AAdapter"/>
</xml-element>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
package com.test.example;
import java.io.StringReader;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class Demo2 {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "com/test/example/oxm-2.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {MyContainerClass.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringReader aXml = new StringReader("<MyContainer><MyObject nameA='foo'/></MyContainer>");
MyContainerClass myContainerA = (MyContainerClass) unmarshaller.unmarshal(aXml);
System.out.println(myContainerA.getMyObject().getClass());
marshaller.marshal(myContainerA, System.out);
StringReader bXml = new StringReader("<MyContainer><MyObject nameB='foo' attrFromB='bar'/></MyContainer>");
MyContainerClass myContainerB = (MyContainerClass) unmarshaller.unmarshal(bXml);
System.out.println(myContainerB.getMyObject().getClass());
marshaller.marshal(myContainerB, System.out);
StringReader cXml = new StringReader("<MyContainer><MyObject nameC='foo' attrFromC='bar'/></MyContainer>");
MyContainerClass myContainerC = (MyContainerClass) unmarshaller.unmarshal(cXml);
System.out.println(myContainerC.getMyObject().getClass());
marshaller.marshal(myContainerC, System.out);
}
}
class com.test.example.A
<?xml version="1.0" encoding="UTF-8"?>
<MyContainer>
<MyObject nameA="foo"/>
</MyContainer>
class com.test.example.B
<?xml version="1.0" encoding="UTF-8"?>
<MyContainer>
<MyObject nameB="foo" attrFromB="bar"/>
</MyContainer>
class com.test.example.C
<?xml version="1.0" encoding="UTF-8"?>
<MyContainer>
<MyObject nameC="foo" attrFromC="bar"/>
</MyContainer>