I am trying to write a class, that has exportToString and importFromString methods. ExportToString serializes this class to JSON string:
public String exportToString() {
Gson gson = new Gson();
String json = gson.toJson(this);
return json;
}
I need to write importFromString(String str). The problem is that "this" variable is final and I can't reassign this value completely. This is what I have:
public void importFromString(String str) {
Gson gson = new Gson();
Object obj = gson.fromJson(str, this.getClass());
this = (PlayerData) obj; // ERROR: cannot assign value to final variable this
}
P.S. Sorry for my english
I think the simplest way to do what you want is to make the second method static and return an instance of the object represented in the string:
public static PlayerData importFromString(String str) {
Gson gson = new Gson();
Object obj = gson.fromJson(str, PlayerData.class);
return (PlayerData) obj;
}
You then invoke it as follows:
PlayerData obj = PlayerData.importFromString(someString);
Something like this maybe?
public static PlayerData importFromString(String str) {
Gson gson = new Gson();
Object obj = gson.fromJson(str, PlayerData.class);
return (PlayerData) obj;
}
Related
I have the following Java class
public static class LogItem {
public Long timestamp;
public Integer level;
public String topic;
public String type;
public String message;
}
and I want to convert an ArrayList<LogItem> into the following JSON string:
{"logitems":[
{"timestamp":1560924642000, "level":20, "topic":"websocket", "type":"status", "message":"connected (mobile)"},
...
]}`
I would like to do the following:
JSONArray logitems = new JSONArray();
for (DB_LogUtils.LogItem item : items) {
logitems.put(DB_LogUtils.asJSONObject(item)); // <----
}
JSONObject data = new JSONObject();
data.put("logitems", logitems);
webViewFragment.onInjectMessage(data.toString(), null);
where DB_LogUtils.asJSONObject is the following method
public static JSONObject asJSONObject(LogItem item) throws JSONException
{
JSONObject logitem = new JSONObject();
logitem.put("timestamp", item.timestamp);
logitem.put("level", item.level);
logitem.put("topic", item.topic);
logitem.put("type", item.type);
logitem.put("message", item.message);
return logitem;
}
but instead of doing this manually (like logitem.put("timestamp", item.timestamp);) I want to do this with Gson, so that I would end up with something like this
JSONArray logitems = new JSONArray();
for (DB_LogUtils.LogItem item : items) {
logitems.put(new Gson().toJSONObject(item)); // <----
}
JSONObject data = new JSONObject();
data.put("logitems", logitems);
webViewFragment.onInjectMessage(data.toString(), null);
in order to not have to edit the code at multiple points when the LogItem class changes.
But Gson().toJSONObject(...) does not exist, only Gson().toJson(...), which returns a String. I don't want to transition into a String only to then parse it with org.json.JSONObject.
I ended up using a second class
public static class LogItems {
public List<LogItem> logitems = new ArrayList<>();
}
which then let me change the whole code to
webViewFragment.onInjectMessage(new Gson().toJson(items), null);
where items would be of type LogItems.
In this case, creating the extra wrapper class was an overall benefit, but I'd still want to know how I can create such a JSONObject from a class by using Gson.
As far as i know it could be not possible without using for loop to iterate json string into array and store into map with same key.
But you can achieve your solution instead of passing dto pass the list of items into gson object as follow.
List<Object> list = new ArrayList<Object>();
list.add("1560924642000");
list.add(20);
list.add("websocket");
list.add("status");
list.add("connected (mobile)");
Gson gson = new Gson();
Map mp = new HashMap();
mp.put("ietams", list);
String json = gson.toJson(mp);
System.out.println(json);
output will be
{"logitems":["1560924642000",20,"websocket","status","connected (mobile)"]}
Hope this will help !
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.
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));
My json string looks like the following:
{
"text": ["foo",1,"bar","2",3],
"text1": "value1",
"ComplexObject": {
.....
}
}
I have a pojo defined like this:
class MyPojo {
List<String> text;
String text1;
ComplexObject complexObject;
}
I use google gson and am able to get my java object populated properly. The problem here is that the field text is an array of mixed types (string and int). So all the entries there are converted into String and i am not able to figure out which entries in the array is a string vs int. I cant use parseInt since the entries in the original array may have "2" as well as 3.
Is there a way for me to get the right instance type of the fields in my array after converting into java object.
SOLUTION
So i implemented the solution using gson the round about way using the JsonDeserializer. And then i tried using jackson. Guess what jackson supports serializing/deserializing the mixed array type by preserving the data types.
ObjectMapper mapper = new ObjectMapper();
MyPojo gmEntry = mapper.readValue(json, new TypeReference<MyPojo >(){});
And i can basically fetch the List<Object> and do an instanceof to check for the datatype.
Shame on you gson!!
By having a custom class and adding a type adapter u can manipulate the string (json.toString() returns with the '"' quotes, so you can see if its a string or not.
Output: (the classes seem correct)
class test.Main$StringPojo pojo{object=foo}
class test.Main$IntPojo pojo{object=1}
class test.Main$StringPojo pojo{object=bar}
class test.Main$StringPojo pojo{object=2}
class test.Main$IntPojo pojo{object=3}
public static void main(final String[] args){
String str = "{\n" +
" \"text\": [\"foo\",1,\"bar\",\"2\",3],\n" +
" \"text1\": \"value1\" }";
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(pojo.class, new JsonDeserializer<pojo>() {
#Override
public pojo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
try {
return new IntPojo(Integer.parseInt(json.toString()));
} catch (Exception e) {
return new StringPojo(json.getAsString());
}
}
});
MyPojo myPojo = builder.create().fromJson(str, MyPojo.class);
for (pojo pojo : myPojo.text) {
System.out.println(pojo.getClass() + " " + pojo.object);
}
}
public static abstract class pojo{
protected Object object;
public pojo() {
}
#Override
public String toString() {
return "pojo{" +
"object=" + object +
'}';
}
}
public static class StringPojo extends pojo{
public StringPojo(String str) {
object = str;
}
}
public static class IntPojo extends pojo{
public IntPojo(int intt) {
this.object = intt;
}
}
public static class MyPojo {
List<pojo> text;
String text1;
}
As you wrote - you defined: List<String> text; but that list also contains integers.
Java is strongly typed, please consider to either declare the List as List<Object> (less preferable) or creating a JSON list that contains only a single type of variable (more preferable).
You can create an abstract class ItemType (for use as array item type) and inherits from it two wrapper classes: one for int type and another for string type.
abstract class ItemType {
protected Object value;
}
class IntType extends ItemType {
IntType(Integer value){
this.value = value;
}
}
class StringType extends ItemType {
IntType(String value){
this.value = value;
}
}
Try this List<ItemType> text;
The above situation can be achived by using TypeAdapter of Gson API.
Please follow : https://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Collection-with-Objects-of-Arbitrary-Types
Not sure if this is what you need, but this is the code I use for parsing JSON.
static public void newsParser(String urlString, String targetObject) throws FileNotFoundException, IOException
{
URL url = new URL(urlString);
JSONParser parser=new JSONParser();
BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
Object obj;
try
{
obj = parser.parse(br);
//JSONObject jsonObject = (JSONObject) obj;
JSONArray jsonArray = (JSONArray) obj;
Iterator<?> i = jsonArray.iterator();
while (i.hasNext())
{
slide = (JSONObject) i.next();
newsInfo = (String)slide.get(targetObject);
System.out.println(newsInfo);
newsTitles.add(newsInfo);
}
}
catch (ParseException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}