java - example - Deserialización de JSON con Jackson: ¿Por qué JsonMappingException “No hay un constructor adecuado”?
objectmapper java (5)
En este caso, podría agregar la anotación @JsonCreator
al constructor. Hay dos formas de hacerlo:
- Si solo agrega esa anotación, entonces todo el JSON correspondiente se vincula primero al tipo del único argumento (`Paquete de datos ''). Supongo que no quieres hacer eso.
- Si también agrega la anotación
@JsonProperty
antes del argumento, entonces la propiedad JSON que coincide con ese nombre se pasa al constructor (la anotación es obligatoria porque el código de byte Java NO contiene el nombre del método o los argumentos del constructor) - Sospecho que desea que@JsonProperty("SubPacket")
Esto funciona si la información necesaria para el constructor proviene de JSON. Si no es así, es necesario agregar un constructor alternativo sin argumentos.
Por cierto, el mensaje de error suena mal en este caso. Solo debe darse si los datos JSON coinciden con el valor esperado si se trata de una cadena JSON.
Tengo un problema al deserializar una cadena JSON utilizando Jackson (pero no tengo ningún problema al serializar un objeto a JSON).
A continuación presento las clases que uso. El problema surge cuando rececivo una cadena JSON (un ProtocolContainer que se serializó en otro lugar y se recuperó a través del servicio web) y quiero dessializarlo:
JSON-string:
{"DataPacketJSONString": null, "DataPacketType": "MyPackage.DataPackets.LoginRequestReply", "MessageId": 6604, "SenderUsername": npcp.pack_packpack.png_pack_pack_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_p_png Motivo ":" Pase o nombre de usuario incorrecto "," Éxito ": falso," Nombre de usuario ":" Usuario1 "}}
Intento deserializar así:
ProtocolContainer ret = ProtocolContainer.Create(jsonString);
y el código que se ejecuta en ProtocolContainer se puede ver a continuación. La excepción:
org.codehaus.jackson.map.JsonMappingException: No se encontró un constructor adecuado para el tipo [tipo simple, clase MyPackage.ProtocolContainer]: no se puede crear una instancia del objeto JSON (¿es necesario agregar / habilitar información de tipo?) en [Fuente: java.io. StringReader @ 4059dcb0; línea: 1, columna: 2]
Realmente apreciaría alguna entrada aquí =) Thx!
ProtocolContainer.java: una clase contenedora que encapsula mis "subpaquetes":
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 - una superclase para todos mis paquetes de datos
public class DataPacket
{
}
LoginRequestReply.java - un paquete de datos
package MyPackage.DataPackets;
import MyPackage.DataPacket;
public class LoginRequestReply extends DataPacket
{
public boolean LoginOK;
public int UserId;
}
Estaba enfrentando el problema y ninguna de las respuestas funcionó para mí. Parece que la excepción lanzada es muy genérica y se lanza para un número n de causas. Así que una solución puede no funcionar para todos. Mi caso: tenemos una respuesta json en la que la tarjeta de crédito es un tipo complejo pero opcional. cuando no hay datos de tarjetas de crédito, obtuvimos una cadena vacía en respuesta:
"tarjeta de crédito":""
Pero la tarjeta de crédito es un tipo complejo para nosotros:
<xs:element name="CC" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="aaa" type="xs:string" minOccurs="0"/>
<xs:element name="bbb" type="xs:string" minOccurs="0"/>
<xs:element name="ccc" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Nos dimos cuenta de que, si no hay datos de tarjetas de crédito, deberíamos tener algo como esto en la respuesta de json:
"tarjeta de crédito":{}
y no "tarjeta de crédito": ""
Se solucionó este problema.
Los mensajes de error lo dicen todo, su ProtocolContainer no tiene un constructor predeterminado, por lo que Jackson no puede crear una instancia de él. (Dado que la única forma actual de crear un ProtocolContainer es pasar un paquete de datos).
Otra posibilidad si usas Lombok ! No he descubierto la razón.
@Getter
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public Car implements Serializable {
Map<String, Object> basicInfo;
CarEnums.TypeEnum type;
List<Maintenance> maintenances;
public void addMaintenance(Maintenance m) {
// initialize if null
maintenances.add(m);
}
// must be static or jackson throws "inner class cannot be static" exception. Yes you see it right.
public static class Maintenance {
private Long id;
public class Maintenance(Long id) { // constructor causes the exception
this.id = id;
}
}
...
}
Si la anotación del constructor lombok se usa en la clase externa, la clase interna, incluso si uno escribe manualmente todos los constructores de argumentos, todavía se queja de que no se puede encontrar el constructor. Si usa @AllArgsConstructor
en el Maintenance
lugar de escribir el suyo, Jackson lo deserializará con éxito. Tuve la misma experiencia hoy, agregando que @AllArgsConstructor
resuelve.
Regla del pulgar : agregue un constructor predeterminado para cada clase que usó como clase de mapeo. Te perdiste esto y surgió el problema!
Simplemente agregue un constructor predeterminado y debería funcionar.