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));
}
Related
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);
}
}
I have JSON response which looks like that:
{
"response":[
"Some number (for example 8091)",
{
"Bunch of primitives inside the first JSONObject"
},
{
"Bunch of primitives inside the second JSONObject"
},
{
"Bunch of primitives inside the third JSONObject"
},
... (and so on)
]
}
So it's an array with first integer element and other elements are JSONObject.
I don't need integer element to be parsed. So how do I handle it using GSON?
I would solve this problem by creating a custom JsonDeserializer and registering it to your Gson instance before parsing. This custom deserializer would be set up to handle both ints and real objects.
First you need to build up a series of model objects to represent the data. Here's a template for what that might look like:
private static class TopLevel {
#SerializedName("response")
private final List<ResponseElement> elements;
private TopLevel() {
this.elements = null;
}
}
private static class ResponseInteger implements ResponseElement {
private final int value;
public ResponseInteger(int value) {
this.value = value;
}
}
private static class ResponseObject implements ResponseElement {
#SerializedName("id")
private final String id;
#SerializedName("text")
private final String text;
private ResponseObject() {
this.id = null;
this.text = null;
}
}
private interface ResponseElement {
// marker interface
}
TopLevel and ResponseObject have private constructors because they are going to let Gson set their fields using reflection, while ResponseInteger has a public constructor because we're going to manually invoke it from our custom deserializer.
Obviously you will have to fill out ResponseObject with the rest of its fields.
The deserializer is relatively simple. The json you posted contains only two kinds of elements, and we'll leverage this. Each time the deserializer is invoked, it checks whether the element is a primitive, and returns a ResponseInteger if so (or a ResponseObject if not).
private static class ResponseElementDeserializer implements JsonDeserializer<ResponseElement> {
#Override
public ResponseElement deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json.isJsonPrimitive()) {
return new ResponseInteger(json.getAsInt());
}
else {
return context.deserialize(json, ResponseObject.class);
}
}
}
To use this deserializer, you'll have to register it with Gson using the GsonBuilder object.
private static Gson getGson() {
return new GsonBuilder()
.registerTypeAdapter(ResponseElement.class, new ResponseElementDeserializer())
.create();
}
And that's it. Now you can use this Gson object to easily parse TopLevel objects!
public void parseJson() {
TopLevel t = getGson().fromJson(json, TopLevel.class);
for (ResponseElement element : t.elements) {
System.out.println(element);
}
}
8061
[450602: Поздравляем!]
[451700: С реакцией чата и рассуждениями Папани после рипа..]
[451578: Помним...Любим...Скорбим...<br>2107 забирает лучших]
[451371: Земля тебе пухом братишка]
[451332: Доигрался, минус 900 экзов<br><br>R I P]
[451269: ]
[451242: https://www.twitch.tv/arthas подрубка<br><br>evilpapech.ru - скидка 30% на футболки!]
[451217: ]
[451181: или так це жерстко?]
[451108: ]
I used these toString() methods, which I omitted above for brevity:
#Override
public String toString() {
return Integer.toString(value);
}
#Override
public String toString() {
return "[" + id + ": " + text + "]";
}
Try this
Gson gson = new Gson();
// Reading from a file.
Example example = gson.fromJson(new FileReader("D:\\content.json"), Example.class);
POJO
package com.example;
public class Example {
private List<Integer> response = null;
public List<Integer> getResponse() {
return response;
}
public void setResponse(List<Integer> response) {
this.response = response;
}
}
Basically this structure is the wrong format for JSON data.
You need to remove the number, or put this number as a field in the same object like the one below (call ObjectA) and consider this is an array of ObjectA.
Then everything should work well. Try the code below:
public class Response {
#SerializedName("response")
#Expose
public List<ObjectA> objectA = null;
}
public class ObjectA {
#SerializedName("value")
#Expose
public Integer value;
#SerializedName("description")
#Expose
public String description;
}
Response response = new Gson().fromJson(responseString, Response.class);
Please use below ValueObject format which doesn't parse first integer element
public class ResponseVO {
public List<Response> response = new ArrayList();
public class Response {
public final long id;
public final long from_id;
...
}
}
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.
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.
How can I parse this JSON string to create collection object in servlet
{"title":["1","2"],"amount":["1","3"]}
inner class in my servlet
public class Data {
private List<String> title;
private List<String> amount;
//getters and setters
}
parsing json
Gson gson = new Gson();
String param=request.getParameter("info");
Data data = gson.fromJson(param, Data.class);
List<String> a=data.getTitle();
if(a==null){p("a null");}else{p("a not null");} //here a is null, prints "a null"
here is the jsfiddle of how I am creating the json string http://jsfiddle.net/testtracker/XDNLp/
client side in form submit function
var dataString=JSON.stringify($(this).serializeObject());
$.ajax({
type: "POST",
url: URL,
data: {"info":JSON.stringify($(this).serializeObject())},
success: function(data){
}
});
This is what I have till now. am I on correct way? what next should I do to System.print them?
When I am unable to solve something, I write the smallest possible program to verify my understanding is correct. In your case, I came up with this:
import java.util.List;
import com.google.gson.Gson;
public class GsonTest {
public static class Data {
private List<String> title;
public List<String> getTitle() {return title;}
public Data() {}
}
public static void main (String [] args) {
Gson gson = new Gson();
Data data = gson.fromJson("{\"title\":[\"1\",\"2\"]}", Data.class);
System.out.println(data.getTitle());
}
}
Compiled, and ran, and it outputs:
["1", "2"]
So I still believe that the input that the servlet receives, is not correct (or you have not provided an accurate description of your existing code). Please compare the example above, against your real code.
try
public class Data {
private ArrayList<String> title;
private ArrayList<String> amount;
//getters and setters
}
List is a abstract class (So GSON doesn't know how to create it)