Problèmes lors de la désérialisation d'exception/throwable à l'aide de Jackson en Java
Je suis confronté à des problèmes lors de la désérialisation d' Exception
et Throwable
instances à l'aide de Jackson (version 2.2.1). Considérons l'extrait suivant:
public static void main(String[] args) throws IOException
{
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
objectMapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);
try {
Integer.parseInt("String");
}
catch (NumberFormatException e) {
RuntimeException runtimeException = new RuntimeException(e);
String serializedException = objectMapper.writeValueAsString(runtimeException);
System.out.println(serializedException);
Throwable throwable = objectMapper.readValue(serializedException, Throwable.class);
throwable.printStackTrace();
}
}
La sortie de System.out.println
dans le catch
bloc est la suivante:
{
"@class" : "java.lang.RuntimeException",
"detailMessage" : "java.lang.NumberFormatException: For input string: \"String\"",
"cause" : {
"@class" : "java.lang.NumberFormatException",
"detailMessage" : "For input string: \"String\"",
"cause" : null,
"stackTrace" : [ {
"declaringClass" : "java.lang.NumberFormatException",
"methodName" : "forInputString",
"fileName" : "NumberFormatException.java",
"lineNumber" : 65
}, {
"declaringClass" : "java.lang.Integer",
"methodName" : "parseInt",
"fileName" : "Integer.java",
"lineNumber" : 492
}, {
"declaringClass" : "java.lang.Integer",
"methodName" : "parseInt",
"fileName" : "Integer.java",
"lineNumber" : 527
}, {
"declaringClass" : "test.jackson.JacksonTest",
"methodName" : "main",
"fileName" : "JacksonTest.java",
"lineNumber" : 26
} ],
"suppressedExceptions" : [ "java.util.ArrayList", [ ] ]
},
"stackTrace" : [ {
"declaringClass" : "test.jackson.JacksonTest",
"methodName" : "main",
"fileName" : "JacksonTest.java",
"lineNumber" : 29
} ],
"suppressedExceptions" : [ "java.util.ArrayList", [ ] ]
}
qui semble très bien. Mais lorsque je tente de désérialiser cette aide objectMapper.readValue()
, j'obtiens l'exception suivante:
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "declaringClass" (class java.lang.StackTraceElement), not marked as ignorable
at [Source: java.io.StringReader@3c5ebd39; line: 9, column: 27] (through reference chain: java.lang.StackTraceElement["declaringClass"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:79)
at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:555)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:708)
at com.fasterxml.jackson.databind.deser.std.JdkDeserializers$StackTraceElementDeserializer.deserialize(JdkDeserializers.java:414)
at com.fasterxml.jackson.databind.deser.std.JdkDeserializers$StackTraceElementDeserializer.deserialize(JdkDeserializers.java:380)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:151)
...
J'ai ensuite essayé d'utiliser mélangez-les dans les annotations, d'ignorer declaringClass
dans java.lang.StackTraceElement
, mais maintenant, le désérialisé Exception
ne contient pas de déclarer la classe dans son stack trace:
java.lang.RuntimeException: java.lang.NumberFormatException: For input string: "String"
at .main(JacksonTest.java:33)
Caused by: java.lang.NumberFormatException: For input string: "String"
at .forInputString(NumberFormatException.java:65)
at .parseInt(Integer.java:492)
at .parseInt(Integer.java:527)
at .main(JacksonTest.java:30)
Ai-je raté quelque chose? Toute aide est grandement appréciée.
OriginalL'auteur Jackall | 2013-07-25
Vous devez vous connecter pour publier un commentaire.
Il semble y avoir un Jackson JIRA entrée pour cette ici. Jackson ne semble pas être en mesure de gérer la
declaringClass
dansjava.lang.StackTraceElement
, depuis la lecture correspondant à ce champ est appelégetClassName()
.J'ai résolu ce problème en utilisant une mesure wrapper autour de
StackTraceElement
comme suggéré dans le TABLEAU de l'entrée mentionnés ci-dessus. Le wrapper personnalisé (CustomStackTraceElement
) le champsdeclaringClass
,methodName
,fileName
, etlineNumber
et les getters et setters. J'ai modifié lecatch
bloc (mentionnés dans la question) comme suit:La
StackTraceElement[]
sera converti enList<CustomStackTraceElement>
par la méthode suivante lors de la sérialisation:... et l'inverse de la transformation sera fait lors de la désérialisation:
Maintenant, après la désérialisation, le
Throwable
objet a prévu trace de la pile.C'est une bonne trouvaille. Merci pour la solution. Une autre solution est d'ajouter un mixin pour StackTraceElement. "' public abstract class StackTraceElementMixin { @JsonProperty("className") private String declaringClass; } ""
OriginalL'auteur Jackall
Ajouter ceci:
Et de faire sortir de la désérialisé exception de la même manière que pour la première fois:
J'ai utilisé le code suivant:
Ajouté ce bocaux: jackson-annotations-2.2.0.jar, jackson-core-2.2.0.jar et jackson-databind-2.2.0.jar.
Après l'exécution, le suivant est imprimé:
DeserializationFeature
, mais j'obtiens le même résultat que celui avec mix dans les annotations (c'est à dire, il n'y a pas de classe de déclaration dans le désérialisé de sortie). J'ai besoin de la compléterException
/Throwable
informations après c'est désérialisé -- il semble bizarre et incomplète autrement.Je peux
t understand, why are you trying to obtain the same result with throwable.printStackTrace() and objectMapper.writeValueAsString(runtimeException). Execute 'e.printStackTrace()' and you
ll obtenir le même "bizarre et incomplète". S'il vous plaît, de modifier la dernière ligne de votre code pour Système..println( objectMapper.writeValueAsString( throwable) ); " et vérifiez la sortie.La principale question que je me pose est avec la désérialisation. Si je dis
objectMapper.writeValueAsString(runtimeException)
, je ne suis pas de la désérialisation duThrowable
à tous, c'est juste le sérialisé de sortie. Imaginez un scénario où j'ai besoin de sérialiser lesThrowable
sur le côté serveur, de transmettre le sérialisé de sortie (sous la forme d'unString
) sur le fil, puis le désérialiser sur le côté client (à l'aide deobjectMapper.readValue
méthode). Le client doit être en mesure de voir l'ensemble desThrowable
informations après c'est désérialisé.Vous n'obtenez pas de moi. Je
m asking you to add 'objectMapper.writeValueAsString( throwable )', not 'objectMapper.writeValueAsString( runtimeException )'. Do you see the difference? You
re appelant à lancer.printStackTrace(), qui ne vous donnera pas de résultat souhaité. Le processus de désérialisation fonctionne très bien. Votre tentative pour obtenir le résultat dans un mauvais sens. Donc, SUPPRIMER " à lancer.printStackTrace()' à partir de votre code et d'ajouter " objectMapper.writeValueAsString( throwable )' (PAS runtimeException).Cela permettra d'imprimer toutes les infos pour votre objet DÉSÉRIALISÉ.J'ai essayé d'utiliser
objectMapper.writeValueAsString(throwable)
(après c'est désérialisé), mais la sortie n'est pas contenant la classe de déclaration; elle est vide (ce qui est similaire à l'impression la trace de la pile). Pour être clair, je veux leThrowable
l'objet à imprimer de la même trace de la pile avant de la sérialisation et après la désérialisation. Je dis que la désérialisation du processus n'est pas bien fonctionner, puisque la trace de la pile n'est pas conservé dans son intégralité.OriginalL'auteur Michael Cheremuhin
Il semble que la sortie de la version 2.2.1 n'est pas la même que je reçois avec la version 2.2.0 (qui, selon le site web est le dernier 2.x version). En plus de la plus récente disponible 2.x version sur le Repository Maven est 2.2.2. Je voudrais donc essayer soit de rétrograder à 2.2.0 ou à le mettre à niveau 2.2.2. Si l'un des changements que vous apporte le résultat attendu, je voudrais aller plus loin avec cette version et ouvrir un BUG dans Jackson JIRA.
Et bien sûr n'oubliez pas
de Michael réponse.
SerializationConfig.Feature
correspond à l'ancienne structure de paquet (avant la version 2.0). J'ai essayé de commenter les deux lignes comme vous l'avez suggéré (lors de la sérialisation, la désérialisation, et les autres combinaisons possibles), mais pas de chance. Le désérialiséThrowable
ne contient pas de déclarer la classe. Et, j'utilise Java 7 (ce qui ne devrait pas beaucoup, tout de même).OK, j'ai testé aussi avec la version 2.2.0 et configuré comme Michael Cheremuhin dit et je reçois aussi les noms de classes dans la trace de la pile (si vous manquez). Puis-je vous demander où avez-vous la version 2.2.1, comme sur la wiki.fasterxml.com/JacksonDownload site il est écrit que la dernière version 2.2.0 ?
J'ai eu la version 2.2.1 de Jackson dans le Central Repository Maven (search.maven.org).
OriginalL'auteur Andrei I
J'ai eu un problème similaire. Je suis en utilisant ce code maintenant, et ça me permet de sérialiser et désérialiser des exceptions avec les bons types (c'est à dire un
RuntimeException
sera unRuntimeException
encore une fois :)):Je suis de la manipulation de la
BeanDeserializerFactory
de fairebuildThrowableDeserializer
pas traiterThrowable
tout spécial, mais comme toute autreObject
. Ensuite, à l'aide deMixins
pour définir le "spécial" de la manipulation deThrowable
etStackTraceElement
à mon goût.OriginalL'auteur Markus Duft
Est-il nécessaire d'utiliser la sérialisation json? Regarde liks il y a quelques bugs avec throwables. Pourquoi ne pas utiliser le système api:
OriginalL'auteur Michael Cheremuhin
Essayez d'utiliser le polymorphisme de sorte que jackson deserializer sait quel genre de Throwable à créer:
OriginalL'auteur Chas