使用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这个答案可能不是你要找的,当然不是一个简单的解决方案。这个帮助类读取输入文件就像它是 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的主要内容,如果未能解决你的问题,请参考以下文章
在将 json 反序列化为对象时,使用 jackson 将 asp.net / MS 专有 json Dateformat 转换为 java8 LocalDateTime