Im trying to deserialize a JSON string into an array of objects looking like this:
[{"ParentLocationName":null
,"Id":"String-Id"
,"Name":"String-Name"
,"ExternalId":null
,"LocationType":0
,"TimeZone":null
,"ParentLocationId":null}
,{"ParentLocationName":"String-Name"
,"Id":"String-Id2"
,"Name":"Child-Name"
,"ExternalId":null
,"LocationType":0
,"TimeZone":null
,"ParentLocationId":"String-Id"}
,{"ParentLocationName":null
,"Id":"String-Id3"
,"Name":"Some other name"
,"ExternalId":null
,"LocationType":0
,"TimeZone":null
,"ParentLocationId":null}]
so I have a class called Location with corresponding fields:
public class Location {
public String ParentLocationName;
public String Id;
public String Name;
public String ExternalId;
public int LocationType;
public String TimeZone;
public String ParentLocationId;
}
Where I am using Gson in the following way:
Gson gson = new Gson();
Location[] places = gson.fromJson(Json_As_String, Location[].class);
and I am receiving error:
Expected a string but was BEGIN_OBJECT at line 1 column 3 path $[0]
Ive also tried using a collection like so:
Type collectionType = new TypeToken<>
Type colType = new TypeToken<Collection<Location>>(){}.getType();
Collection<Location> locs = gson.fromJson(Json_As_String,colType );
But receiving the same error.
Related
I have a problem. I have the following JSON:
{
"Market":"USDT",
"Coin":"BTC",
"Period":"1h",
"EmergencyPerc":-25,
"TakeProfitPerc":1.2,
"ProtectiveOrdersEnabled":"no",
"EMACrossMarginPerc":0.5,
"EMABuySellPeriod":"15m",
"EMABuySellNameLow":"EMA10",
"EMABuySellNameHigh":"EMA50",
"EMAUnfreezePeriod":"1h",
"EMAUnfreezeNameLow":"EMA20",
"EMAUnfreezeNameHigh":"EMA200",
"SimTemplate":"t001",
"Patterns":{
"Buy":[
"buy_pattern_1",
"buy_pattern_2"
],
"Sell":[
"sell_pattern_1",
"sell_pattern_2"
]
}
}
I want to parse that JSON to the following class:
public class AgentStrategy {
private String Market;
private String Coin;
private double EmergencyPerc;
private double TakeProfitPerc;
private String ProtectiveOrdersEnabled;
public double EMACrossMarginPerc;
public String EMABuySellPeriod;
public String EMABuySellNameLow;
public String EMABuySellNameHigh;
public String EMAUnfreezePeriod;
public String EMAUnfreezeNameLow;
public String EMAUnfreezeNameHigh;
private String SimTemplate;
private ArrayList<PriceDropSell> PriceDropSells;
private ArrayList<String> buyPatternsUsed = new ArrayList<>();
private ArrayList<String> sellPatternsUsed = new ArrayList<>();
}
For that I have the following method inside that class:
public AgentStrategy parseJsonToObject(String jsonString) {
Gson gson = new Gson();
AgentStrategy agent = gson.fromJson(jsonString, AgentStrategy.class);
// PATTERNS
Map patternsMap = (Map) map.get("Patterns");
Map sellMap = (Map) patternsMap.get("Sell");
Map buyMap = (Map) patternsMap.get("Buy");
agent.buyPatternsUsed = new ArrayList<>(sellMap.values());
agent.buyPatternsUsed = new ArrayList<>(buyMap.values());
return agent;
}
But I get an error on this line at the pattern parse part:
agent.buyPatternsUsed = new ArrayList<>(sellMap.values());
With: Exception in thread "main" java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class java.util.Map (java.util.ArrayList and java.util.Map are in module java.base of loader 'bootstrap')
How can I parse all the patterns from buy and sell to a String Array (seperate)?
How can I parse all the patterns from buy and sell to a String Array (seperate)?
The JSON you posted has two arrays and you're trying to parse them as maps. Parse them as arrays (lists).
List sellList = (List) patternsMap.get("Sell");
List buyList = (List) patternsMap.get("Buy");
That said, the true power of GSON (and JSON parsers in general) is that do the heavy work for you if you model your classes correctly. You could have a "Patterns" class that has two lists of strings, then the strategy class would have a "Pattern". For example:
class Patterns {
List<String> Buy;
List<String> Sell;
}
class Agent Strategy {
Patterns Patterns;
}
Now, when you parse the object, because the class structure matches the json structure, the lists are parsed automatically for you:
AgentStrategy agent = gson.fromJson(jsonString, AgentStrategy.class);
// agent.Patterns.Buy and .Sell now have the lists
Then you could just define helpers to get the data you care about:
class Agent Strategy {
Patterns Patterns;
public getBuyPatternsUsed() { return Patterns.Buy; }
public getSellPatternsUsed() { return Patterns.Sell; }
}
P.S. - Tip: when you see "class cast exception" use your debugger to step through up to line where the crash happens and see what type you're actually getting compared to what you expect. That will help you debug your issue.
"Buy":[
"buy_pattern_1",
"buy_pattern_2"
],
"Sell":[
"sell_pattern_1",
"sell_pattern_2"
]
The Buy and Sell are arrays.
So the following cast will throw exception
Map sellMap = (Map) patternsMap.get("Sell");
Map buyMap = (Map) patternsMap.get("Buy");
Suggestion
Try to use annotations to map the java attribute name and json field name
i have only named few fields (using #SerializedName annotation)
static class PriceDropSell {
#SerializedName("Buy")
List<String> buy;
#SerializedName("Sell")
List<String> sell;
}
static class AgentStrategy {
private String Market;
private String Coin;
private double EmergencyPerc;
private double TakeProfitPerc;
private String ProtectiveOrdersEnabled;
public double EMACrossMarginPerc;
public String EMABuySellPeriod;
public String EMABuySellNameLow;
public String EMABuySellNameHigh;
public String EMAUnfreezePeriod;
public String EMAUnfreezeNameLow;
public String EMAUnfreezeNameHigh;
private String SimTemplate;
#SerializedName(("Patterns"))
private PriceDropSell Patterns;
}
public static void main(String[] args) {
Gson gson = new Gson();
AgentStrategy agentStrategy = gson.fromJson(str, AgentStrategy.class);
System.out.println(gson.toJson(agentStrategy));
}
I have some json string like this:
example1
{
"path":{
"start":"abc"
},
"name":"Fork1"
}
example2
{
"path":[{
"start":"abc"
},
{
"start":"def"
}],
"name":"Fork1"
}
and I want to serialize with one JAVA object like this:
#Data
public static class ForkNode {
private List<Path> path;
private String name;
}
#Data
public static class Path {
private String start;
}
new Gson().fromJson(jsonStr, ForkNode.class)
but it will throw an exception
IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 2 column 11 path $.path
So how do I treat the first example as a list of one elements?
Or is there any way I can serialize two different types of json strings with one object?
I don't think it is a good way to serialize two different types of json strings with ONE object.
For example 1, the Object should be like this:
#Data
public static class ForkNode {
// only one path
private Path path;
private String name;
}
#Data
public static class Path {
private String start;
}
new Gson().fromJson(jsonStr, ForkNode.class)
While For example 2, the Object should be like this:
#Data
public static class ForkNode {
// several paths
private List<Path> path;
private String name;
}
#Data
public static class Path {
private String start;
}
new Gson().fromJson(jsonStr, ForkNode.class)
In JSON:
Objects are enclosed directly in curly brackets {} While JSON
Arrays that are enclosed in square brackets [] inside JSON Objects.
One more thing, If you do really want to do that, I think you need to implement a custom deserializer by yourself. Please ref the doc of Gson.
I solved it by modify JsonObject.
I use this code to convent JsonObject to JsonArray, so I can deserializer it like JsonArray.
public void objectToArray(JsonObject jsonObject, String node) {
JsonElement jsonElement = jsonObject.get(node);
if (jsonElement instanceof JsonObject) {
JsonArray array = new JsonArray();
array.add(jsonElement);
jsonObject.remove(node);
jsonObject.add(node, array);
}
}
This question already has answers here:
Simple parse JSON from URL on Android and display in listview
(6 answers)
Get JSONArray without array name?
(4 answers)
Parsing json array with no name in android [closed]
(4 answers)
Closed 4 years ago.
I am trying to parse the JSON data retrieved from the following link
http://fipeapi.appspot.com/api/1/carros/marcas.json
It does not have a name of the JsonArray. Here is what I have tried so far.
private String getName(int position) {
String name = "";
try {
//Getting object of given index
JSONObject json = result.getJSONObject(position);
//Fetching name from that object
name = json.getString(Config.TAG_NAME);
} catch (JSONException e) {
e.printStackTrace();
}
//Returning the name
return name;
}
And here is the Config class
public class Config {
//JSON URL
public static final String DATA_URL = "http://fipeapi.appspot.com/api/1/carros/marcas.json";
//Tags used in the JSON String
public static final String TAG_USERNAME = "name";
public static final String TAG_NAME = "fipe_name";
public static final String TAG_COURSE = "key";
public static final String TAG_ID_MARCA_CARRO = "id";
//JSON array name
public static final String JSON_ARRAY = "marcas";
}
Please let me know if you need more information to help me in solving this problem. Thanks in advance!
The easier way to parse a JSON data in Android is using Gson. It is simple and easier to integrate with your code. You just need to add the following dependency in your build.gradle file.
dependencies {
implementation 'com.google.code.gson:gson:2.8.5'
}
Now in your code, you need to create the following class.
public class Car {
public String name;
public String fipe_name;
public Integer order;
public String key;
public Long id;
}
Now simply parse the JSON string you have like the following.
Gson gson = new Gson();
Car[] carList = gson.fromJson(jsonResponse, Cars[].class);
You will find the JSON parsed as an array of objects. Hope that helps.
I have a class which holds other objects in an ArrayList:
class Program {
#Expose
private List<BaseData> dataList;
}
And I have other classes:
class BaseData {
#Expose
String name;
}
class Data extends BaseData {
#Expose
String description;
}
class DataA extends Data{
#Expose
String a;
}
class DataB extends Data{
#Expose
String b;
}
When I would like to serialize it:
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
Log.d(TAG, gson.toJson(myProgram));
I can see only the keys which I have in BaseData. My list in my Program object contains DataA, DataB and Data objects too.
How can I fix this?
Update:
So my program work like this: it does stuff and fills the Program's list with data. Than I save it: I use Gson to turn the Program to a json string. I use Shared Preferences.
Than when I open up the app again, it loads the previously saved json string. I Log.d it, and everything is cool.
Than
I would like to create a Program object from that json.
Gson gson = new Gson();
instance = gson.fromJson(savedJson, Program.class);
And after I serialize it again with Gson happens what I wrote above. So it seems that it only creates BaseData objects from the json.
I found the Solution.
Btw. It feels like a bit "brute force" method.
Gson gson = new Gson();
JSONObject progJsonObj = new JSONObject(json);
progJsonObj.clearDataList();
JSONArray dataList= reader.getJSONArray("dataList");
Program program = gson.fromJson(progJsonObj.toString());
for (int i = 0; i < dataList.length(); i++) {
JSONObject blockData = blocksInProgram.getJSONObject(i);
// Added new class variable of the base class
String type = blockData.getString("dataType");
if (type.equals("data_a")) {
DataA d = gson.fromJson(blockData.toString(), DataA.class);
program.addData(d);
} else if (type.equals("data_b")){
DataB d = gson.fromJson(blockData.toString(), DataB.class);
program.addData(d);
}
}
I want to send the server an http request with this json (upper line)
and I want to get such a json and parse it to Java object (lower line)
I remember from last times, that a missing field in a collection that I want to deserialize
crashes the deserialization
(for a single deserialization, if the json has no such field - a default value is inserted)
Is there any way I can create a single Java class to represent both the request json and the two types on response json objects?
My try:
public class ConfigValue {
public String key;
public String defaultValue;
public String value;
}
Gson gson = new Gson();
Type collectionType = new TypeToken<Array<ConfigValue>>() {
}.getType();
ConfigValue[] configValues = (ConfigValue[]) gson
.fromJson(result, collectionType);
Neither of the two JSON strings in your image are directly a list (or array) of ConfigValue objects. They are in fact a JSON object, with one property configValues, which is a list of ConfigValue objects. You therefore need a wrapper class to deserialize them to:
public class ConfigValues {
public ConfigValue[] configValues;
}
public class ConfigValue {
public String key;
public String defaultValue;
public String value;
}
public static void main(String[] args) {
String firstJson = "{\"configValues\":[{\"key\":\"radiusMeters\",\"value\":\"200\"}]}";
String secondJson = "{\"configValues\":[{\"key\":\"redeemExpirationMins\",\"defaultValue\":\"300\"},{\"key\":\"radiusMeters\",\"value\":\"200\",\"defaultValue\":\"400\"}]}";
Gson gson = new Gson();
ConfigValues firstConfigValues = gson.fromJson(firstJson, ConfigValues.class);
ConfigValues secondConfigValues = gson.fromJson(secondJson, ConfigValues.class);
System.out.println(firstConfigValues);
System.out.println(secondConfigValues);
}
If you add toString methods to the two classes, the main method prints the following deserialized objects:
ConfigValues(configValues=[ConfigValue(key=radiusMeters, defaultValue=null, value=200)])
ConfigValues(configValues=[ConfigValue(key=redeemExpirationMins, defaultValue=300, value=null), ConfigValue(key=radiusMeters, defaultValue=400, value=200)])
You can see that any missing fields of ConfigValue are deserialized to null.