Le message d'erreur suivant s'affiche lorsque j'essaie d'obtenir une demande JSON et de la traiter:
org.codehaus.jackson.map.JsonMappingException: aucun constructeur approprié trouvé pour le type [type simple, classe com.myweb.ApplesDO]: impossible d'instancier un objet JSON (nécessité d'ajouter/d'activer des informations de type?)
Voici le JSON que j'essaye d'envoyer:
{
"applesDO" : [
{
"Apple" : "Green Apple"
},
{
"Apple" : "Red Apple"
}
]
}
Dans Controller, j'ai la signature de méthode suivante:
@RequestMapping("showApples.do")
public String getApples(@RequestBody final AllApplesDO applesRequest){
// Method Code
}
AllApplesDO est une enveloppe d'ApplesDO:
public class AllApplesDO {
private List<ApplesDO> applesDO;
public List<ApplesDO> getApplesDO() {
return applesDO;
}
public void setApplesDO(List<ApplesDO> applesDO) {
this.applesDO = applesDO;
}
}
PommesDO:
public class ApplesDO {
private String Apple;
public String getApple() {
return Apple;
}
public void setApple(String appl) {
this.Apple = Apple;
}
public ApplesDO(CustomType custom){
//constructor Code
}
}
Je pense que Jackson est incapable de convertir JSON en objets Java pour les sous-classes. S'il vous plaît aider avec les paramètres de configuration pour Jackson pour convertir JSON en objets Java. J'utilise Spring Framework.
EDIT: Inclusion du bogue principal à l’origine de ce problème dans l’exemple de classe ci-dessus - Consultez la réponse acceptée pour obtenir une solution.
Alors, finalement, j'ai réalisé quel était le problème. Ce n'est pas un problème de configuration de Jackson, comme j'en ai douté.
En fait, le problème était dans ApplesDO Class:
public class ApplesDO {
private String Apple;
public String getApple() {
return Apple;
}
public void setApple(String Apple) {
this.Apple = Apple;
}
public ApplesDO(CustomType custom) {
//constructor Code
}
}
Un constructeur personnalisé a été défini pour la classe, ce qui en fait le constructeur par défaut. L'introduction d'un constructeur factice a commis l'erreur de partir:
public class ApplesDO {
private String Apple;
public String getApple() {
return Apple;
}
public void setApple(String Apple) {
this.Apple = Apple;
}
public ApplesDO(CustomType custom) {
//constructor Code
}
//Introducing the dummy constructor
public ApplesDO() {
}
}
Cela se produit pour ces raisons:
votre classe interne doit être définie comme static
private static class Condition { //jackson specific
}
Il se peut que vous n'ayez aucun constructeur par défaut dans votre classe ( UPDATE: Cela semble ne pas être le cas)
private static class Condition {
private Long id;
public Condition() {
}
// Setters and Getters
}
Il se peut que vos Setters ne soient pas définis correctement ou ne soient pas visibles (par exemple, un passeur privé)
Je voudrais ajouter une autre solution à cela qui ne nécessite pas de constructeur factice. Étant donné que les constructeurs factices sont un peu brouillons et prêtent à confusion. Nous pouvons fournir un constructeur sûr et en annotant les arguments du constructeur, nous permettons à Jackson de déterminer le mappage entre le paramètre du constructeur et le champ.
donc ce qui suit fonctionnera aussi. Notez que la chaîne à l'intérieur de l'annotation doit correspondre au nom du champ.
import com.fasterxml.jackson.annotation.JsonProperty;
public class ApplesDO {
private String Apple;
public String getApple() {
return Apple;
}
public void setApple(String Apple) {
this.Apple = Apple;
}
public ApplesDO(CustomType custom){
//constructor Code
}
public ApplesDO(@JsonProperty("Apple")String Apple) {
}
}
Lorsque j’ai rencontré ce problème, c’est parce que j’ai essayé d’utiliser une classe interne pour servir de DO. La construction de la classe interne (en silence) nécessite une instance de la classe englobante - ce qui n'était pas disponible pour Jackson.
Dans ce cas, le déplacement de la classe interne vers son propre fichier .Java a résolu le problème.
Généralement, cette erreur survient parce que nous n’avons pas créé de constructeur par défaut, mais dans mon cas, le problème ne venait que parce que j’ai créé une classe d’objet used dans la classe parente. Cela a perdu toute ma journée.
Thumb Rule : Ajoutez un constructeur par défaut pour chaque classe que vous avez utilisée en tant que classe de mappage. Vous avez manqué cela et le problème se pose!
Ajoutez simplement le constructeur par défaut et cela devrait fonctionner.
Pouvez-vous s'il vous plaît tester cette structure. Si je me souviens bien, vous pouvez l'utiliser de cette façon:
{
"applesRequest": {
"applesDO": [
{
"Apple": "Green Apple"
},
{
"Apple": "Red Apple"
}
]
}
}
Deuxièmement, veuillez ajouter le constructeur par défaut à chaque classe, cela pourrait également aider.
Vous devez créer un constructeur vide factice dans notre classe de modèle. Ainsi, lors du mappage JSON, il est défini par la méthode setter.
Si vous commencez à annoter le constructeur, vous devez annoter tous les champs.
Remarquez que mon champ Staff.name est associé à "ANOTHER_NAME" dans la chaîne JSON.
String jsonInString="{\"ANOTHER_NAME\":\"John\",\"age\":\"17\"}";
ObjectMapper mapper = new ObjectMapper();
Staff obj = mapper.readValue(jsonInString, Staff.class);
// print to screen
public static class Staff {
public String name;
public Integer age;
public Staff() {
}
//@JsonCreator - don't need this
public Staff(@JsonProperty("ANOTHER_NAME") String n,@JsonProperty("age") Integer a) {
name=n;age=a;
}
}
Vous devez savoir quelles options Jackson dispose pour la désérialisation. En Java, les noms d'argument de méthode ne sont pas présents dans le code compilé. C'est pourquoi Jackson ne peut généralement pas utiliser les constructeurs pour créer un objet bien défini avec tout ce qui est déjà défini.
Donc, s'il y a un constructeur vide et qu'il y a aussi des setters, il utilise le constructeur vide et les setters. S'il n'y a pas de setters, une magie noire (réflexions) est utilisée pour le faire.
Si vous souhaitez utiliser un constructeur avec Jackson, vous devez utiliser les annotations mentionnées par @PiersyP dans sa réponse. Vous pouvez également utiliser un modèle de générateur. Si vous rencontrez des exceptions, bonne chance. La gestion des erreurs dans Jackson est très pénible, il est difficile de comprendre ce charabia dans les messages d'erreur.
En ce qui concerne la dernière publication, le problème était identique à celui de l'utilisation de Lombok 1.18. *.
Ma solution a été d'ajouter @NoArgsConstructor (constructeur sans paramètres), car @Data inclut par défaut @RequiredArgsConstructor (constructeur avec paramètres).
documentation lombok https://projectlombok.org/features/all
Cela résoudrait le problème:
package example.counter;
import javax.validation.constraints.NotNull;
import lombok.Data;
@Data
@NoArgsConstructor
public class CounterRequest {
@NotNull
private final Integer int1;
@NotNull
private final Integer int2;
}
Le problème réside également dans l’échec des sérialiseurs/désérialiseurs jackson personnalisés. Bien que ce ne soit pas votre cas, il convient de le mentionner.
J'ai fait face à la même exception et c'était le cas.
Pour moi, cela fonctionnait auparavant, mais la mise à niveau des bibliothèques a entraîné l'apparition de ce problème. Le problème était d'avoir un cours comme celui-ci:
package example.counter;
import javax.validation.constraints.NotNull;
import lombok.Data;
@Data
public class CounterRequest {
@NotNull
private final Integer int1;
@NotNull
private final Integer int2;
}
Utiliser lombok:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.0</version>
</dependency>
Retomber sur
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
Correction du problème. Je ne sais pas pourquoi, mais je voulais le documenter pour l'avenir.