web-dev-qa-db-fra.com

Gestion de l'exception "Jeton non reconnu" dans json personnalisé avec Jackson

J'essaie d'utiliser l'analyseur Jackson json (v2.5.2) pour analyser un document json personnalisé qui n'est pas du vrai json et je ne sais pas comment le faire fonctionner. J'ai un document json qui pourrait ressembler à:

{
    "test": {
        "one":"oneThing",
        "two": nonStandardThing(),
        "three": true
    }
}

Je veux utiliser l'ObjectMapper pour mapper ceci à un Java.util.Map Et je voudrais juste que la nonStandardThing() soit ajoutée comme valeur de chaîne dans ma carte pour la clé two.

Lorsque j'exécute cela via la ObjectMapper.readValue(json, Map.class) j'obtiens l'exception:

com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'nonStandardThing': was expecting 'null', 'true', 'false' or NaN
 at [Source: { "test":{"test1":nonStandardThing(),"test2":"two"}}; line: 1, column: 35]
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.Java:1487)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.Java:518)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.Java:2300)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.Java:2277)

J'ai essayé d'enregistrer un DeserializationProblemHandler avec le ObjectMapper mais il n'est jamais appelé lorsque ce problème se produit.

Voici un exemple d'application qui montre ce que j'ai essayé:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
import Java.io.IOException;
import Java.util.Map;
import Java.util.logging.Level;
import Java.util.logging.Logger;

public class JacksonDeserializerTest {
    private Logger log = Logger.getLogger(JacksonDeserializerTest.class.getName());
    public JacksonDeserializerTest() {
        String validJson = "{ \"test\":{\"test1\":\"one\",\"test2\":\"two\"}}";
        String invalidJson = "{ \"test\":{\"test1\":nonStandardThing(),\"test2\":\"two\"}}";

        ObjectMapper mapper = new ObjectMapper();
        mapper.addHandler(new DeserializationProblemHandler() {
            @Override
            public boolean handleUnknownProperty(DeserializationContext dc, JsonParser jp, JsonDeserializer<?> jd, Object bean, String property) throws IOException, JsonProcessingException {
                System.out.println("Handling unknown property: " + property);
                return false;
            }
        });

        try {
            log.log(Level.INFO, "Valid json looks like: {0}", mapper.readValue( validJson, Map.class).toString());
            log.log(Level.INFO, "Invalid json looks like: {0}", mapper.readValue(invalidJson, Map.class).toString());
        } catch (IOException ex) {
            log.log(Level.SEVERE, "Error parsing json", ex);
        }

    }

    public static void main(String[] args) {
        JacksonDeserializerTest test = new JacksonDeserializerTest();
    }
}

La sortie ressemble à:

Apr 24, 2015 1:40:27 PM net.acesinc.data.json.generator.jackson.JacksonDeserializerTest <init>
INFO: Valid json looks like: {test={test1=one, test2=two}}
Apr 24, 2015 1:40:27 PM net.acesinc.data.json.generator.jackson.JacksonDeserializerTest <init>
SEVERE: Error parsing json
com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'nonStandardThing': was expecting 'null', 'true', 'false' or NaN
 at [Source: { "test":{"test1":nonStandardThing(),"test2":"two"}}; line: 1, column: 35]
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.Java:1487)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.Java:518)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.Java:2300)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.Java:2277)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._matchToken(ReaderBasedJsonParser.Java:2129)

Quelqu'un peut-il indiquer pourquoi le gestionnaire n'est jamais appelé? Ou, s'il y a une meilleure analyse de ce document json personnalisé (jackson ou pas ...), faites le moi savoir.

12
Andrew Serff

Le gestionnaire n'est pas appelé car la partie non valide n'est pas la propriété ("two") Mais la valeur (nonStandardThing()).

Une façon évidente de gérer cela est de passer nonStandardThing() en String, c'est-à-dire réécrire le document JSON en tant que

{
    "test": {
        "one":"oneThing",
        "two": "nonStandardThing()",
        "three": true
    }
}

Si ce n'est pas une possibilité, il n'y a pas grand chose à faire. L'utilisation d'un JacksonDeserializer personnalisé n'est utile que pour les propriétés, pas pour les valeurs.

9
PNS

Le contenu que vous listez n'est malheureusement pas un JSON valide, donc ce que vous avez n'est pas vraiment un document JSON, mais peut-être la sérialisation d'un objet Javascript. Toutes les valeurs de chaîne DOIVENT être placées entre guillemets doubles dans JSON.

Jackson ne prend pas directement en charge la lecture d'un tel contenu, mais il peut être possible de le lire en utilisant l'analyseur YAML comme SnakeYAML. Jackson a également un module de format de données YAML à https://github.com/FasterXML/jackson-dataformat-yaml/ donc vous pouvez peut-être l'utiliser. Étant donné que YAML est (surtout!) Un sur-ensemble de JSON, il pourrait probablement faire ce que vous voulez.

2
StaxMan