My question is very similiar to this:
Unable to parse Json array using Gson
But I cann't get the answer from it.
The answer from above link:
public static List<MapData> getData(){
Gson gson = new Gson();
String jsonString = "[{\"id\":18,\"city\":\"test\",\"street\":\"test 1\",\"zipcode\":121209,\"state\":\"IL\",\"lat\":32.158138,\"lng\":34.807838},{\"id\":19,\"city\":\"test\",\"street\":\"1\",\"zipcode\":76812,\"state\":\"IL\",\"lat\":32.161041,\"lng\":34.810410}]";
Type type = new TypeToken<List<MapData>>(){}.getType();
return gson.fromJson(jsonString, type);
}
It works well, but I want to use implicit operator on generic type. See below:
public static <T> List<T> getData(Class<T> classT){
Gson gson = new Gson();
String jsonString = "[{\"id\":18,\"city\":\"test\",\"street\":\"test 1\",\"zipcode\":121209,\"state\":\"IL\",\"lat\":32.158138,\"lng\":34.807838},{\"id\":19,\"city\":\"test\",\"street\":\"1\",\"zipcode\":76812,\"state\":\"IL\",\"lat\":32.161041,\"lng\":34.810410}]";
Type type = new TypeToken<List<T>>(){}.getType();
return gson.fromJson(jsonString, type);
}
And then I try to pass the Class argument to the method:
List<MapData> data = getData(MapData.class);
System.out.println(data.get(0).city);
Then an error was arised:
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.ssc.ctq.nav.util.MapData
Can anyone tell me why I get this error? Is implicit operator is not supported in TypeToken class?
you can do like this:
Gson gson = new Gson();
String jsonString = "[{\"id\":18,\"city\":\"test\",\"street\":\"test 1\",\"zipcode\":121209,\"state\":\"IL\",\"lat\":32.158138,\"lng\":34.807838},{\"id\":19,\"city\":\"test\",\"street\":\"1\",\"zipcode\":76812,\"state\":\"IL\",\"lat\":32.161041,\"lng\":34.810410}]";
List<Map> tmpList = gson.fromJson(jsonString);
List<T> resultList = new Arraylist<T>(tmplist.size());
for(Map map:tmpList){
String tmpJson = gson.toJson(map);
resultList.add(gson.fromJson(tmpJson, classT));
}
return resultList;
I met the same problem. From the Javadoc of TypeToken:
This syntax cannot be used to create type literals that have wildcard parameters, such as Class<?> or List<? extends CharSequence>.
You must explicitly indicate the type of T in TypeToken<T>, without generics.
You can use this method in order to parse generic json string to map
public Map<String, String> getMapFromJson(String jsonString) {
Map<String, String> map = new HashMap<>();
try {
JSONObject object = new JSONObject(jsonString);
Iterator<?> iterator = object.keys();
while (iterator.hasNext()) {
String key = (String) iterator.next();
if(!key.isEmpty() && !object.getString(key).isEmpty()){
map.put(key, object.getString(key));
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return map;
}
Related
I want to write a generic function to parse a json string (stringEtcdContent below in the code). The string has a list of objects with the key "value". I parse the json into a tree, get a list of JsonNode's (valueNodes below) with the string to parse using a generic class. The class in which I have the function is this: "public abstract class DashboardReportProvider". Based on a similar question here, I wrote this function:
#SuppressWarnings("unchecked")
public List<T> getStatusList(String path) {
Class<T> clazz;
clazz = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
List<T> statusList = new ArrayList<>();
T statusItem;
ObjectMapper mapper = new ObjectMapper();
try {
String stringEtcdContent = etcdCommandExecutor.getEtcdValue(path);
JsonParser parser=new MappingJsonFactory().createParser(stringEtcdContent);
JsonNode rootNode=parser.readValueAsTree();
List<JsonNode> valueNodes=rootNode.findValues("value");
Iterator<JsonNode> valueNodesIterator=valueNodes.listIterator();
while (valueNodesIterator.hasNext()) {
JsonNode valueNode=(JsonNode)valueNodesIterator.next();
ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter();
String valueString = writer.writeValueAsString(valueNode);
statusItem = mapper.readValue(valueString, clazz);
statusList.add(statusItem);
}
return statusList;
} catch (Exception e) {
LOG.error(e.getMessage());
}
return statusList;
}
It compiles fine, but when I try to run the code, I get this error:
"[ERROR] java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType". What is wrong?
Try ObjectMapper ,
new ObjectMapper().readValue(path,Object.class);
where Object.class - cast to type
here is my pojo
public class Data{
List<Object> objects;
String owneruid;
}
if the out put is pure json like this
{"object":[{"p1":100,"p2":"name","p3":"sfa0","p4":300}],"owneruid":"owneruid"}
then iam able to convert with no worries but
here is my output
{
"object":"[{\"p1\":32,\"p3\":470,\"p3\":\"213\",\"p4\":\"name\"}]",
"owneruid":"6697729776330393738"
}
im converting a json string to string because to store in my db as it does not accept json so when i query returns like above so every time i need to fetch the value and convert it to json object and put it in list and display. can you suggest me a better approach.
And when i try to convert a list of custom classes to json using GSON
ArrayList<Object> list=new ArrayList<>();
Object object=new Object();
object.setP1(3);
object.setP2(4);
list.add(object);
Gson gson=new Gson();
String json = gson.toJson(list);
Required:
{"object":[{"p1":100,"p2":"name","p2":"sfa0","p4":300}],"owneruid":"owneruid"}
buts it ends like this
{"object":"[{\"p1\":313,\"p2\":470,\"p3\":\"1521739327417\",\"p4\":\"name\"}]","owneruid":"6697729776330393738"}
You have to use any json frameworks. E.g. Jackson or Gson. As alternative you could do smth. like this. Just evaluate JavaScript.
public static void main(String... args) throws ScriptException {
ScriptEngine js = new ScriptEngineManager().getEngineByName("javascript");
Object obj = js.eval("[{\"width\":313,\"height\":470,\"mediauid\":\"1521739327417\",\"mediatype\":\"image\"}]");
// res is either List<Object> or Map<String, Object>
Object res = convertIntoJavaObject(obj);
}
private static Object convertIntoJavaObject(Object obj) {
if (!(obj instanceof ScriptObjectMirror))
return obj;
ScriptObjectMirror mirror = (ScriptObjectMirror)obj;
if (mirror.isArray())
return mirror.entrySet().stream()
.map(entry -> convertIntoJavaObject(entry.getValue()))
.collect(Collectors.toList());
Map<String, Object> map = new HashMap<>();
mirror.entrySet().forEach((key, value) -> map.put(key, convertIntoJavaObject(value)));
return map;
}
You can use the below code snippet as it seems fit for your case.
ObjectMapper can be found with Jackson framework. inputJson is the JSON string you have mentioned.
ObjectMapper mapper = new ObjectMapper();
Object mediaMetaDataObj = mapper.readValue( inputJson, Object.class );
Hope this helps.
Below my function,
public <T> List<T> jsonToListBean(String json, Class<T> clazz) {
Gson gson = new Gson();
Type listType = new TypeToken<List<T>>(){}.getType();
List<T> returnValue = gson.fromJson(json, listType);
return returnValue;
}
but the system returns this exception:
java.lang.ClassCastException: com.google.gson.internal.StringMap
I notice also that if I use the following line code
Type listType = new TypeToken<ArrayList<ShapeBean>>(){}.getType();
it works, but my target is to be absolutly as generic as possible to make my code more efficient.
How should i change my code to make usable also passing the type "T" instead the "ShapeBean"?
Solved. Thanks to kan's link below the code:
public <T> List<T> listEntity(String jsonCommand, Class<T> clazz) {
List<T> lst = new ArrayList<T>();
try {
// Consuming remote method
JsonParser parser = new JsonParser();
JsonArray array = parser.parse(jsonCommand).getAsJsonArray();
for(final JsonElement json: array){
Gson g = new Gson();
T entity = g.fromJson(json, clazz);
lst.add(entity);
}
} catch (Exception e) {
e.printStackTrace();
} return lst;
}
check also this:
Gson TypeToken with dynamic ArrayList item type
I want to make a generic method for saving any type of List to SharedPreference.
public static List<T extends Object> readAnyTypeOfList<T>() {
Gson gson = new Gson();
return (gson.fromJson(SharedPref.read("anyTypeOfList", "[]"),
new TypeToken<List<T>>() {
}.getType()));
}
And for saving any Type of List
public static void saveAnyTypeOfList(List<T> value) {
Gson gson = new GsonBuilder().create();
JsonArray jsonArray = gson.toJsonTree(value).getAsJsonArray();
SharedPref.save("anyTypeOfList", jsonArray.toString());
}
but both methdos give error . what is the proper way to create a generic method. I have also tried this
where working example is
public static ListOfModel = "ListKey"
public static List<ModelClass> readListOfModel() {
Gson gson = new Gson();
return (gson.fromJson(SharedPref.read(ListOfModel, "[]"),
new TypeToken<List<ModelClass>>() {
}.getType()));
}
public static void saveListOfModel(List<ModelClass> value) {
Gson gson = new GsonBuilder().create();
JsonArray jsonArray = gson.toJsonTree(value).getAsJsonArray();
SharedPref.save(ListOfModel, jsonArray.toString());
}
You can not create a TypeToken generically like that. T is erased, the specific type information is not available at runtime, so there will be no information in the token.
The error you made in the declaration of the generic methods, is that you never declared the type variable T. Like this:
public static <T> someMethod(T t) {...}
//............^^^
(The syntax is different from C#)
My advice would be to do like this:
public static <T> void saveAnyTypeOfList(String key, List<T> value) {
Gson gson = new GsonBuilder().create();
JsonArray jsonArray = gson.toJsonTree(value).getAsJsonArray();
SharedPref.save(key, jsonArray.toString());
}
public static <T> List<T> readAnyTypeOfList(String key, TypeToken<List<T>> tt) {
Gson gson = new Gson();
return (gson.fromJson(SharedPref.read(key, "[]"), tt.getType()));
}
I use the Gson library and I have a class that has an arraylist as one of its members.
I add different object types to this arraylist then I serialize it to json
public class MethodParameter {
private String className;
private String methodName;
private ArrayList parameters;
public MethodParameter(){
parameters = new ArrayList();
}
public String getClassName(){
return className;
}
public String getMethodName(){
return methodName;
}
public List<Object> getParameters(){
return parameters;
}
public void setClassName(String value){
className = value;
}
public void setMethodName(String value){
methodName = value;
}
public void setParameters(ArrayList value){
parameters = value;
}
}
Then I convert as follows:
Gson gson = new Gson();
java.lang.reflect.Type type = new TypeToken<MethodParameter>() {}.getType();
String json = gson.toJson(mp, type);
but all I get is :
{"className":"MainClass","methodName":"Test","parameters":[]}
Parameters is an arraylist to which I add classes of different types. How do I get it to create the correct json result?
I tried your code and 2 things,
define the MethodParameter.parameters as a list (just a best practice)
the issue may be in the way you are manipulating the list in the MethodParameter object...
anyway here is a snippet working as you want it to do:
Example:
public static void main(String[] args) {
MethodParameter mp = new MethodParameter();
mp.setClassName(String.class.getCanonicalName());
mp.setMethodName("replace");
List<String> parametersList = new ArrayList<String>();
parametersList.add("target");
parametersList.add("sequence");
mp.setParameters(parametersList);
//
Gson gson = new Gson();
java.lang.reflect.Type type = new TypeToken<MethodParameter>() {
}.getType();
String json = gson.toJson(mp, type);
System.out.println(json);
}
but in my opinion you can generate the json by just doing this:
System.out.println(gson.toJson(mp, MethodParameter.class));