La désérialisation de JSON avec Jackson - Pourquoi JsonMappingException “Aucun constructeur approprié”?
J'ai un problème désérialisation d'une chaîne JSON à l'aide de Jackson (mais je n'ai pas de problème de sérialisation d'un objet JSON).
Ci-dessous, je présente les classes que j'utilise. Le problème vient quand je rececive un JSON-chaîne (un ProtocolContainer a été sérialisé ailleurs et récupéré via webservice) et que vous souhaitez dé-sérialiser:
JSON-chaîne:
{"DataPacketJSONString":null,"DataPacketType":"MyPackage.DataPackets.LoginRequestReply","MessageId":6604,"SenderUsername":null,"SubPacket":{"__type":"LoginRequestReply:#MyPackage.DataPackets","Reason":"Mauvaise passe ou nom d'utilisateur","Succès":false,"Nom":"User1"}}
J'essaie de désérialiser comme ceci:
ProtocolContainer ret = ProtocolContainer.Create(jsonString);
et le code qui s'exécute dans ProtocolContainer peut être vu ci-dessous. L'exception:
org.codehaus.jackson.carte.JsonMappingException: Aucun constructeur approprié
trouvé pour le type [type simple, classe
MyPackage.ProtocolContainer]: ne peut pas
instancier d'objet JSON (besoin d'ajouter/activer le type d'information?)
à [Source: java.io.StringReader@4059dcb0; ligne: 1, colonnes: 2]
J'apprécierais vraiment certains commentaires ici =) Thx!
ProtocolContainer.java - un conteneur de classe qui encapsule mon "SubPackets":
import java.io.IOException;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import MyPackage.DataPackets.*;
public class ProtocolContainer
{
public String SenderUsername;
public String DataPacketType;
public long MessageId;
public String DataPacketJSONString;
public DataPacket SubPacket;
public ProtocolContainer(DataPacket dp)
{
DataPacketType = dp.getClass().toString().substring(6);
SubPacket = dp;
}
public String toJSON()
{
try {
if (SubPacket != null)
this.DataPacketJSONString = ProtocolContainer.mapper.writeValueAsString(SubPacket);
return ProtocolContainer.mapper.writeValueAsString(this);
} catch (JsonGenerationException e) {
//TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
//TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static ObjectMapper mapper = new ObjectMapper();
public static ProtocolContainer Create(String jsonString)
{
ProtocolContainer pc = null;
try {
pc = mapper.readValue(jsonString, ProtocolContainer.class); //error here!
} catch (JsonParseException e) {
//TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
//TODO Auto-generated catch block
e.printStackTrace(); //Exception when deserializing
} catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
try
{
if (pc != null && pc.DataPacketType == "LoginRequest")
pc.SubPacket = mapper.readValue(jsonString, LoginRequest.class);
}
catch (JsonParseException e)
{
e.printStackTrace();
}
catch (JsonMappingException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
return pc;
}
}
DataPacket.java - une super-classe de toutes mes datapackets
public class DataPacket
{
}
LoginRequestReply.java - un DataPacket
package MyPackage.DataPackets;
import MyPackage.DataPacket;
public class LoginRequestReply extends DataPacket
{
public boolean LoginOK;
public int UserId;
}
- Suivi: Après quelques bricoler, je ne reçois pas le message d'erreur suivant: JsonMappingException: ne Peut pas instancier une valeur de type [type simple, classe MyPackage.ProtocolContainer] de Chaîne JSON; pas une seule Chaîne de constructeur/méthode de fabrique. Si j'ajoute un constructeur qui prend une Chaîne de caractères, alors pas d'erreur, mais l'Objet est "vide"... je ne pense pas qu'il devrait être nécessaire d'ajouter de l'appui à l'exécution dans le constructeur. Comment dois-je résoudre ce problème?
Vous devez vous connecter pour publier un commentaire.
Les messages d'erreur tout est dit, votre ProtocolContainer ne possède pas de constructeur par défaut si Jackson est impossible de créer une instance. (Depuis le seul moyen de créer un ProtocolContainer en passant une DataPacket.)
Dans ce cas, vous pourriez ajouter
@JsonCreator
annotation de constructeur. Il y a deux façons cela pourrait être fait:@JsonProperty
annotation avant l'argument, puis JSON propriété correspondant à ce nom est transmis au constructeur (annotation est obligatoire parce que Java byte code ne contient PAS de nom de méthode ou d'un constructeur arguments) -- je soupçonne que vous voulez@JsonProperty("SubPacket")
Cela fonctionne si l'information nécessaire pour le constructeur vient de JSON. Si non, vous avez besoin d'ajouter d'autres non-arg constructeur.
Par la manière, le message d'erreur ne son mal dans ce cas. Il ne doit être administré que si les données JSON correspondant à la valeur attendue si une Chaîne JSON.
Pouce Règle: Ajouter un constructeur par défaut pour chaque catégorie que vous avez utilisé comme un mappage de classe. Vous avez manqué ce et question!
Il suffit d'ajouter un constructeur par défaut et cela devrait fonctionner.
super()
rien ne fonctionne.J'ai été confronté à la question et aucune réponse n'a fonctionné pour moi. il semble que l'exception levée est très générique et est levée pour n certain nombre de causes. Si un correctif peut ne pas fonctionner pour tout le monde.
Mon cas:
nous avons une réponse json dans lequel une carte de crédit est un type complexe, mais facultative. quand il n'y a pas de carte de banque de données, nous avons été faire une chaîne vide en réponse:
"carte de crédit":""
Mais la carte de Crédit est un type complexe pour nous:
Nous avons compris, si il n'y a pas de carte de banque de données, on devrait avoir quelque chose comme cela dans la réponse json:
"carte de crédit":{}
et pas de "carte de crédit":""
il résolu ce problème.
Une autre possibilité si vous utilisez Lombok! Je n'ai pas trouvé la raison.
Si lombok constructeur annotation est utilisée à l'extérieur de la classe, à l'intérieur de la classe, même si on écrit tous les arguments du constructeur manuellement, il se plaint encore le constructeur ne peut pas être trouvé. Si vous utilisez
@AllArgsConstructor
surMaintenance
au lieu d'écrire votre propre, jackson deserialise avec succès. J'ai eu la même expérience aujourd'hui, l'ajout de@AllArgsConstructor
elle n'en résout.