web-dev-qa-db-ja.com

JAXBを使用してオブジェクトをシリアライズおよびデシリアライズする方法は?

問題があります。 JAXBを使用してオブジェクトを別のオブジェクトに変換したい。同様に、クラスcom.home.Studentと別のクラスcom.school.Studentがあり、両方とも同じ引数を持ちます。実際、両方は同じ(コピーペースト)ですが、パッケージは異なります。 JAXBを使用して、それらの間の変換を実行します。

それを行う方法は、私を助けてください。

36
M.J.

次のことができます。

注:

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

}
40
bdoughan

問題を説明するコードを含めておくといいでしょう。

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

そして、 nmarshelling the input ..によってもデシリアライズします。

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

37
Mohamed Mansour

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)を使用する必要があります。これにより、値を割り当てている間に一時的にアクセシビリティを変更できます。または、フィールドアクセスを直接使用するのではなく、パブリックセッター/ゲッターを使用する少し複雑なコードを記述します。

2
Kevin