【问题标题】:How to parse JSON object by Jackson if type of one field is unknown如果一个字段的类型未知,如何通过 Jackson 解析 JSON 对象
【发布时间】:2014-09-05 16:01:49
【问题描述】:

我有一个 JSON 响应,我尝试用 Jackson 解析,但其中一个字段的类型未知。

例子:

{"name" : "Catalina"}

{"name" : {"First" : "Catalina", "Last" : "Kyle"}}

如何将该对象反序列化为 POJO:

class NamesHolder {
    public String singleName;
    public Map<String, String> nameMap;
}

这是合成示例,但我希望它能够清楚地理解。

在第一种情况下,我希望对象具有 singleName == "Catalina" 和 nameMap == null,在其他情况下反之亦然。

更新

真的很抱歉,最后我拼错了属性名称。在这两种情况下,它们都是相同的:名称。

【问题讨论】:

  • 可以,只要json属性名不同(比如“name”和“names”)就不难了。您尝试过的方法不起作用?
  • 第二种情况,是一直只有FirstLast还是可以包含更多字段?
  • 为什么还要麻烦 POJO?只需反序列化为 Maps。
  • 如果你做了类似的事情,请删除问题

标签: java json jackson


【解决方案1】:

尝试将您的姓名字段设为对象:

class MyPojo {
  public Object name;
}

您必须在运行时检查它是反序列化为字符串还是映射。

【讨论】:

    【解决方案2】:

    最简单的方法是将您的POJO 属性重命名为您在JSON 中的相同名称。见下例:

    class NamesHolder {
        public String name;
        public Map<String, String> names;
    
        @Override
        public String toString() {
            return "NamesHolder{" +
                    "name='" + name + '\'' +
                    ", names=" + names +
                    '}';
        }
    }
    

    如果您不想重命名属性,可以使用@JsonProperty 注释。见下例:

    class NamesHolder {
    
        @JsonProperty("name")
        public String singleName;
    
        @JsonProperty("names")
        public Map<String, String> nameMap;
    
        @Override
        public String toString() {
            return "NamesHolder{" +
                    "name='" + singleName + '\'' +
                    ", names=" + nameMap +
                    '}';
        }
    }
    

    以上两个类适用于您的 JSON 示例。见以下程序:

    ObjectMapper mapper = new ObjectMapper();
    System.out.println(mapper.readValue("{\"names\" : {\"First\" : \"Catalina\", \"Last\" : \"Kyle\"}}", NamesHolder.class));
    System.out.println(mapper.readValue("{\"name\" : \"Catalina\"}", NamesHolder.class));
    

    哪个打印:

    NamesHolder{name='null', names={First=Catalina, Last=Kyle}}
    NamesHolder{name='Catalina', names=null}
    

    编辑 1


    在这种情况下,您必须使用Object 类型手动处理它。见下例:

    public class JacksonTest {
    
        public static void main(String[] args) throws Exception {
            String json = "{\"name\" : \"Catalina\"}";
            ObjectMapper deserializerMapper = new ObjectMapper();
            NamesHolder namesHolder = deserializerMapper.readValue(json, NamesHolder.class);
            System.out.println(toString(namesHolder));
    
            json = "{\"name\" : {\"First\" : \"Catalina\", \"Last\" : \"Kyle\"}}";
            namesHolder = deserializerMapper.readValue(json, NamesHolder.class);
            System.out.println(toString(namesHolder));
        }
    
        private static String toString(NamesHolder namesHolder) {
            if (namesHolder.hasStringName()) {
                return "Type: String, Value: " + namesHolder.getStringName();
            } else if (namesHolder.hasMapNames()) {
                return "Type: Map, Value: " + namesHolder.getMapNames();
            }
            return "Type: Unknown, Value: " + namesHolder;
        }
    }
    
    class NamesHolder {
    
        public Object name;
    
        public boolean hasStringName() {
            return name instanceof String;
        }
    
        public String getStringName() {
            return name.toString();
        }
    
        public boolean hasMapNames() {
            return name instanceof Map;
        }
    
        public Map<String, String> getMapNames() {
            return (Map<String, String>) name;
        }
    
        @Override
        public String toString() {
            return String.valueOf(name);
        }
    }
    

    以上示例打印:

    Type: String, Value: Catalina
    Type: Map, Value: {First=Catalina, Last=Kyle}
    

    【讨论】:

    • 对不起,@Michał。两种情况下属性字段的名称相同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-28
    • 2021-04-03
    • 1970-01-01
    相关资源
    最近更新 更多