Обработка исключения "нераспознанный токен" в пользовательском json с Jackson

Я пытаюсь использовать парсер Jackson json (v2.5.2) для анализа пользовательского документа json, который не является истинным json, и я не могу понять, как заставить его работать. У меня есть документ json, который может выглядеть так:

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

Я хочу использовать ObjectMapper для сопоставления этого с java.util.Map и я просто хотел бы nonStandardThing() для добавления в качестве строкового значения в мою карту для ключа two.

когда я запускаю это через ObjectMapper.readValue(json, Map.class) Я получаю исключение:

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)

I попробовали зарегистрировать DeserializationProblemHandler С ObjectMapper но она никогда не вызывается, когда эта проблема возникает.

вот пример приложения, которое показывает, что я пробовал:

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();
    }
}

вывод выглядит так:

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)

может ли кто-нибудь указать, почему обработчик никогда не вызывается? Или, если есть лучший разбор этого пользовательского документа json (Джексон или нет...), дайте мне знать.

2 ответов


обработчик не вызывается, потому что недопустимая часть не является свойством ("two"), но значение (nonStandardThing()).

очевидный способ справиться с этим, - передать nonStandardThing() как String, т. е. перепишите документ JSON как

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

если это невозможно, то делать особо нечего. С помощью настраиваемого Jackson Deserializer имеет смысл только для свойств, а не значения.


содержимое, которое вы перечисляете, к сожалению, недействительно JSON, поэтому то, что у вас есть, на самом деле не является документом JSON, но, возможно, сериализация объекта Javascript. Все строковые значения должны быть заключены в двойные кавычки в JSON.

Джексон не поддерживает чтение такого контента напрямую, но его можно прочитать с помощью парсера YAML, такого как SnakeYAML. Джексон также имеет модуль формата данных YAML в https://github.com/FasterXML/jackson-dataformat-yaml/ Так вы смогли возможно, использовать. Учитывая, что ЯМЛ (в основном!) суперсет JSON, он, вероятно, может делать то, что вы хотите.