使用Jackson处理自定义json中的“无法识别的令牌”异常

时间:2015-04-24 19:42:53

标签: java json data-binding jackson

我正在尝试使用Jackson json解析器(v2.5.2)来解析不是真正的json的自定义json文档,我无法弄清楚如何使其工作。我有一个json文档,可能看起来像:

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

我想使用ObjectMapper将其映射到java.util.Map,我希望将nonStandardThing()作为字符串值添加到我的地图中,用于键two。< / p>

当我通过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)

我尝试使用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)

任何人都可以指出Handler永远不会被调用的原因吗?或者,如果有一个更好的解析这个自定义json文档(杰克逊或不...),请告诉我。

2 个答案:

答案 0 :(得分:9)

未调用处理程序,因为无效部分不是属性("two"),而是值(nonStandardThing())。

处理此问题的一种显而易见的方法是将nonStandardThing()作为String传递,即将JSON文档重写为

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

如果不可能,那就没什么可做的了。使用自定义Jackson Deserializer仅对属性有用,而不是值。

答案 1 :(得分:2)

遗憾的是,您列出的内容不是有效的JSON,因此您所拥有的并不是JSON文档,而是Javascript对象的序列化。 所有字符串值必须用JSON中的双引号括起来。

杰克逊不支持直接阅读此类内容,但可以使用像SnakeYAML这样的YAML解析器来阅读。 杰克逊在https://github.com/FasterXML/jackson-dataformat-yaml/也有YAML数据格式模块,所以你也许可以使用它。鉴于YAML(主要是!)是JSON的超集,它可能会做你想要的。