Comment obtenir la chaîne sous-jacente d’un JsonParser (Jackson Json)

En parcourant la documentation et le code source, je ne vois pas comment le faire. Curieux si je manque quelque chose.

Supposons que je reçoive un InputStream à partir d’une réponse du serveur. Je crée un JsonParser à partir de ce InputStream. Il est prévu que la réponse du serveur est un texte contenant un JSON valide, tel que:

{"iamValidJson":"yay"}

Cependant, si la réponse finit par être un JSON invalide ou pas du tout JSON, tel que:

Some text that is not JSON

le JsonParser va éventuellement lancer une exception. Dans ce cas, j’aimerais pouvoir extraire du texte JsonParser le texte non valide sous-jacent “Du Some text that is not JSON ” afin qu’il puisse être utilisé à d’autres fins.

Je ne peux pas le retirer du InputStream car il ne prend pas en charge la réinitialisation et la création du JsonParser le consum.

Y a-t-il un moyen de faire cela?

Si vous avez le JsonParser vous pouvez utiliser jsonParser.readValueAsTree().toSsortingng() .

Toutefois, cela nécessite probablement que le JSON analysé soit effectivement un JSON valide.

J’étais dans une situation où j’utilisais un désérialiseur personnalisé, mais je voulais que le désérialiseur par défaut fasse l’essentiel du travail, puis utiliser SAME json pour effectuer un travail personnalisé supplémentaire. Cependant, une fois que le désérialiseur par défaut a fonctionné, l’emplacement actuel de l’object JsonParser était au-delà du texte json dont j’avais besoin. J’ai donc eu le même problème que vous: comment accéder à la chaîne JSON sous-jacente.

Vous pouvez utiliser JsonParser.getCurrentLocation.getSourceRef() pour accéder à la source JSON sous-jacente. Utilisez JsonParser.getCurrentLocation().getCharOffset() pour rechercher l’emplacement actuel dans la source JSON.

Voici la solution que j’ai utilisée:

 public class WalkStepDeserializer extends StdDeserializer implements ResolvableDeserializer { // constructor, logger, and ResolvableDeserializer methods not shown @Override public MyObj deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { MyObj myObj = null; JsonLocation startLocation = jp.getCurrentLocation(); long charOffsetStart = startLocation.getCharOffset(); try { myObj = (MyObj) defaultDeserializer.deserialize(jp, ctxt); } catch (UnrecognizedPropertyException e) { logger.info(e.getMessage()); } JsonLocation endLocation = jp.getCurrentLocation(); long charOffsetEnd = endLocation.getCharOffset(); Ssortingng jsonSubSsortingng = endLocation.getSourceRef().toSsortingng().subssortingng((int)charOffsetStart - 1, (int)charOffsetEnd); logger.info(strWalkStep); // Special logic - use JsonLocation.getSourceRef() to get and use the entire Json // ssortingng for further processing return myObj; } } 

Et des informations sur l’utilisation d’un désérialiseur par défaut dans un désérialiseur personnalisé sont à l’adresse Comment appeler le désérialiseur par défaut à partir d’un désérialiseur personnalisé à Jackson

Ce que vous essayez de faire est en dehors de la scope de Jackson (et de la plupart sinon de toutes les autres bibliothèques JSON Java disponibles). Ce que vous voulez faire est de complètement utiliser le stream d’entrée en chaîne, puis d’essayer de convertir cette chaîne en object JSON à l’aide de Jackson. Si la conversion échoue, faites quelque chose avec la chaîne intermédiaire, sinon continuez normalement. Voici un exemple d’utilisation de l’excellente bibliothèque Apache Commons IO :

 final InputStream stream ; // Your stream here final Ssortingng json = IOUtils.toSsortingng(stream); try { final JsonNode node = new ObjectMapper().readTree(json); // Do something with JSON object here } catch(final JsonProcessingException jpe) { // Do something with intermediate ssortingng here } 

5 ans de retard, mais c’était ma solution:

J’ai converti le jsonParser en chaîne

 Ssortingng requestSsortingng = jsonParser.readValueAsTree().toSsortingng(); 

Puis j’ai converti cette chaîne en JsonParser

 JsonFactory factory = new JsonFactory(); JsonParser parser = factory.createParser(requestSsortingng); 

Puis j’ai parcouru mon parsingur

 ObjectMapper objectMapper = new ObjectMapper(); while(!parser.isClosed()){ JsonToken jsonToken = parser.nextToken(); if(JsonToken.FIELD_NAME.equals(jsonToken)){ Ssortingng currentName = parser.getCurrentName(); parser.nextToken(); switch (currentName) { case "someObject": Object someObject = objectMapper.readValue(parser, Object.class) //validate someObject break; } } 

J’avais besoin de sauvegarder la chaîne json originale à des fins de journalisation, c’est pourquoi je l’ai fait en premier lieu. Était un mal de tête pour le savoir, mais finalement l’a fait et j’espère que j’aide quelqu’un 🙂

Construire mon propre Deserialiser dans lequel je voulais désérialiser un champ spécifique en tant que texte en tant que DTO, voici la solution que j’ai proposée.

J’ai écrit mon propre JsonToSsortingngDeserializer comme ceci:

 import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.TreeNode; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import lombok.NoArgsConstructor; import org.apache.commons.lang3.SsortingngEscapeUtils; import java.io.IOException; /** * Deserialiser to deserialise any Json content to a Ssortingng. */ @NoArgsConstructor public class JsonToSsortingngDeserializer extends JsonDeserializer { /** * Deserialise a Json atsortingbute that is a fully fledged Json object, into a {@link Ssortingng}. * @param jsonParser Parsed used for reading JSON content * @param context Context that can be used to access information about this deserialization activity. * @return The deserialized value as a {@link Ssortingng}. * @throws IOException */ @Override public Ssortingng deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException { final TreeNode node = jsonParser.getCodec().readTree(jsonParser); final Ssortingng unescapedSsortingng = SsortingngEscapeUtils.unescapeJava(node.toSsortingng()); return unescapedSsortingng.subssortingng(1, unescapedSsortingng.length()-1); } } 

Annotez le champ que vous souhaitez désérialiser comme ceci:

 @JsonDeserialize(using = JsonToSsortingngDeserializer.class) 

J’ai d’abord suivi le conseil qui disait d’utiliser un TreeNode comme ceci:

  final TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser); return treeNode.toSsortingng(); 

Mais alors vous obtenez une chaîne Json qui contient des caractères d’échappement.