JAXB-Eclipselink:映射抽象“getter”到 XML

发布于 2024-12-24 22:57:49 字数 1710 浏览 2 评论 0原文

我正在使用 JAXB 的 EclipseLink 实现 (2.3) 将 POJO 映射到 XML,并遇到以下用例的问题:

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 设置为瞬态,如下所示

<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 继承。

将 B 的访问器类型设置为 FIELD,可以消除此错误,不幸的是,这不是一个选项,因为我在 B 中确实有一个额外的属性marshal 不返回字段,而是返回计算值,因此我陷入了 PROPERTY 的困境(以下工作:将 B 的访问器类型设置为 FIELD 并使用 @XmlPath 注释映射额外的属性 - 但我不想在代码中使用注释) 。

由于受困于类 B 的访问器类型 PROPERTY,我的下一个尝试是:

<java-type name="foo.A" xml-accessor-type="NONE"/>

防止抽象属性被 B 继承,这让我明白:

Ignoring attribute [x] on class [bar.B] as no Property was generated for it.

使用此映射也会发生同样的情况:

<java-type name="foo.A" xml-accessor-type="PROPERTY">
    <java-attributes>
        <xml-transient java-attribute="x"/>
    </java-attributes>
</java-type>

在这两种情况下,属性“x”都被忽略。

我现在确实花了相当多的时间在这上面 - 我无法想象它不可能让它工作?

我目前的解决方法:

将 foo.A 保留为瞬态,为 bar.B 指定访问器类型FIELD(这可以毫无问题地获取属性“x”)并使用代码中的注释映射 B 中的额外属性。 但正如之前提到的:我想在没有注释的情况下完全解决这个问题 - 有人知道吗?布莱斯? :)

问候,

--qu

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();

}

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"/>

and for class 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>

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.

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).

Being stuck with accessor-type PROPERTY for class B, my next attempt was:

<java-type name="foo.A" xml-accessor-type="NONE"/>

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>

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??

My workaround at the moment:

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? :)

regards,

--qu

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

围归者 2024-12-31 22:57:49

注意:我是EclipseLink JAXB (MOXy) 的领导者和 JAXB 2 的成员(JSR-222)专家组。

您似乎遇到了错误。您可以通过以下链接跟踪我们在此问题上的进展。我在下面提供了有关此问题的更多详细信息:


使用注释

如果您要使用 JAXB/MOXy 注释来映射此用例,您可以在A 类并执行以下操作:

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< /em>

下面是一个 MOXy 外部映射文件,表示与前面显示的注释等效的内容:

<?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>

演示

下面的代码演示了如何引用映射文件:

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>

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:


Using Annotations

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";
    }

}

Demo

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);
    }

}

Output

<?xml version="1.0" encoding="UTF-8"?>
<b>
   <a>
      <b>
         <c>Hello World</c>
      </b>
   </a>
   <calculatedValue>Calculated Value</calculatedValue>
</b>

Using MOXy's External Mapping File

oxm.xml

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>

Demo

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);
    }

}

Output

[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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文