如何使用JAXB序列化和反序列化对象?

时间:2011-03-04 04:33:05

标签: java jaxb

我有一个问题。我想使用JAXB将对象转换为另一个对象。就像在,我有一个类com.home.Student,另一个类com.school.Student,都有相同的参数,实际上两者都是相同的(复制粘贴),但不同的包。我想使用JAXB执行它们之间的转换。

如何做到这一点,请帮助我。

3 个答案:

答案 0 :(得分:39)

您可以执行以下操作。

注意:

  • 通过利用JAXBSource,它不需要您将数据实现为XML。
  • 您的对象模型不需要任何注释。

<强> com.home.Student

package com.home;

public class Student {

    private String name;
    private Status status;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

}

<强> com.home.Status

package com.home;

public enum Status {

    FULL_TIME("F"),
    PART_TIME("P");

    private final String code;

    Status(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }

}

<强> com.school.Student

package com.school;

public class Student {

    private String name;
    private Status status;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

}

<强> com.school.Status

package com.school;

public enum Status {

    FULL_TIME("F"),
    PART_TIME("P");

    private final String code;

    Status(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }

}

<强> com.example.Demo;

package com.example;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.util.JAXBSource;
import javax.xml.namespace.QName;

public class Demo {

    public static void main(String[] args) throws Exception {
        com.home.Student studentA = new com.home.Student();
        studentA.setName("Jane Doe");
        studentA.setStatus(com.home.Status.FULL_TIME);

        JAXBContext contextA = JAXBContext.newInstance(com.home.Student.class);
        JAXBElement<com.home.Student> jaxbElementA = new JAXBElement(new QName("student"), com.home.Student.class, studentA);
        JAXBSource sourceA = new JAXBSource(contextA, jaxbElementA);

        JAXBContext contextB = JAXBContext.newInstance(com.school.Student.class);
        Unmarshaller unmarshallerB = contextB.createUnmarshaller();
        JAXBElement<com.school.Student> jaxbElementB = unmarshallerB.unmarshal(sourceA, com.school.Student.class);

        com.school.Student studentB = jaxbElementB.getValue();
        System.out.println(studentB.getName());
        System.out.println(studentB.getStatus().getCode());
    }

}

答案 1 :(得分:36)

如果您包含一些解释您问题的代码,那就太好了。

JAXB 101说你应该放置正确的注释,然后你可以正确地序列化和反序列化。您应该使用@XmlRootElement@XmlElement@XmlAttribute等正确注释您的课程

例如:

@XmlRootElement(name="student")
@XmlAccessorType(XmlAccessType.NONE)
class Student {
  @XmlElement(name="name")
  private String name;

  @XmlElement(name="age")
  private int age;

  public Student() {
  }

  public String getName() { return name; }

  public int getAge() { return age; }
}

然后您可以使用JAXB Marshaller来序列化它:

StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance(Student.class);
Marshaller m = context.createMarshaller();
m.marshal(student, writer);

并通过输入Unmarshelling对其进行反序列化。

JAXBContext context = JAXBContext.newInstance(Student.class);
Unmarshaller m = context.createUnmarshaller();
return (Student)m.unmarshal(new StringReader(input));

请确保查看我上面提到的JavaDoc,因为有很多方法可以这样做。

如果你不能修改你的类,你仍然可以使用JAXB(或者你可以使用XStream)假设你的类如下:

class Student {
  private String name;
  private int age;

  public Student() {
  }

  public void setName(String name) { this.name = name; }
  public String getName() { return name; }
  public void setAge(int age) { this.age = age; }
  public int getAge() { return age; }
}

您可以执行以下操作序列化:

Student student = new Student();
student.setAge(25);
student.setName('FooBar');
StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance(Student.class);
Marshaller m = context.createMarshaller();
m.marshal(new JAXBElement(new QName(Student.class.getSimpleName()), Student.class, student), writer);
System.out.println(writer.toString());

如果您使用XStream,则可以在没有注释的情况下进行序列化(并且它更易于控制)。 http://x-stream.github.io/tutorial.html

答案 2 :(得分:2)

如果你的目标只是在两者之间进行转换(实际分配),除了包名之外它们是相同的,我认为你可以使用简单的反射。只需遍历源对象的字段,并分配给目标对象中的同名字段。模糊地,像这样:

import java.lang.reflect.Field;

public class Converter {
    public void convert (com.home.Student src, com.school.Student dst) throws Exception {
        for (Field f : src.getFields()) {

            // src field name
            String name = f.getName();

            // get corresponding field in dst
            Field dstField = dst.getDeclaredField(name);

            dstField.set(dst, f.get());
        }
    }
}

注意:我没有编译这个,这就是为什么我说“模糊”。如果字段是私有的,则需要使用Field.isAccessible()/ Field.setAccessible(true),以便在分配值时临时更改可访问性。或者,您编写的代码稍微复杂一些,使用公共setter / getter而不是直接使用字段访问。