3
votes

Comment transformer un JSON plat en classe Java hiérarchique?

Je dois désérialiser un objet JSON plat en un objet Java avec certaines propriétés définies sur un objet enfant.

Class Student {
  String name;
  Address address;
}

Class Address {
 String line1;
 String line2;
}

{
 "name": "abcd",
 "addressLine1": "123",
 "addressLine2": "1111"
}

Comment désérialiser mon JSON à l'aide de Jackson en un objet Student ? Je ne peux pas mapper addressLine1 à Student.Address.line1 et addressLine2 à Student.Address.line2


1 commentaires

êtes-vous sûr du json? name, addressLine1 et addressLine2 ne sont-ils pas entre guillemets? aussi la virgule après "1111" le rend invalide.


4 Réponses :



0
votes

Vous pouvez utiliser ObjectMapper comme ceci:

Class Student{
    String name;
    String addressLine1;
    String addressLine2;
} 

Mais vous devez également modifier la classe Student comme suit avec tous les getters et setters implémentés:

ObjectMapper objectMapper = new ObjectMapper();
Student student = objectMapper.readValue(json, Student.class);


0 commentaires

1
votes

EDIT: Tant que mes solutions fonctionnent, la réponse de Selindek est la meilleure

Votre Json n'est pas valide selon https://jsonlint.com/ pour 2 raisons:

  • Les noms de vos champs ne sont pas cités
  • Vous avez une virgule après la dernière ligne

Je vais assumer ce JSON, avec des noms de champs sans guillemets:

mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

Je peux penser à 2 approches:

1 - Traitement simple des cartes

{
    "name": "abcd",
    "addressLine1": "123",
    "addressLine2": "1111"
}

2 - Utilisation d'un objet Proxy (je préférerais celui-ci)

Une autre approche serait d'avoir une classe proxy dans laquelle vous pouvez désérialiser votre JSON, et construire votre étudiant à partir de celui-ci:

// Create your mapper, and configure it to allow unquoted field names
ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

// Parse the JSON to a RawStudent object
RawStudent rawStudent = null;
try {
    rawStudent = mapper.readValue(jsonUnquoted, RawStudent.class);
} catch (Exception e) {
    System.out.println("Something went wrong:" + e.getMessage());
}


// Read the data from the map and build your objects
Student student = null;
if (rawStudent != null) {

    student = rawStudent.toStudent();

    System.out.println(student.getName());
    System.out.println(student.getAddress().getLine1());
    System.out.println(student.getAddress().getLine2());
}

Et l'utiliser de cette façon: p >

class RawStudent {
    private String name, addressLine1, addressLine2;

    public Student toStudent() {
        Address address = new Address();
        address.setLine1(addressLine1);
        address.setLine2(addressLine2);

        Student student = new Student();
        student.setName(name);
        student.setAddress(address);

        return student;
    }

    // GETTERS / SETTERS

}

REMARQUE

Si vous avez mal saisi et avez effectivement cité des champs, par exemple:

// Create your mapper, and configure it to allow unquoted field names
ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

// Parse the JSON to a Map
TypeReference<HashMap<String, String>> typeRef
        = new TypeReference<HashMap<String, String>>() {};
Map<String, String> jsonAsMap = null;
try {
    jsonAsMap = mapper.readValue(yourJsonString, typeRef);
} catch (Exception e) {
    System.out.println("Something went wrong:" + e.getMessage());
}


// Read the data from the map and build your objects
Student student = null;
if(jsonAsMap != null) {

    Address address = new Address();
    address.setLine1(jsonAsMap.get("addressLine1"));
    address.setLine2(jsonAsMap.get("addressLine2"));

    student = new Student();
    student.setName(jsonAsMap.get("name"));
    student.setAddress(address);

    System.out.println(student.getName());
    System.out.println(student.getAddress().getLine1());
    System.out.println(student.getAddress().getLine2());
}

Alors vous n'avez pas besoin de cette ligne

{
    name: "abcd",
    addressLine1: "123",
    addressLine2: "1111"
}


0 commentaires

4
votes

Vous pouvez définir vos classes de données de cette manière:

mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

Ensuite, vous pouvez utiliser l ' Objectmapper de la manière habituelle - sans magie supplémentaire ni solution de contournement: p>

Student student = mapper.readValue(json, Student.class);

Si votre chaîne json entrante est effectivement au format que vous avez fourni (sans guillemets), ajoutez également:

  public static class Student {
    String name;

    @JsonUnwrapped
    Address address;
  }

  public static class Address {
    @JsonProperty("addressLine1")
    String line1;
    @JsonProperty("addressLine2")
    String line2;
  }


5 commentaires

Agréable! Je ne connaissais pas cette annotation @JsonUnwrapped . Je pense que vous devez annoter l'attribut name avec @JsonProperty .


Vous pouvez également annoter la propriété name, mais ce n'est pas nécessaire, car le nom de la propriété dans la classe et le nom de la propriété dans la chaîne json sont identiques.


J'ai simplement soulevé le problème parce que j'ai essayé de l'exécuter et que cela ne fonctionnait pas pour moi sans l'annotation.


C'est intéressant. Je l'ai essayé avant de publier la réponse et cela a fonctionné pour moi avec plus rapidexml 2.9.8. Peut-être que vous utilisez un autre package ou version avec des paramètres par défaut différents.


Je suppose que cela n'a pas vraiment d'importance, ce n'est pas de toute façon la question qui se pose :)