JAXB-Eclipselink:映射抽象“getter"到 XML [英] JAXB-Eclipselink: Mapping abstract "getter" to XML
问题描述
我正在使用 JAXB 的 EclipseLink 实现 (2.3) 将 POJO 映射到 XML 并遇到以下用例的问题:
I am using the EclipseLink implementation (2.3) of JAXB to map POJOs to XML and encountering a problem with following usecase:
public abstract class A {
public abstract Set<X> getX();
// There is no setter
}
public class B extends A {
// Set via constructor
private Set<X> x;
@Override
public Set<X> getX();
}
我在外部绑定文件中完全定义映射本身,我将类 A 设置为瞬态,如下所示:
I am defining the mapping itself completely in an external bindings-file, i set class A to be transient like so:
<java-type name="foo.A" xml-transient="true"/>
对于 B 类:
<java-type name="bar.B" xml-accessor-type="PROPERTY">
<xml-root-element name="B" />
<java-attributes>
<xml-element java-attribute="x" xml-path="..."/>
</java-attributes>
</java-type>
现在,在编组时,我收到异常:在类 [bar.B] 上发现名为 [x] 的重复属性"在我看来,它来自 A 中的抽象声明,被 B 继承.
Now, upon marshalling i am getting the exception: "Duplicate Property named [x] found on class [bar.B]" which in my opinion is coming from the abstract declaration in A, being inherited by B.
将 B 的访问器类型设置为 FIELD,摆脱了这个错误,不幸的是,这不是一个选项,因为我在 B 中有一个额外的属性来封送它不返回一个字段而是一个计算值,所以我坚持使用 PROPERTY(以下工作:将 B 的访问器类型设置为 FIELD 并使用 @XmlPath 注释映射额外的属性 - 但我不想在我的代码中添加注释).
Setting the accessor-type for B to FIELD, gets rid of this error, unfortunately this is not an option because i do have an extra property in B to marshal which does not return a field but a calculated value, so i am stuck with PROPERTY (following works: setting accessor-type for B to FIELD and mapping the extra property with an @XmlPath annotation - but i dont want annotations in my code).
被 B 类的访问器类型 PROPERTY 困住了,我的下一次尝试是:
Being stuck with accessor-type PROPERTY for class B, my next attempt was:
<java-type name="foo.A" xml-accessor-type="NONE"/>
防止抽象属性被B继承,这让我:
to prevent the abstract property from being inherited by B, which gets me:
Ignoring attribute [x] on class [bar.B] as no Property was generated for it.
使用此映射也会发生同样的情况:
Same is happening using this mapping:
<java-type name="foo.A" xml-accessor-type="PROPERTY">
<java-attributes>
<xml-transient java-attribute="x"/>
</java-attributes>
</java-type>
在这两种情况下,属性x"都被忽略.
In both cases property 'x' is ignored.
我现在真的花了很多时间 - 我无法想象它不可能让它起作用??
I have really spent quite some time on this now - i cant imagine that its not possible to get this to work??
我目前的解决方法:
让 foo.A 为瞬态,为 bar.B 指定访问器类型 FIELD(它毫无问题地获得属性 'x')并使用代码中的注释映射 B 中的额外属性.但如前所述:我想在没有注释的情况下完全解决这个问题-有人知道吗?布莱斯?:)
Leaving foo.A to be transient, specifying accessor-type FIELD for bar.B (which gets me property 'x' without problems) and mapping the extra property in B using an annotation in code. But as mentioned before: I would like to solve this completely without annotations - anybody any idea? Blaise? :)
问候,
--qu
推荐答案
注意:我是EclipseLink JAXB (MOXy) 领导和成员 JAXB 2 (JSR-222) 专家组.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
您似乎遇到了错误.您可以通过以下链接跟踪我们在此问题上的进展.我在下面提供了有关此问题的其他详细信息:
You appear to have hit a bug. You can track our progress on this issue at the following link. I have provided additional details on this issue below:
使用注释
如果您打算使用 JAXB/MOXy 注释映射这个用例,您可以在 A
类上设置 @XmlAccessorType(XmlAccessType.NONE)
并执行如下操作:
If you were going to map this use case with JAXB/MOXy annotations you could set @XmlAccessorType(XmlAccessType.NONE)
on the A
class and do something like:
A
package forum8727402;
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.NONE)
public abstract class A {
public abstract String getX();
}
B
package forum8727402;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
@XmlRootElement
public class B extends A {
@XmlPath("a/b/c/text()")
private String x;
public B() {
x = "Hello World";
}
@Override
public String getX() {
return x;
}
@XmlElement
public String getCalculatedValue() {
return "Calculated Value";
}
}
演示
package forum8727402;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(B.class);
B b = new B();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(b, System.out);
}
}
输出
<?xml version="1.0" encoding="UTF-8"?>
<b>
<a>
<b>
<c>Hello World</c>
</b>
</a>
<calculatedValue>Calculated Value</calculatedValue>
</b>
使用 MOXy 的外部映射文件
oxm.xml
下面是一个 MOXy 外部映射文件表示相当于之前显示的注释:
Below is a MOXy external mapping file that represents the equivalent of the previously shown annotations:
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum8727402">
<java-types>
<java-type name="A" xml-accessor-type="NONE"/>
<java-type name="B">
<xml-root-element/>
<java-attributes>
<xml-element java-attribute="x" xml-path="a/b/c/text()"/>
<xml-element java-attribute="calculatedValue"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
演示
下面的代码演示了如何引用映射文件:
The code below demonstrates how to reference the mapping file:
package forum8727402;
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>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum8727402/oxm.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {A.class, B.class}, properties);
B b = new B();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(b, System.out);
}
}
输出
[EL Warning]: 2012-01-04 14:45:46.366--Ignoring attribute [x] on class [forum8727402.xml.B] as no Property was generated for it.
<?xml version="1.0" encoding="UTF-8"?>
<b>
<calculatedValue>Calculated Value</calculatedValue>
</b>
这篇关于JAXB-Eclipselink:映射抽象“getter"到 XML的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!