How to re-use code when use gson to parse json file? - java

I got a problem when I use gson to parse json file. I want to deserialize some similar json files
to my objects. I typed a method to do this job, but I don't know how to apply this method to different json files. These json files have some similar structures, so I want to deserialize them into subtypes of the same supertypes.
private Map<String, PatternDetectionRequestBody> readRequestFromJson(File jsonFile) {
Map<String, PatternDetectionRequestBody> requestBodyMap = null;
try {
FileReader fileReader = new FileReader(jsonFile);
JsonReader jsonReader = new JsonReader(fileReader);
Gson gson = new Gson();
Type type = new TypeToken<Map<String, PatternDetectionRequestBody>>(){}.getType();
requestBodyMap = gson.fromJson(jsonReader, type);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return requestBodyMap;
}
As code above, I want to use this code to parse different json files by changing PatternDetectionRequestBody to some sibling classes. Could anyone tell me how to do this?

Can't you just do something like this? Class<? extends ParentOfYourObject>
EDIT
Did something like this for a trial, and it worked.
private static <T> Map<String, T> readRequestFromJson(File jsonFile, TypeToken<Map<String, T>> typeToken) {
Map<String, T> requestBodyMap = null;
try {
FileReader fileReader = new FileReader(jsonFile);
JsonReader jsonReader = new JsonReader(fileReader);
Gson gson = new Gson();
requestBodyMap = gson.fromJson(jsonReader, typeToken.getType());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return requestBodyMap;
}
public static void main(String[] args) throws Exception {
Map<String, Person> myMap = (Map<String, Person>) readRequestFromJson(new File("C:/Users/User.Admin/Desktop/jsonFile"),
new TypeToken<Map<String, Person>>() {
});
for (Map.Entry<String, Person> entry : myMap.entrySet()) {
System.out.println(entry.getValue().getFirstName());
}
}

Related

Inner object(ArrayList) is not converting to JSON String?

I am facing issue in converting the nested list object to JSON.I am using object mapper and it is only converting the starting values and after that there is one arraylist inside it and it is not going through that list.
I have tried some basic iteration using JsonNode root = mapper.valueToTree(obj)so that i can iterate through the inner arraylist but i am not getting the result.I am new to this parsing conversion.
code snippet--
public class JsonUtils {
public static <T> String toJsonString(final T obj) throws IOException {
final ObjectMapper mapper = new ObjectMapper();
String jsonString = null;
try {
//JsonNode root = mapper.valueToTree(obj);
jsonString = mapper.writeValueAsString(obj);
} catch (final JsonProcessingException e) {
throw e;
} catch (IOException e) {
throw e;
}
return jsonString;
}
public static <T> String toJsonString(final List<T> lstObject) throws JSONException, IOException {
final JSONArray jsonArray = new JSONArray();
for (final T object : lstObject) {
final String json = JsonUtils.toJsonString(object);
final JSONObject jsonObj = new JSONObject(json);
jsonArray.put(jsonObj);
}
return jsonArray.toString();
}
}
So here is the result which i am getting -
[2, [{"geoMarketId":1,"geoname":"AP","geoId":1,"checked":false},
{"geoMarketId":7,"geoname":"EP","geoId":2,"checked":false},
{"geoMarketId":16,"geoname":"Japan","geoId":3,"checked":true},
{"geoMarketId":18,"geoname":"LA","geoId":4,"checked":true},
{"geoMarketId":22,"geoname":"MEA","geoId":5,"checked":true},
{"geoMarketId":24,"geoname":"NA","geoId":6,"checked":false}]]
Actual Result which should come-
{"geoMarketId":1,"geoname":"AP","geoId":1,"checked":false,
marketName:{"marketname":JP,"marketname":"AP","marketname":MP}}
My json conversion is ignoring this inner list in the same index.
Is there any way my json class can iterate and also convert that innerlist to JSON?

Deserialization fails with when using null as map key

Gson deserialization failed when using null as map key
Gson gson = new GsonBuilder()
.serializeNulls()
.serializeSpecialFloatingPointValues()
.create();
Map<Integer, String> mapData = new HashMap<Integer, String>();
mapData.put(null, "abc");
String data = gson.toJson(mapData);
System.out.println(data);
Type type = TypeToken.getParameterized(HashMap.class, Integer.class, String.class).getType();
Object obj = gson.fromJson(data, type);
System.out.println(obj);
Exception:
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: For input string: "null"
The following code snippet work well.
Gson gson = new GsonBuilder()
.serializeNulls()
.serializeSpecialFloatingPointValues()
.create();
Map<String, Integer> mapData = new HashMap<>();
mapData.put("abc", null);
String data = gson.toJson(mapData);
System.out.println(data);
Type type = TypeToken.getParameterized(HashMap.class, String.class, Integer.class).getType();
Object obj = gson.fromJson(data, type);
System.out.println(obj);
output:
{"abc":null}
{abc=null}
You can create TypeAdapter for Integer:
Gson gson = new GsonBuilder()
.serializeNulls()
.serializeSpecialFloatingPointValues()
.registerTypeAdapter(Integer.class, new TypeAdapter<Integer>() {
#Override
public void write(JsonWriter jsonWriter, Integer integer) throws IOException {
jsonWriter.jsonValue(String.valueOf(integer));
}
#Override
public Integer read(JsonReader jsonReader) throws IOException {
if (jsonReader.peek() == JsonToken.NULL) {
jsonReader.nextNull();
return null;
} else {
String numberStr = jsonReader.nextString();
return "null".equals(numberStr) ? null : Integer.valueOf(numberStr);
}
}
})
.create();
Output:
{"null":"abc"}
{null=abc}
The reason why null works for value and doesn't works for key without custom Integer Adapter, is the way map adapter serialises each: key all the time is String in JSON, it couldn't be neither int or null. You can see it in your output: {"null":"abc"} vs {"abc":null}.
Check out implementation of map type adapter.

Java:JSON to map using GSON

I have a string like this
{"key0":"value0","key1":"value1","key0":"value3"}
I want to store it in a map and the desired result is {"key0":"value3","key1":"value1"}
Using org.json.JsonObject: I passed the string to the constructor and Duplicate key exception is thrown
Using GSON: Same exception when I tried through new Gson.fromJson(string,Type)
Using Jackson: It does work
Is there a workaround to achieve the same using JSONObject and Gson
Interestingly if you first cast that json to an Object and then to a Map<String,String> your desired result happens:
String json = "{\"key0\":\"value0\",\"key1\":\"value1\",\"key0\":\"value3\"}";
Gson gson = new Gson();
Object obj = gson.fromJson(json, Object.class);
try {
Map<String,String> map = (Map<String, String>)obj;
// Outputs...
// key0=value3
// key1=value1
for (Map.Entry<String,String> entry : map.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
} catch (ClassCastException e) {
e.printStackTrace();
}
GSON uses MapTypeAdapterFactory to deserialioze map. Below is a short excerpt of its source code where a new entry is put in a map:
V replaced = map.put(key, value);
if (replaced != null) {
throw new JsonSyntaxException("duplicate key: " + key);
}
Knowing that there is at least one way to bypass this strict behavior: create your own map that overrides the method put(..) to return always null, like:
public class DuploMap extends HashMap<String, String>{
#Override
public String put(String key, String value) {
super.put(key, value);
return null;
}
}
then deserailizing to it like:
gson.fromJson(JSON, DuploMap.class);
will not throw that exception.
You can use GSON's JsonReader if you do not mind the manual effort.
On the plus side:
faster (no reflection, no casts)
fully under your control
--
String json = "{"key0":"value0","key1":"value1","key0":"value3"}";
JsonReader jsonReader = new JsonReader(new StringReader(json));
HashMap<String,String> map = new HashMap<String, String>()
String currKey;
try {
while(jsonReader.hasNext()){
JsonToken nextToken = jsonReader.peek();
if(JsonToken.NAME.equals(nextToken)){
currKey = jsonReader.nextName();
}
if(JsonToken.STRING.equals(nextToken)){
map.put(currKey, jsonReader.nextString())
}
}
} catch (IOException e) {
e.printStackTrace();
}

Parsing JSON into a object

I'm trying to parse this JSON using gson:
{"hvs1":{"16191":[["TestFile3","C",["A"]],["TestFile3","-",["1G","1A"]]],"16193":[["TestFile3","C",["G"]]]},"hvs2":{"25":[["TestFile3","-",["1A"]]]},"outros":{"16423":[["TestFile3","A",["T"]]]}}
Into this object
public class Results {
private String regiaoAfetada;
private String posicaoReferencia;
private String nomeDoArquivo;
private String baseAlteradaReferencia;
private List<String> mutacaoEncontrada;
//get and set
}
And my test class to try to achive this, but I'm getting a error.
public class JsonTeste {
public static void main(String[] args) {
Gson gson = new Gson();
try (Reader reader = new FileReader("foobar.json")) {
Type type = new TypeToken<TreeMap<String, TreeMap>>() {
}.getType();
TreeMap<String, TreeMap<String, List<List<List<String>>>>> map = gson.fromJson(reader, type);
List<Results> listaMutacoes = new ArrayList<Results>();
for (Entry<String, TreeMap<String, List<List<List<String>>>>> regioesMap : map.entrySet()) {
TreeMap<String, List<List<List<String>>>> regiaoUm = regioesMap.getValue();
for (Entry<String, List<List<List<String>>>> regiaoUmResult : regiaoUm.entrySet()) {
List<List<List<String>>> resultados = regiaoUmResult.getValue();
for (List<List<String>> list : resultados) {
Results resultado = new Results();
resultado.setRegiaoAfetada(regioesMap.getKey());
resultado.setPosicaoReferencia(regiaoUmResult.getKey());
resultado.setNomeDoArquivo(list.get(0).toString());
resultado.setBaseAlteradaReferencia(list.get(1).toString());
resultado.setMutacaoEncontrada(list.get(2));
listaMutacoes.add(resultado);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
The problem is when I try to parse this part
[
"TestFile3",
"-",
[
"1G",
"1A"
]
]
Because I have two Strings and a Array inside, so the problem Is when I try to place "TestFile3" into setNomeDoArquivo, but even if I comment this line, i get the same error in the second line.
resultado.setNomeDoArquivo(list.get(0).toString());
resultado.setBaseAlteradaReferencia(list.get(1).toString());
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.List
Can you guys help me?
The List resultados is of List<string> or List<List<String>>.When you get the item of resultados it can be one of them. So to generalized declare it as List<List<Object>>
Try The below Code :
Gson gson = new Gson();
try (Reader reader = new FileReader("foobar.json")) {
Type type = new TypeToken<TreeMap<String, TreeMap>>() {
}.getType();
TreeMap<String, TreeMap<String, List<List<Object>>>> map = gson.fromJson(reader, type);
List<Results> listaMutacoes = new ArrayList<>();
for (Map.Entry<String, TreeMap<String, List<List<Object>>>> regioesMap : map.entrySet()) {
TreeMap<String, List<List<Object>>> regiaoUm = regioesMap.getValue();
for (Map.Entry<String, List<List<Object>>> regiaoUmResult : regiaoUm.entrySet()) {
List<List<Object>> resultados = regiaoUmResult.getValue();
for (List<Object> list : resultados) {
System.out.println(list);
Results resultado = new Results();
resultado.setRegiaoAfetada(regioesMap.getKey());
resultado.setPosicaoReferencia(regiaoUmResult.getKey());
resultado.setNomeDoArquivo((String) list.get(0));
resultado.setBaseAlteradaReferencia((String) list.get(1));
resultado.setMutacaoEncontrada((List<String>) list.get(2));
listaMutacoes.add(resultado);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}

Regarding serialize hibernate object to json using Gson

I m trying to serialize hibernate object to json with the use of Gson library.I had to implement custom Type Adapter in this case because GSon can't serialize HibernateProxy objects in normal manner.I tried to implement the TypeAdapter as I can use with any object type without modifying it .
Here is my TypeAdapter class :
public class CustomTypeAdapter implements JsonSerializer<Object> {
#Override
public JsonElement serialize(Object object, Type type, JsonSerializationContext jsc) {
JsonObject jsonObject = new JsonObject();
try {
Map<String, String> properties = BeanUtils.describe(object);
//org.apache.commons.beanutils
for (Map.Entry<String, String> entry : properties.entrySet()) {
jsonObject.addProperty(entry.getKey(), entry.getValue());
}
} catch (Exception ex) {
ex.printStackTrace();
}
return jsonObject;
}
}
But the problem I have got is the inner objects are not going to serialize with this implementation. It is just returns the address of the object.(Product#54554356)
List<ProductHasSize> phsList = s.createCriteria(ProductHasSize.class, "phs")
.createAlias("phs.product", "product")
.add(Restrictions.eq("product.id", 1))
.list();
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.registerTypeAdapter(ProductHasSize.class, new CustomTypeAdapter()).create();
String element = gson.toJson(phsList);
response.getWriter().write(element);
Current Out-put :
[{"product":"com.certus.dbmodel.Product#54554356","size":"com.certus.dbmodel.Size#215a88a","price":"1250.0","qnty":"20","id":"1","class":"class com.certus.dbmodel.ProductHasSize"},{"product":"com.certus.dbmodel.Product#54554356","size":"com.certus.dbmodel.Size#2eab455a","price":"1300.0","qnty":"5","id":"2","class":"class com.certus.dbmodel.ProductHasSize"}]
Thanks in advance.
BeanUtils.describe does not provide enough information. It will be fine if all types are primitive.
You will have to serialize each property independently. For fields that are not primitive types, serialize them. You also have to create the adapter for the actual type, so you can access its properties.
public class CustomTypeAdapter implements JsonSerializer<ProductHasSize> {
#Override
public JsonElement serialize(ProductHasSize phs, Type type, JsonSerializationContext jsc) {
JsonObject jsonObject = new JsonObject();
// try {
// Map<String, String> properties = BeanUtils.describe(object);
// //org.apache.commons.beanutils
// for (Map.Entry<String, String> entry : properties.entrySet()) {
// jsonObject.addProperty(entry.getKey(), entry.getValue());
// }
// } catch (Exception ex) {
// ex.printStackTrace();
// }
jsonObject.addProperty("price", phs.getPrice());
jsonObject.addProperty("quantity", phs.getQuantity());
JsonElement jsonProduct = jsc.serialize(phs.getProduct());
jsonObject.add("product", jsonProduct);
JsonElement jsonSize = jsc.serialize(phs.getSize());
jsonObject.add("size", jsonSize);
return jsonObject;
}
}
This page has a nice introduction: http://www.javacreed.com/gson-serialiser-example/

Categories

Resources