web-dev-qa-db-fra.com

Comment sérialiser et désérialiser des objets à l'aide de JAXB?

J'ai un problème. Je veux convertir un objet en un autre objet en utilisant JAXB. Comme dans, j'ai une classe com.home.Student, et une autre classe com.school.Student, les deux ont les mêmes arguments, en fait les deux sont identiques (copier-coller), mais un package différent. Je veux effectuer la conversion entre eux en utilisant JAXB.

Comment faire, s'il vous plaît, aidez-moi.

36
M.J.

Vous pouvez faire ce qui suit.

Remarque:

  • Il ne nécessite pas que vous matérialisiez les données au format XML, en exploitant JAXBSource.
  • Il ne nécessite aucune annotation sur votre modèle d'objet.

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

Ce serait bien si vous incluiez du code qui explique votre problème.

JAXB 101 dit que vous devez placer les bonnes annotations, puis vous pouvez sérialiser et désérialiser correctement. Vous devez annoter correctement vos classes avec @ XmlRootElement , @ XmlElement , @ XmlAttribute , etc.

Par exemple:

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

Ensuite, vous pouvez le sérialiser en utilisant JAXB Marshaller :

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

Et désérialisez-le également en nmarshelling l'entrée ..

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

Assurez-vous de regarder le JavaDoc que j'ai mentionné ci-dessus car il existe de nombreuses façons de le faire.

Si vous ne pouvez pas modifier vos classes, vous pouvez toujours utiliser JAXB (ou vous pouvez utiliser XStream) En supposant que votre classe est la suivante:

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

Vous pouvez le sérialiser en faisant:

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

Si vous utilisez XStream , vous pouvez également effectuer la sérialisation sans annotations (et c'est plus contrôlable). http://x-stream.github.io/tutorial.html

37
Mohamed Mansour

Si votre objectif est simplement de convertir (attribuer en fait) entre les deux, et qu'ils sont identiques sauf le nom du package, je pense que vous pourriez utiliser une réflexion simple. Parcourez simplement les champs de l'objet source et attribuez-les au champ du même nom dans l'objet cible. Vaguement, comme ceci:

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

Remarque: je n'ai pas compilé cela, c'est pourquoi je dis "vaguement". Vous devrez utiliser Field.isAccessible ()/Field.setAccessible (true) si les champs sont privés, afin de pouvoir modifier temporairement l'accessibilité pendant que vous attribuez des valeurs. Ou, vous écrivez un code légèrement plus complexe qui utilise des setters/getters publics plutôt que d'utiliser directement l'accès aux champs.

2
Kevin