使用jackson将json对象列表转换为hashmap

Posted

技术标签:

【中文标题】使用jackson将json对象列表转换为hashmap【英文标题】:Convert a List of json object to hashmap using jackson 【发布时间】:2016-06-17 18:00:41 【问题描述】:

有没有办法使用内置的 Jackson 功能使用 java 将 json 对象列表转换为 HashMap

说明: 我需要解析的Json结构


    list:[
        
            keyId : 1,
            keyLabel : "Test 1",
            valueId: 34,
            valueLabel: "Test Lable"
        ,
        
            keyId : 2,
            keyLabel : "Test 2",
            valueId: 35,
            valueLabel: "Test Lable"
        ,
        
            keyId : 3,
            keyLabel : "Test 3",
            valueId: 36,
            valueLabel: "Test Lable"
        
    ]

我期待的对象模型,

class Key
    int keyId;
    String keyLable;

    hashCode()
    return keyId.hashCode();
    


class Value
    int valueId;
    String valueLable;

    hashCode()
    return valueId.hashCode();
    

我需要把上面的json列表转换成这样的地图,

HashMap<Key,Value> map;

【问题讨论】:

请用双引号将所有属性名称都引用为有效的 JSON 对象。 【参考方案1】:

我建议手动进行。你只需要写几行。有点像

    ObjectMapper jmap = new ObjectMapper();
    //Ignore value properties
    List<Key> keys = jmap.readValue("[, ]", jmap.getTypeFactory().constructCollectionType(ArrayList.class, Key.class));
    //Ignore key properties
    List<Value> values = jmap.readValue("[, ]", jmap.getTypeFactory().constructCollectionType(ArrayList.class, Value.class));

    Map<Key, Value> data = new HashMap<>();
    for (int i = 0; i < keys.size(); i++) 
        data.put(keys.get(i), values.get(i));
    

注意:您的 json 和模型中存在拼写不匹配 (valueLabel != valueLable)。

【讨论】:

然后就可以使用自定义反序列化器了。 是的...我也想写一个,但是正如@neal 指定的那样,有没有办法避免使用中间对象....如果不使用中间类,我无论如何都找不到... 如果我做对了,你想避免使用 CustomObject。您的 json 代表一个对象,而不是列表。所以杰克逊需要精确的模型来映射json。但是,您可以从 json 对象中提取列表,然后使用用户自定义反序列化器。 JsonNode node = mapper.readTree(json).path("list")【参考方案2】:

先将list转化为map数组,再创建key和value的map。

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonMapExample 

    public static void main(String[] args) 

        try 

            ObjectMapper mapper = new ObjectMapper();
            String json = "\"list\":[\"keyId\":1,\"keyLabel\":\"Test 1\",\"valueId\":34,\"valueLabel\":\"Test Lable\",\"keyId\":2,\"keyLabel\":\"Test 2\",\"valueId\":35,\"valueLabel\":\"Test Lable\",\"keyId\":3,\"keyLabel\":\"Test 3\",\"valueId\":36,\"valueLabel\":\"Test Lable\"]";
            JsonNode node = mapper.readTree(json).path("list");
            JsonParser parser = mapper.treeAsTokens(node);
            Map<String, Object>[] clients = parser.readValueAs(new TypeReference<Map<String, Object>[]>() 
            );
            Map<Key, Value> result = new HashMap<Key, Value>();
            for (Map<String, Object> map : clients) 
                int keyId = Integer.parseInt(map.get("keyId").toString());
                int valueId = Integer.parseInt(map.get("valueId").toString());
                result.put(new Key(keyId, map.get("keyLabel").toString()),
                        new Value(valueId, map.get("valueLabel").toString()));
            
            System.out.println(result);
         catch (JsonGenerationException e) 
            e.printStackTrace();
         catch (JsonMappingException e) 
            e.printStackTrace();
         catch (IOException e) 
            e.printStackTrace();
        
    

【讨论】:

【参考方案3】:

我认为您必须编写自定义反序列化程序。这是一个选项:

    public class CustomObject
    private List<KeyValuePairs> list;

    public List<KeyValuePairs> getList() 
        return list;
    
    public void setList(List<KeyValuePairs> list) 
        this.list = list;
    

    //Helper
    public HashMap<CustomKey,CustomValue> getCustomKeyValueMap()
        Map<CustomKey,CustomValue> map = new HashMap<CustomKey,CustomValue>();
        for(KeyValuePairs kvpair: list)
            map.put(new CustomKey(kvpair.getKeyId(),kvpair.getKeyLabel()), 
                    new CustomValue(kvpair.getValueId(),kvpair.getValueLabel()));
        
        return map;
    


    public class KeyValuePairs
        private int keyId;
        private String keyLabel;
        private int valueId;
        private String valueLabel;

        //Getters and Setters
        public int getKeyId() 
            return keyId;
        
        public void setKeyId(int keyId) 
            this.keyId = keyId;
        
        public String getKeyLabel() 
            return keyLabel;
        
        public void setKeyLabel(String keyLabel) 
            this.keyLabel = keyLabel;
        
        public int getValueId() 
            return valueId;
        
        public void setValueId(int valueId) 
            this.valueId = valueId;
        
        public String getValueLabel() 
            return valueLabel;
        
        public void setValueLabel(String valueLabel) 
            this.valueLabel = valueLabel;
        

    
        public class CustomKey
            int keyId;
            String keyLable;

            public CustomKey()

            

            public CustomKey(int keyId, String keyLable)
                this.keyId = keyId;
                this.keyLable = keyLable;
            

            public int getKeyId() 
                return keyId;
            
            public void setKeyId(int keyId) 
                this.keyId = keyId;
            
            public String getKeyLable() 
                return keyLable;
            
            public void setKeyLable(String keyLable) 
                this.keyLable = keyLable;
            

               



        public class CustomValue
            int valueId;
            String valueLable;

            public CustomValue()

            
            public CustomValue(int valueId, String valueLable)
                this.valueId = valueId;
                this.valueLable = valueLable;
            

            public int getValueId() 
                return valueId;
            
            public void setValueId(int valueId) 
                this.valueId = valueId;
            
            public String getValueLable() 
                return valueLable;
            
            public void setValueLable(String valueLable) 
                this.valueLable = valueLable;
            

        

【讨论】:

我们可以避免使用 KeyValuePairs 吗?? 我认为您无法避免使用它。我相信杰克逊需要这门课来弄清楚如何通过反射来映射字段。为了得到结果,你要做的就是:CustomObject o = objectMapper.readValue(carJson, CustomObject.class); Map map = o.getCustomKeyValueMap();【参考方案4】:

这个答案可能不是你要找的,当然不是一个简单的解决方案。这个帮助类读取输入文件就像它是 SAX-XML 解析器,不像 DOM-XML 解析器。

我的用例是一个大型的“随机”结构化 json 文件和更新数据库对象。这永远不会将整个文档加载到 RAM 内存中。我不能使用强类型对象,所以选择了 hashmap 解决方案。

这个循环输入文件,收集每个给定断点对象路径的字段值,调用处理函数。 Hashmap 具有 parent.entry.field=xxxxx 值,转储 keyval 对以查看命名语法。

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Stack;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

public class JSONHandler 
    private Stack<String> parents;
    private String cachedParent;
    private Map<String,String> entry;
    private Map<String,String> parentEntry;

    public JSONHandler(JSONHandler.EntryHandler handler, JsonParser jsonP, 
                        String path) throws Exception 
        parents = new Stack<String>();
        entry = new LinkedHashMap<String,String>(16);// new HashMap<String,String>(16);
        parentEntry = new LinkedHashMap<String,String>(8);

        if (!path.endsWith(".")) path+=".";

        boolean isParent=true;
        int arrayIdx=-1;
        cachedParent="";
        JsonToken token;
        boolean doProcess=true;
        while ( (token=jsonP.nextToken()) != null) 
            String name = jsonP.getCurrentName();
            if (token == JsonToken.START_OBJECT) 
                parents.push(name);
                if (cachedParent.equals(path)) 
                    entry.clear(); // start new target entry
                    arrayIdx=0;
                    if (!parentEntry.isEmpty()) entry.putAll(parentEntry);
                    isParent=false;
                 else if (!cachedParent.startsWith(path)) 
                    isParent=true; // add fields to parent entry
                
                cachedParent = implodeStack(parents);
             else if (token == JsonToken.END_OBJECT) 
                parents.pop();
                cachedParent = implodeStack(parents);
                if (cachedParent.equals(path)) 
                    doProcess=handler.process(entry);
                    arrayIdx=-1;
                    if (!doProcess) break;
                 else if (name==null && cachedParent.startsWith(path)) 
                    String sArrayIdx = parents.peek(); // increment arrayIndex+1
                    parents.set(parents.size()-1, ""+(Integer.parseInt(sArrayIdx)+1) );
                    cachedParent = implodeStack(parents);
                 else if (!cachedParent.startsWith(path)) 
                    Iterator<Map.Entry<String,String>> iter=parentEntry.entrySet().iterator();
                    while(iter.hasNext()) 
                        Map.Entry<String,String> me = iter.next();
                        if (me.getKey().startsWith(cachedParent))
                            iter.remove();
                    
                
             else if (token == JsonToken.START_ARRAY) 
                parents.push(name);
                if (arrayIdx>-1) parents.push(String.valueOf(arrayIdx));
                cachedParent = implodeStack(parents);
             else if (token == JsonToken.END_ARRAY) 
                parents.pop();
                if (arrayIdx>-1) 
                    parents.pop();
                    arrayIdx=0;
                
                cachedParent = implodeStack(parents);
             else if (token == JsonToken.FIELD_NAME) 
                //System.out.println("field="+jsonP.getCurrentName());
             else 
                String value;
                if (token == JsonToken.VALUE_NULL) value = null;
                else if (token == JsonToken.VALUE_TRUE) value = "1";
                else if (token == JsonToken.VALUE_FALSE) value = "0";
                else value = jsonP.getText();
                if (cachedParent.startsWith(path)) 
                    if (name==null && arrayIdx>-1) 
                        // simple array "values":["aa","bb","cc"], 
                        // write parent.item.values.0=aa, .1=bb, .2=cc
                        parents.set(parents.size()-1, ""+(arrayIdx++) );
                        cachedParent = implodeStack(parents);
                        entry.put(cachedParent.substring(0,cachedParent.length()-1), value);
                     else
                        entry.put(cachedParent+name, value);
                 else if (isParent) 
                    parentEntry.put(cachedParent+name, value);
                
            
        
    

    private String implodeStack(Stack<String> stack) 
        StringBuilder sb = new StringBuilder();
        for(String value : stack) 
            if (value!=null)
                sb.append(value + ".");
        
        return sb.toString();
    


    public static interface EntryHandler 
        public void startDocument() throws Exception;
        public boolean process(Map<String,String> entry) throws Exception;
    


示例客户端

    JSONHandler.EntryHandler handler = new JSONHandler.EntryHandler() 
        public void startDocument() throws Exception ;
        public boolean process(Map<String,String> entry) throws Exception 
            for(String key : entry.keySet())
                System.out.println(key+"="+entry.get(key));
            return true;
        
    ;

    JsonFactory jsonF = new JsonFactory();
    jsonF.enable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
    JsonParser jsonP = jsonF.createParser(file);
    try 
       handler.startDocument();
       new JSONHandler(handler, jsonP, "list");
     finally 
       jsonP.close();
    

(从我的应用程序中简化复制粘贴可能会引入语法错误)

【讨论】:

以上是关于使用jackson将json对象列表转换为hashmap的主要内容,如果未能解决你的问题,请参考以下文章

JackSon将java对象转换为JSON字符串

使用 Jackson 将 Java 对象转换为 JSON

Java - 使用jackson将json转换为复杂对象

Jackson 对象和JSON的相互转换

在将 json 反序列化为对象时,使用 jackson 将 asp.net / MS 专有 json Dateformat 转换为 java8 LocalDateTime

如何使用骆驼杰克逊将 JSONArray 转换为对象列表