I hope you were joking about writing your own parser. :-)
For such a simple mapping, most tools from http://json.org (section java) would work. For one of them (Jackson https://github.com/FasterXML/jackson-databind/#5-minute-tutorial-streaming-parser-generator), you'd do:
Map<String,Object> result =
new ObjectMapper().readValue(JSON_SOURCE, HashMap.class);
(where JSON_SOURCE is a File, input stream, reader, or json content String)
Answer from StaxMan on Stack Overflowjava - Convert a JSON String to a HashMap - Stack Overflow
java - creating Hashmap from a JSON String - Stack Overflow
java - How to convert a JSON string to a Map<String, String> with Jackson JSON - Stack Overflow
String with JSON inside to HashMap (instead to objects)
I hope you were joking about writing your own parser. :-)
For such a simple mapping, most tools from http://json.org (section java) would work. For one of them (Jackson https://github.com/FasterXML/jackson-databind/#5-minute-tutorial-streaming-parser-generator), you'd do:
Map<String,Object> result =
new ObjectMapper().readValue(JSON_SOURCE, HashMap.class);
(where JSON_SOURCE is a File, input stream, reader, or json content String)
Using the GSON library:
import com.google.gson.Gson;
import com.google.common.reflect.TypeToken;
import java.lang.reclect.Type;
Use the following code:
Type mapType = new TypeToken<Map<String, Map>>(){}.getType();
Map<String, String[]> son = new Gson().fromJson(easyString, mapType);
In recursive way:
public static Map<String, Object> jsonToMap(JSONObject json) throws JSONException {
Map<String, Object> retMap = new HashMap<String, Object>();
if(json != JSONObject.NULL) {
retMap = toMap(json);
}
return retMap;
}
public static Map<String, Object> toMap(JSONObject object) throws JSONException {
Map<String, Object> map = new HashMap<String, Object>();
Iterator<String> keysItr = object.keys();
while(keysItr.hasNext()) {
String key = keysItr.next();
Object value = object.get(key);
if(value instanceof JSONArray) {
value = toList((JSONArray) value);
}
else if(value instanceof JSONObject) {
value = toMap((JSONObject) value);
}
map.put(key, value);
}
return map;
}
public static List<Object> toList(JSONArray array) throws JSONException {
List<Object> list = new ArrayList<Object>();
for(int i = 0; i < array.length(); i++) {
Object value = array.get(i);
if(value instanceof JSONArray) {
value = toList((JSONArray) value);
}
else if(value instanceof JSONObject) {
value = toMap((JSONObject) value);
}
list.add(value);
}
return list;
}
Using Jackson library:
import com.fasterxml.jackson.databind.ObjectMapper;
Map<String, Object> mapping = new ObjectMapper().readValue(jsonStr, HashMap.class);
Using Gson, you can do the following:
Map<String, Object> retMap = new Gson().fromJson(
jsonString, new TypeToken<HashMap<String, Object>>() {}.getType()
);
Parse the JSONObject and create HashMap
public static void jsonToMap(String t) throws JSONException {
HashMap<String, String> map = new HashMap<String, String>();
JSONObject jObject = new JSONObject(t);
Iterator<?> keys = jObject.keys();
while( keys.hasNext() ){
String key = (String)keys.next();
String value = jObject.getString(key);
map.put(key, value);
}
System.out.println("json : "+jObject);
System.out.println("map : "+map);
}
Tested output:
json : {"phonetype":"N95","cat":"WP"}
map : {cat=WP, phonetype=N95}
You can use Google's Gson library to convert json to Hashmap. Try below code
String jsonString = "Your JSON string";
HashMap<String,String> map = new Gson().fromJson(jsonString, new TypeToken<HashMap<String, String>>(){}.getType());
[Update Sept 2020] Although my original answer here, from many years ago, seems to be helpful and is still getting upvotes, I now use the GSON library from Google, which I find to be more intuitive.
I've got the following code:
public void testJackson() throws IOException {
ObjectMapper mapper = new ObjectMapper();
File from = new File("albumnList.txt");
TypeReference<HashMap<String,Object>> typeRef
= new TypeReference<HashMap<String,Object>>() {};
HashMap<String,Object> o = mapper.readValue(from, typeRef);
System.out.println("Got " + o);
}
It's reading from a file, but mapper.readValue() will also accept an InputStream and you can obtain an InputStream from a string by using the following:
new ByteArrayInputStream(astring.getBytes("UTF-8"));
There's a bit more explanation about the mapper on my blog.
Try TypeFactory. Here's the code for Jackson JSON (2.8.4).
Map<String, String> result;
ObjectMapper mapper;
TypeFactory factory;
MapType type;
factory = TypeFactory.defaultInstance();
type = factory.constructMapType(HashMap.class, String.class, String.class);
mapper = new ObjectMapper();
result = mapper.readValue(data, type);
Here's the code for an older version of Jackson JSON.
Map<String, String> result = new ObjectMapper().readValue(
data, TypeFactory.mapType(HashMap.class, String.class, String.class));
I have a very complex JSON in String format so I don't want to create all necessary Java Classes because It would make my project very large, I just want to get one specific property from that JSON so my intention is to pass it to HashMap. This way I could get that property without creating any Java classes, is there any way to do that?
Thanks.
Json example (simplified):
[{ "line": 1, "elements": [{ "start_timestamp": "2020-03-13T12:14:35.340Z", "before": [{ "result": { "error_message": "org.openqa.selenium.NoSuchElementException: asdfasdf", "duration": 35995000000, "status": "failed" }, "match": { "location": "Cucumber.Tarragona.Integrados.Hooks.GeneralHooks.setup(io.cucumber.java.Scenario)" } }], "line": 4, "name": "Alta escala", "description": "", "id": "alta-escala;alta-escala", "after": [{ "embeddings": [{ "data": "iVBORw0KGgoAAA", "Something": "more..." }] }] }] }]
I tried:
ObjectMapper mapper = new ObjectMapper();Map<String, String> map = mapper.readValue(reportJson, new TypeReference<Map<String, String>>() {}); //https://mkyong.com/java/how-to-convert-java-map-to-from-json-jackson/ <-- reference
I get this error:
Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of \java.util.LinkedHashMap<java.lang.Object,java.lang.Object>\ out of START_ARRAY token at [Source: (StringReader); line: 1, column: 1] at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59) at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1445) at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1219) at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1129) at com.fasterxml.jackson.databind.deser.std.StdDeserializer._deserializeFromEmpty(StdDeserializer.java:639) at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:360) at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:29) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4218) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3214) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3197) at TestlinkAPI.TestlinkApiDemo.TestLinkConnector.executeKatalonSpecificTestCase(TestLinkConnector.java:605) at TestlinkAPI.TestlinkApiDemo.TestLinkConnector.main(TestLinkConnector.java:218)\``
This is method to read Map from json string using Jackson:
public final class JsonUtils {
public static <T> Map<String, T> readMap(String json) throws Exception {
if (json == null)
return null;
ObjectReader reader = new ObjectMapper().readerFor(Map.class);
MappingIterator<Map<String, T>> it = reader.readValues(json);
if (it.hasNextValue()) {
Map<String, T> res = it.next();
return res.isEmpty() ? Collections.emptyMap() : res;
}
return Collections.emptyMap();
}
}
This is how to read Map from json using given utilit method:
Map<String, String> map = flatMap(new LinkedHashMap<>(), "", JsonUtils.readMap(json));
And finally, this is how to transfrom Map into required Map (probably this could be done within Jackson engine, with provided custom deserializers or so, but I do not know exactly how, and thats why it is easier to me to implement it manually):
public static Map<String, String> flatMap(Map<String, String> res, String prefix, Map<String, Object> map) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = prefix + entry.getKey();
Object value = entry.getValue();
if (value instanceof Map)
flatMap(res, key + '.', (Map<String, Object>)value);
else
res.put(key, String.valueOf(value));
}
return res;
}
Jackson JSON is a pretty cool library which does this for you. I wrote a quick example below but you should be able to apply this to your JSONObject.
Let's say you have A.class with property B.class who in turn has a nested property C.class
@JsonPropertyOrder({ "b" })
class A {
@JsonProperty("b")
public B b;
@JsonProperty("b")
public B getB() {
return b;
}
@JsonProperty("b")
public void setB(B b) {
this.b = b;
}
}
@JsonPropertyOrder({ "c" })
class B {
@JsonProperty("c")
public C c;
@JsonProperty("c")
public C getC() {
return c;
}
@JsonProperty("c")
public void setC(C c) {
this.c = c;
}
}
@JsonPropertyOrder({ "d" })
class C {
@JsonProperty("d")
public String d;
@JsonProperty("d")
public String getD() {
return d;
}
@JsonProperty("d")
public void setD(String d) {
this.d = d;
}
}
You can convert a nested JSONObject {"b":{"c":{"d":"test"}}} into A.class like this:
C c = new C();
c.setD("test");
B b = new B();
b.setC(c);
JSONObject obj = new JSONObject();
obj.put("b", b);
String jsonAsString = new Gson().toJson(obj);
A a = mapper.readValue(jsonAsString, A.class);
Similarly you should be able to convert your JSONObject into any type you want. Hope this helps