Jackson:POJO由JSON对象,字符串数组或字符串定义

时间:2018-04-27 03:32:00

标签: java json jackson

我期待能够使用Jackson将几种JSON格式解析为相同的以下对象:

public class SpeechAction extends Action {

    public String[] speechText;

}

知道我的父类是:

public class Action {

    public String onCompletedEvent;

}

我希望能够支持的格式(为了便于编写,因为它将由人而不是机器编写一段时间):

1。简单字符串

{
    "speech": <speech_text>
}

2。字符串数组

{
    "speech":[
        <variant1>, 
        <variant2>, 
        …
    ]
}

第3。嵌套的简单字符串

{
    "speech": {
        "speechText": <speech_text>,
        "onCompletedEvent":<EVENT_NAME>
    }
}

4。嵌套字符串数组

{
    "speech": {
        "speechText":[
            <variant1>, 
            <variant2>, 
            …
        ],
        "onCompletedEvent":<EVENT_NAME>
    }
}

使用以下代码成功解析格式1,3和4:

public class SpeechAction extends Action {

    @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
    @JsonProperty("speechText")
    public String[] speechText;

    public SpeechAction() {
        speechText = new String[]{""};
    }

    public SpeechAction(String... text) {
        speechText = text;
    }

    public SpeechAction(String text) {
        speechText = new String[]{text};
    }

}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes({@JsonSubTypes.Type(value = SpeechAction.class, name = "speech")})
public class Action {

    @JsonProperty("onCompletedEvent")
    public String onCompletedEvent;

}

但我还没有能够解决格式2.我在尝试解析时遇到以下异常:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `com.nerus.app.actions.SpeechAction` out of START_ARRAY token
at [Source: (String)"{
    "speech": [
        "Hello there!",
        "Hey you!"
    ]
}
"; line: 2, column: 11]

我能够通过使用@JsonCreator注释来支持格式1和格式2,但是3和4立即丢失了。

我探索了自定义反序列化方法,但另外不想失去注释的优势,我没有看到如何以一种不会为我父母的课程重复的方式做到这一点&#34; onCompletedEvent&# 34;属性(因为我有很多从Action继承的类)。

感谢您的领导!

1 个答案:

答案 0 :(得分:0)

Jackson API为您提供了一个名为JsonNode的通用对象,它可以解析任何类型的JSON流,除非您收到有效的JSON输入。因此,您始终可以考虑将JSON模式4视为通用JSON,因为它涵盖了所有方案。

我坚信存在设计缺陷。鉴于这种情况,我想以三种方式处理这个问题陈述。

  1. 在问题中提及所有带有公共架构的JSON,类型为4 JSON。
  2. 为4个JSON模式创建POJO并使用Jackson API的ObjectMapper映射它们。
  3. 使用JsonNode将输入JSON映射到ObjectMapper并找到所有必需字段。 (这是处理JSON的最天真的方式。)
  4. 因为,您已经在评论中提到了我想向您展示的方法。

    注意:我不想亲自采用这种方法。如果我是你,我将重新考虑我的设计并采用第一种或第二种方法。

    public class JsonTest {
    
        public static void main(String[] args) throws JsonProcessingException, IOException {
            String jsoninpt = "{\r\n" + 
                    "   \"speech\": \"speech text\"\r\n" + 
                    "}";
            String jsoninpt1 = "{\r\n" + 
                    "   \"speech\": [\r\n" + 
                    "       \"speech text1\",\r\n" + 
                    "       \"speech text2\"\r\n" + 
                    "   ]\r\n" + 
                    "}";
    
            String jsonInpt2 = "{\r\n" + 
                    "    \"speech\": {\r\n" + 
                    "        \"speechText\": <speech_text>,\r\n" + 
                    "        \"onCompletedEvent\":<EVENT_NAME>\r\n" + 
                    "    }\r\n" + 
                    "}";
            String jsonInput3 = "{\r\n" + 
                    "    \"speech\": {\r\n" + 
                    "        \"speechText\":[\r\n" + 
                    "            <variant1>, \r\n" + 
                    "            <variant2>, \r\n" + 
                    "            …\r\n" + 
                    "        ],\r\n" + 
                    "        \"onCompletedEvent\":<EVENT_NAME>\r\n" + 
                    "    }\r\n" + 
                    "}";
    
    
            jsonParser(jsoninpt);
    
        }
    
        public static void jsonParser(String jsoninput) throws IOException {
            ObjectMapper mapper = new ObjectMapper();
            JsonNode jsonInputNode = mapper.readTree(jsoninput);
    
            System.out.println(mapper.writeValueAsString(jsonInputNode));
    
            if(jsonInputNode.has("speech")) {
                JsonNode value = jsonInputNode.get("speech");
                if(value.isTextual()) {
                    String speechText = value.asText();
                    System.out.println(speechText);
                }else if(value.isArray() || value.isObject()) {
                    Iterator<Entry<String, JsonNode>> speechObjects = value.fields();
                    while(speechObjects.hasNext()) {
                        Entry<String,JsonNode> speechObject = speechObjects.next();
                        String key = speechObject.getKey();
                        JsonNode node = speechObject.getValue();                    
                    }
            }
    
        }
        }
    
    }