I have a java code where i am find the difference between two json strings. As shown below:-
String afterString = converterUtil.convertObjectToJson(targetObject);
Gson g = new Gson();
Type mapType = new TypeToken<Map<String, Object>>() {
}.getType();
Map<String, Object> firstMap = g.fromJson(beforeString, mapType);
Map<String, Object> secondMap = g.fromJson(afterString, mapType);
System.out.println(Maps.difference(firstMap, secondMap));
How can i save the difference result as map which is returned by Maps.difference?
From Guava's Maps documentation, Maps#difference returns a MapDifference. To convert this to a Map, you can use MapDifference#entriesDiffering. There also exist other methods which may be useful to you such as MapDifference#entriesInCommon, MapDifference#entriesOnlyOnLeft, and MapDifference#entriesOnlyOnRight.
Related
I have a JSON like this: [{key:key1, value:value1}, {key:key2, value:value2}, ..., {key:keyn, value:valuen}]
and I need a HashMap in Java from that json like: {key1:value1, key2:value2, ..., keyn:valuen}
Is there a simple way to have it converted like this? I'm trying with Jackson but don't know how to specify key and value keywords.
It is very simple:
https://stackoverflow.com/a/24012023/7137584
I would recommend using Jackson library:
import com.fasterxml.jackson.databind.ObjectMapper;
TypeReference<HashMap<String, Object>> typeRef = new TypeReference<>() {};
Map<String, Object> mapping = new ObjectMapper().readValue(jsonStr, typeRef);
The input JSON describes an array/list of map entries where each entry is a POJO:
#Data
class Entry {
private String key;
private String value; // the type of value may be Object
}
Here #Data is a Lombok annotation which provides getters, setters, toString, etc.
So, at first a list of map entries is read, which is converted then to the map:
String json = "[{\"key\":\"key1\", \"value\":\"value1\"}, {\"key\":\"key2\", \"value\":\"value2\"}, {\"key\":\"keyN\", \"value\":\"valueN\"}]";
// step 1: read raw list of entries
List<Entry> input = mapper.readValue(json, new TypeReference<List<Entry>>() {});
// step 2: convert to map
Map<String, String> mapRead = input.stream()
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
System.out.println(mapRead);
Output:
{key1=value1, key2=value2, keyN=valueN}
Here's a solution using the JSON-P api.
import javax.json.*;
var str = "[{\"key\":\"key1\", \"value\":\"value1\"}, {\"key\":\"key2\", \"value\":\"value2\"}, {\"key\":\"keyN\", \"value\":\"valueN\"}]";
JsonReader reader = Json.createReader(new StringReader(str));
JsonArray jarr = reader.readArray();
Map<String,String> map = new HashMap<>();
for(JsonValue jv : jarr) {
JsonObject jo = (JsonObject)jv;
map.put(jo.getString("key"), jo.getString("value") );
}
System.out.println(map);
I am using a JsonReader to convert the String to a JsonArray object.
Each entry of this JsonArray is a JsonObject like {key: keyX, value: valueX}.
I get the values corresponding to 'key' and 'value' and add them to a HashMap using a for loop.
I want to search data from a table where Map<String,String> is passed as parameter in search method. It will also return a Map<String,String>.
I want to solve it using Spring and Hibernate.e.g:
Map<String, String> findByItem(Map<String, String> q){
}
if you can not change method signature. i think it will be below...
Map<String, String> findByItem(Map<String, String> q){
Query listQuery = session.createSQLQuery("SELECT quiestionnaireCode, questionnaireName FROM Questionnaire WHERE quiestionnaireCode =:quiestionnaireCode AND quiestionnaireName =:quiestionnaireName");
listQuery.setParameter("quiestionnaireCode", q.get("quiestionnaireCode");
listQuery.setParameter("quiestionnaireName", q.get("quiestionnaireName");
List<Questionnaire> quiestionnaireList= listQuery.list();
Gson gson = new Gson();
String str = gson.toJson(quiestionnaireList);
Map<String, String> output = new HashMap<String, String>();
output.add("result",str);
return output;
}
I use this list:
List<HashMap<Map<String, Object>, Map<String, Object>>>
And I need to save it to a text file.
So with the List#toString method, I obtain a text like that:
[{{key=value, key=value, key=value}={key=value, key=value}}, {{key=value, key=value, key=value}={key=value, key=value}}, {{key=value, key=value, key=value}={key=value, key=value}}]
How can I convert it back to a List?
Thanks!
You are better off using a format like JSON or YAML. Usng toString() means there is too many corner cases like a = { } or , appearing in a key or value.
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map1=new HashMap<>();
map1.put("key","value");
map1.put("key1","value");
map1.put("key2","value");
map1.put("key3","value");
HashMap<Map<String, Object>, Map<String, Object>> hash=new HashMap<>();
List<HashMap<Map<String, Object>, Map<String, Object>>> lists=new ArrayList<>();
hash.put(map1, map1);
lists.add(hash);
System.out.println(mapper.writeValueAsString(lists));
The toString() method produces a format that is intended for logging and debugging, not for serialization and deserialization.
I recommend to convert your object into json format (other formats like xml can work just as well) and use a json library such as "Gson" for conversions.
Example how you can convert your object into a json string:
Gson gson = new Gson();
String json = gson.toJson(myObject);
Example how you can convert the json string back into an object, see:
creating Hashmap from a JSON String
Update: Here's a complete example of the first part:
List<HashMap<Map<String, Object>, Map<String, Object>>> myObject = new ArrayList<>();
HashMap<Map<String, Object>, Map<String, Object>> hashMap1 = new HashMap<>();
myObject.add(hashMap1);
Map<String, Object> key1 = new HashMap<>();
key1.put("key1", "keyValue1");
Map<String, Object> value1 = new HashMap<>();
value1.put("value1", "valueValue1");
hashMap1.put(key1, value1);
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
String json = gson.toJson(myObject);
System.out.println(json);
This example prints:
[{"{key1=keyValue1}":{"value1":"valueValue1"}}]
Update2 Use Pair (from apache commons lang3) instead of HashMap. That makes a lot more sense.
List<Pair<Map<String, Object>, Map<String, Object>>> myObject = new ArrayList<>();
MutablePair<Map<String, Object>, Map<String, Object>> pair1 = new MutablePair<>();
myObject.add(pair1);
Map<String, Object> key1 = new HashMap<>();
key1.put("key1", "keyValue1");
Map<String, Object> value1 = new HashMap<>();
value1.put("value1", "valueValue1");
pair1.setLeft(key1);
pair1.setRight(value1);
Gson gson = new Gson();
String json = gson.toJson(myObject);
System.out.println(json);
Prints:
[{"left":{"key1":"keyValue1"},"right":{"value1":"valueValue1"}}]
I have a JSONObject with some attributes that I want to convert into a Map<String, Object>
Is there something that I can use from the json.org or ObjectMapper?
You can use Gson() (com.google.gson) library if you find any difficulty using Jackson.
//changed yourJsonObject.toString() to yourJsonObject as suggested by Martin Meeser
HashMap<String, Object> yourHashMap = new Gson().fromJson(yourJsonObject, HashMap.class);
use Jackson (https://github.com/FasterXML/jackson) from http://json.org/
HashMap<String,Object> result =
new ObjectMapper().readValue(<JSON_OBJECT>, HashMap.class);
This is what worked for me:
public static Map<String, Object> toMap(JSONObject jsonobj) throws JSONException {
Map<String, Object> map = new HashMap<String, Object>();
Iterator<String> keys = jsonobj.keys();
while(keys.hasNext()) {
String key = keys.next();
Object value = jsonobj.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;
}
Most of this is from this question: How to convert JSONObject to new Map for all its keys using iterator java
The best way to convert it to HashMap<String, Object> is this:
HashMap<String, Object> result = new ObjectMapper().readValue(jsonString, new TypeReference<Map<String, Object>>(){}));
Note to the above solution (from A Paul):
The solution doesn't work, cause it doesn't reconstructs back a HashMap< String, Object > - instead it creates a HashMap< String, LinkedHashMap >.
Reason why is because during demarshalling, each Object (JSON marshalled as a LinkedHashMap) is used as-is, it takes 1-on-1 the LinkedHashMap (instead of converting the LinkedHashMap back to its proper Object).
If you had a HashMap< String, MyOwnObject > then proper demarshalling was possible - see following example:
ObjectMapper mapper = new ObjectMapper();
TypeFactory typeFactory = mapper.getTypeFactory();
MapType mapType = typeFactory.constructMapType(HashMap.class, String.class, MyOwnObject.class);
HashMap<String, MyOwnObject> map = mapper.readValue(new StringReader(hashTable.toString()), mapType);
The JSONObject has a method toMap which returns Map<String,Object>.
The Maven dependency used in pom.xml:
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>current-version</version>
</dependency>
You can find the current-version here.
Found out these problems can be addressed by using
ObjectMapper#convertValue(Object fromValue, Class<T> toValueType)
As a result, the origal quuestion can be solved in a 2-step converison:
Demarshall the JSON back to an object - in which the Map<String, Object> is demarshalled as a HashMap<String, LinkedHashMap>, by using bjectMapper#readValue().
Convert inner LinkedHashMaps back to proper objects
ObjectMapper mapper = new ObjectMapper();
Class clazz = (Class) Class.forName(classType);
MyOwnObject value = mapper.convertValue(value, clazz);
To prevent the 'classType' has to be known in advance, I enforced during marshalling an extra Map was added, containing <key, classNameString> pairs. So at unmarshalling time, the classType can be extracted dynamically.
This is how I did it in Kotlin:
mutableMapOf<String, Any>().apply {
jsonObj.keys().forEach { put(it, jsonObj[it]) }
}
import com.alibaba.fastjson.JSONObject;
Map<String, Object> map = new HashMap<String, Object>();
JSONObject rec = JSONObject.parseObject(<JSONString>);
map.put(rec.get("code").toString(), rec.get("value").toString());
This link from the Gson project seems to indicate that I would have to do something like the following for serializing a typed Map to JSON:
public static class NumberTypeAdapter
implements JsonSerializer<Number>, JsonDeserializer<Number>,
InstanceCreator<Number> {
public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext
context) {
return new JsonPrimitive(src);
}
public Number deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context)
throws JsonParseException {
JsonPrimitive jsonPrimitive = json.getAsJsonPrimitive();
if (jsonPrimitive.isNumber()) {
return jsonPrimitive.getAsNumber();
} else {
throw new IllegalStateException("Expected a number field, but was " + json);
}
}
public Number createInstance(Type type) {
return 1L;
}
}
public static void main(String[] args) {
Map<String, Number> map = new HashMap<String, Number>();
map.put("int", 123);
map.put("long", 1234567890123456789L);
map.put("double", 1234.5678D);
map.put("float", 1.2345F);
Type mapType = new TypeToken<Map<String, Number>>() {}.getType();
Gson gson = new GsonBuilder().registerTypeAdapter(Number.class, new
NumberTypeAdapter()).create();
String json = gson.toJson(map, mapType);
System.out.println(json);
Map<String, Number> deserializedMap = gson.fromJson(json, mapType);
System.out.println(deserializedMap);
}
Cool and that works, but it seems like so much overhead (a whole Type Adapter class?). I have used other JSON libraries like JSONLib and they let you build a map in the following way:
JSONObject json = new JSONObject();
for(Entry<String,Integer> entry : map.entrySet()){
json.put(entry.getKey(), entry.getValue());
}
Or if I have a custom class something like the following:
JSONObject json = new JSONObject();
for(Entry<String,MyClass> entry : map.entrySet()){
JSONObject myClassJson = JSONObject.fromObject(entry.getValue());
json.put(entry.getKey(), myClassJson);
}
The process is more manual, but requires way less code and doesn't have the overhead of haivng to create a custom Type Adapter for Number or in most cases for my own custom class.
Is this the only way to serialize a map with Gson, or has anyone found a way that beats out what Gson recommends in the link above.
Only the TypeToken part is neccesary (when there are Generics involved).
Map<String, String> myMap = new HashMap<String, String>();
myMap.put("one", "hello");
myMap.put("two", "world");
Gson gson = new GsonBuilder().create();
String json = gson.toJson(myMap);
System.out.println(json);
Type typeOfHashMap = new TypeToken<Map<String, String>>() { }.getType();
Map<String, String> newMap = gson.fromJson(json, typeOfHashMap); // This type must match TypeToken
System.out.println(newMap.get("one"));
System.out.println(newMap.get("two"));
Output:
{"two":"world","one":"hello"}
hello
world
Default
The default Gson implementation of Map serialization uses toString() on the key:
Gson gson = new GsonBuilder()
.setPrettyPrinting().create();
Map<Point, String> original = new HashMap<>();
original.put(new Point(1, 2), "a");
original.put(new Point(3, 4), "b");
System.out.println(gson.toJson(original));
Will give:
{
"java.awt.Point[x\u003d1,y\u003d2]": "a",
"java.awt.Point[x\u003d3,y\u003d4]": "b"
}
Using enableComplexMapKeySerialization
If you want the Map Key to be serialized according to default Gson rules you can use enableComplexMapKeySerialization. This will return an array of arrays of key-value pairs:
Gson gson = new GsonBuilder().enableComplexMapKeySerialization()
.setPrettyPrinting().create();
Map<Point, String> original = new HashMap<>();
original.put(new Point(1, 2), "a");
original.put(new Point(3, 4), "b");
System.out.println(gson.toJson(original));
Will return:
[
[
{
"x": 1,
"y": 2
},
"a"
],
[
{
"x": 3,
"y": 4
},
"b"
]
]
More details can be found here.
In Gson 2.7.2 it's as easy as
Gson gson = new Gson();
String serialized = gson.toJson(map);
I'm pretty sure GSON serializes/deserializes Maps and multiple-nested Maps (i.e. Map<String, Map<String, Object>>) just fine by default. The example provided I believe is nothing more than just a starting point if you need to do something more complex.
Check out the MapTypeAdapterFactory class in the GSON source: http://code.google.com/p/google-gson/source/browse/trunk/gson/src/main/java/com/google/gson/internal/bind/MapTypeAdapterFactory.java
So long as the types of the keys and values can be serialized into JSON strings (and you can create your own serializers/deserializers for these custom objects) you shouldn't have any issues.
Map<String, Object> config = gson.fromJson(reader, Map.class);