将Java对象转换为XML

4
我正在尝试将Java库中的Java对象转换为XML文件。然而,我遇到了这个问题:
A a = new A();

// initializing for a

JAXBContext jc = JAXBContext.newInstance("libraryA.A");

Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(a, System.out);

然后我遇到了这个异常:

javax.xml.bind.JAXBException: "libraryA.a" doesnt contain ObjectFactory.class or jaxb.index
    at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:186)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:128)
    at javax.xml.bind.ContextFinder.find(ContextFinder.java:290)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:372)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:337)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:244)

如果我改成: JAXBContext jc = JAXBContext.newInstance("libraryA.a");

变成:

JAXBContext jc = JAXBContext.newInstance(libraryA.A.class);

然后我又遇到了另一个异常:
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions

library.A is an interface, and JAXB can't handle interfaces.
    this problem is related to the following location:
        at library.A

library.A does not have a no-arg default constructor.
    this problem is related 

to the following location:
    at library.A
2个回答

14

背景信息(来自相关问题

根据你之前问题的评论,该领域模型已经在使用JAXB。要让客户端和服务器通过XML通信的最简单方法是利用两端已有的注释模型。

我刚刚检查了我的客户端源代码。在这个过程中,我们需要使用javax.xml.bind.JAXBContext和javax.xml.bind.Marshaller将从Java对象生成的XML文件转换回XML文件。所以我的问题是,是否可能将XML文件读回到同一个Java对象中?然后我们就可以将Java对象用于进一步的步骤。提前感谢!


更新

看起来你的问题是由于具有由实现类支持的接口定义的领域模型引起的。下面我将演示如何使用JAXB实现(Metro、MOXy、JaxMe等)来处理这个问题。

演示代码

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(CustomerImpl.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("input.xml");
        Customer customer = (Customer) unmarshaller.unmarshal(xml);

        Address address = customer.getAddress();
        System.out.println(address.getStreet());

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }

}

接口模型

以下接口代表我们的领域模型。这些接口将被用来启动JAXBContext。

客户(Customer)

public interface Customer {

    public Address getAddress();

    public void setAddress(Address address);

}

地址

public interface Address {

    public String getStreet();

    public void setStreet(String street);

}

实现类

实现类是使用JAXB将被映射到XML的内容。

CustomerImpl

注意,在 CustomerImpl 类中,我们使用@XmlElement注释在address属性上指定类型为AddressImpl

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="customer")
public class CustomerImpl implements Customer {

    private Address address;

    @XmlElement(type=AddressImpl.class)
    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

}

AddressImpl

=>

AddressImpl

public class AddressImpl implements Address {

    private String street;

    public String getStreet() {
        return street;
    }

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

}

input.xml

<?xml version="1.0" encoding="UTF-8"?>
<customer>
    <address>
        <street>1 Any Street</street>
    </address>
</customer>

@Blaise:但是如果我只能调用Java接口,那么就意味着我不能使用JAXB吗?我说得对吗? - olidev
1
嗨Blaise:我在使用xStream反序列化Java对象时遇到了问题。因此,我想再次尝试JAXB,正如我之前提到的,我们有一个Java库,所以我无法修改它们的实现以添加:@XmlRootElement(name =“customer”),我该怎么办?提前致谢。 - olidev
嗨Blais!感谢您的回答。我仍然有这个问题:com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1个IllegalAnnotationExceptions计数 AImpl没有无参默认构造函数。 此问题与以下位置相关: 在AImpl处=>在我的情况下,AImpl是一个Java对象,提供了一个Java库,因此我无法修改AImpl。您能否帮助我解决这个问题? - olidev
嗨Blaise:我已经在我的包实现中添加了一个名为jaxb.properties的文件,其内容为:javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory,但是我无法将其添加到域类中,因为这些类位于Java库中! - olidev
@JoesyXHN - binding.xml文件是手动创建的,作为提供注释的替代方法。要使用MOXy,您需要提供一个jaxb.properties文件(http://bdoughan.blogspot.com/2011/05/specifying-eclipselink-moxy-as-your.html)。如果在堆栈跟踪中看到com.sun.xml.internal.bind,则说明您没有正确配置MOXy。 - bdoughan
显示剩余6条评论

1

如果您不必使用JAXB,也许可以使用XStream

XStream对于您可以序列化/反序列化到/从XML的内容很少有限制,并且在您不需要特别使用JAXB时可能更为合适。


同意。有很多库可以将对象序列化为XML。JAXB并不是其中最著名的一个。 - Cyde Weys
请查看:http://bdoughan.blogspot.com/2010/10/how-does-jaxb-compare-to-xstream.html - bdoughan
@Cyde Weys -(注意:我领导EclipseLink JAXB(MOXy)实现,并且是JAXB(JSR-222专家组)的成员)我认为JAXB是将对象从XML转换的最知名的API。1)Java SE 6中包含了一个实现,2)它是Java EE的标准部分(用于JAX-WS和JAX-RS的绑定层),并且包含在每个应用程序服务器中 3)有大量在SO上的相关问题4)出现在投票中:http://java.dzone.com/polls/how-do-you-handle-xml-your 5)有多个开源实现:Metro、MOXy、JaxMe等。 - bdoughan
是的,Xtream确实比JAXB更简单! - olidev
1
@JoseyXHN - XStream 是一种序列化器而非映射器(http://xstream.codehaus.org/faq.html#Uses)。使用它可以轻松地获取一个 XML 表示,但不一定是您根据 XML 模式定义的那个,因为 XStream 可能会添加序列化工件(http://stackoverflow.com/questions/5541677/howto-prevent-xstream-from-displaying-class-string)。同时,使用 XStream 进行具有命名空间的 XML 映射可能会很困难(http://www.experts123.com/q/why-does-xstream-not-have-any-namespace-support.html),而使用 JAXB 却非常容易:http://bdoughan.blogspot.com/2010/08/jaxb-namespaces.html。 - bdoughan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接