Using an API, I am calling for an options chain with lots of different data. It looks like this:
```
[
putCall=PUT
symbol=AAPL_012023P100
description=AAPL Jan 20 2023 100 Put
exchangeName=OPR
bidPrice=10.05
askPrice=10.3
lastPrice=10.15
bidAskSize=78X102
markPrice=10.18
bidSize=78
askSize=102
lastSize=0
highPrice=10.15
lowPrice=9.85
openPrice=0.0
closePrice=9.98
totalVolume=334
quoteTimeInLong=1612904400035
tradeTimeInLong=1612903831902
netChange=0.17
volatility=37.645
delta=-0.195
gamma=0.004
theta=-0.014
vega=0.524
rho=-0.676
timeValue=10.15
openInterest=7941
isInTheMoney=false
theoreticalOptionValue=10.175
theoreticalVolatility=29.0
isMini=false
isNonStandard=false
optionDeliverablesList=<null>
strikePrice=100.0
expirationDate=1674248400000
expirationType=R
multiplier=100.0
settlementType=
deliverableNote=
isIndexOption=<null>
percentChange=1.75
markChange=0.2
markPercentChange=2.01
otherFields={lastTradingDay=1674262800000, daysToExpiration=709, tradeDate=null}
]], ```
This is one part of the many it returns. I need all of them. So, using Jackson I understand how to convert this to JSON using something like this:
```
ObjectMapper mapper = new ObjectMapper();
String data = eq.toString();
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(data);
Now, this cleans it up some, but now for what I actually need.. I need 3 things out of all this. I would like to create an object for each one of these things with the following fields: openInterest, totalVolume, and description.
I have tried searching for this, but I can't figure it out for when you have multiple values. What I posted above is just one of many entries that the API returns me. I would really appreciate some help :)
this:
[
putCall=PUT
symbol=AAPL_012023P100
/*bla di bla whatever*/
markPercentChange=2.01
otherFields={lastTradingDay=1674262800000, daysToExpiration=709, tradeDate=null}
]], ``
I'ma call this leSRC
JSONObject zTHING = new JSONObject();
zTHING.put("openInterest", leSRC.getJSONObject("openInterest"));
zTHING.put("totalVolume", leSRC.getJSONObject("totalVolume"));
zTHING.put("description", leSRC.getJSONObject("description"));
Your zTHING object should have those 3 KvP's set up correctly.
Related
I am building tests in SoapUI. I have a very large response (>3500 duties). For that response I need to build a request and execute that request. Currently the code (Java) works, but I would like to optimize the code.
For each Duty I build a request to get additional employee data and execute it using a for next loop. Below is an example of the large XML response that I get.
<DUTIES>
<DUTY>
<EMPNO>1</EMPNO>
<LOCATION>AMS</BASE_STATION>
<ACTUALTIME>2019-02-20T06:00:00</ACTUALTIME>
<POSITIONING_CODE>1</POSITIONING_CODE>
</DUTY>
<DUTY>
<EMPNO>2</EMPNO>
<LOCATION>RTM</BASE_STATION>
<ACTUALTIME>2019-02-20T06:00:00</ACTUALTIME>
<POSITIONING_CODE/>
</DUTY>
<DUTY>
<EMPNO>1</EMPNO>
<LOCATION>AMS</BASE_STATION>
<ACTUALTIME>2019-02-21T06:00:00</ACTUALTIME>
<POSITIONING_CODE>1</POSITIONING_CODE>
</DUTY>
</DUTIES>
As you can see from the sample the same employee is multiple times in the response, so currently I am calling the request multiple time for the same employee. I would like to optimize this.
In SoapUI I can use the statement:
String[] emps = resp.getNodeValues("/Duties/Duty/string(EMPNO)");
String[] locs = resp.getNodeValues("/Duties/Duty/string(LOCATION)");
String[] tims = resp.getNodeValues("/Duties/Duty/string(ACTUALTIME)");
Then I would like to sort the arrays on emps and only build a request to get additional employee data when the employee changes. This will make the code much faster.
Now my questions:
What is the best way to do this? Work with multidimensional array and sort them? Or is there a better way of doing this?
Thanks in advance,
Said
I would create an instance of java.util.HashMap<String,String> or java.util.HashMap<Long,String> depending on which datatype is returned, when you retrive the empno.
Just blindly do a map.put(empno,null) for each duty element, and you will only have each employee in the hashmap once afterwards, as each additional addition of the same key will overwrite the existing.
After that, simply
for (String key : map.keySet()) {
// do your stuff
}
As I see it, you really don't need to sort anything to get there.
I am writing an API in Java using Spark (irrelevant to my problem but that gives a bit of context).
I have the following JSON (exactly as it is returned by my back-end):
{"CfgCampaign":{"callingLists":{"CfgCallingListInfo":{"callingListDBID":{"value":126},"share":{"value":10},"isActive":{"value":2}}},"xmlns":"http://schemas.genesyslab.com/Protocols/Configuration/ConfServer/2005/","DBID":{"value":101},"name":{"value":"WI_Camp_1"},"state":{"value":1},"campaignGroups":{"CfgCampaignGroupInfo":[{"groupType":{"value":5},"dialerDBID":{"value":0},"optMethodValue":{"value":80},"origDNDBID":{"value":0},"numOfChannels":{"value":10},"groupDBID":{"value":826},"isActive":{"value":2},"scriptDBID":{"value":0},"trunkGroupDNDBID":{"value":0},"operationMode":{"value":1},"dialMode":{"value":2},"statServerDBID":{"value":176},"optRecBuffSize":{"value":6},"optMethod":{"value":1},"minRecBuffSize":{"value":4}},{"groupType":{"value":5},"dialerDBID":{"value":0},"optMethodValue":{"value":80},"origDNDBID":{"value":0},"numOfChannels":{"value":10},"groupDBID":{"value":827},"isActive":{"value":2},"scriptDBID":{"value":0},"trunkGroupDNDBID":{"value":0},"operationMode":{"value":1},"dialMode":{"value":2},"statServerDBID":{"value":176},"optRecBuffSize":{"value":6},"optMethod":{"value":1},"minRecBuffSize":{"value":4}}]},"scriptDBID":{"value":0},"tenantDBID":{"value":101}}}
It seems to be valid, as per https://jsonlint.com/
I store it in my code as a JSONObject (so basically, the above is the result of a toString()).
However, when I try to extract "campaignGroups" in a JSONArray, I get:
org.json.JSONException: JSONObject["campaignGroups"] not found.
I actually get this error even by just trying to get any key for that matter, e.g. calling get("DBID") will return the same error.
I am a bit confused as to what is going on here, and any help would be appreciated.
edit: Because it is only obvious from the exception, I am using json.org
Thanks !
I believe the error you're experiencing is due to the outer JSON object, "CfgCampaign", that contains the rest of your data. Some sample code for how to get around this using the org.json library is shown below:
// Loads the JSON (assuming you provide it as a string).
JSONObject x = new JSONObject(...);
// Gets and stores a reference to the outer object.
JSONObject y = x.getJSONObject("CfgCampaign");
// Now you can access any of the nested fields as follows.
JSONObject z = y.getJSONObject("campaignGroups");
Calling toString() on that object should return a string that looks something like "[Object Object]", if the toString method has to be called on it, then you'll also need to call JSON.parse(your_object_here) on it to access properties on it.
Also it looks like you'll need to be looking for your_object_name.CfgCampaign.campaignGroups or your_object_name["CfgCampaign"]["campaignGroups", but it's hard to tell without the code you're using to access campaignGroups.
If you set something like
const obj = {"CfgCampaign":{"callingLists":{"CfgCallingListInfo":{"callingListDBID":{"value":126},"share":{"value":10},"isActive":{"value":2}}},"xmlns":"http://schemas.genesyslab.com/Protocols/Configuration/ConfServer/2005/","DBID":{"value":101},"name":{"value":"WI_Camp_1"},"state":{"value":1},"campaignGroups":{"CfgCampaignGroupInfo":[{"groupType":{"value":5},"dialerDBID":{"value":0},"optMethodValue":{"value":80},"origDNDBID":{"value":0},"numOfChannels":{"value":10},"groupDBID":{"value":826},"isActive":{"value":2},"scriptDBID":{"value":0},"trunkGroupDNDBID":{"value":0},"operationMode":{"value":1},"dialMode":{"value":2},"statServerDBID":{"value":176},"optRecBuffSize":{"value":6},"optMethod":{"value":1},"minRecBuffSize":{"value":4}},{"groupType":{"value":5},"dialerDBID":{"value":0},"optMethodValue":{"value":80},"origDNDBID":{"value":0},"numOfChannels":{"value":10},"groupDBID":{"value":827},"isActive":{"value":2},"scriptDBID":{"value":0},"trunkGroupDNDBID":{"value":0},"operationMode":{"value":1},"dialMode":{"value":2},"statServerDBID":{"value":176},"optRecBuffSize":{"value":6},"optMethod":{"value":1},"minRecBuffSize":{"value":4}}]},"scriptDBID":{"value":0},"tenantDBID":{"value":101}}}
then to get the array in campaignGroups you'll need something to look like:
obj.CfgCampaign.campaignGroups
First I know my title is bad as I didn't come up with better, I'm opened to suggestion.
I'm using retrofit to get data from an api of this kind : #GET("users/{userid}")
It works fine and I'm happy with it, the problem is when I call the same api with #POST("users/widget") with a list of ids. I have the following answer :
{
"long_hash_id": {
"_id": "long_hash_id"
.......
},
"long_hash_id": {
"_id": "long_hash_id",
.....
},
........
}
the "long_hash_id" is typicaly "525558cf8ecd651095af7954"
it correspond to the id of the user attached to it.
When I didn't use retrofit, I used Gson in stream mode to get each user one by one. But I don't know how to tell retrofit.
Hope I'm clear and
Thank you in advance.
----------- Solution :
I made my interface this way :
#FormUrlEncoded
#POST(AppConstants.ROUTE_USER_GROUP)
Call<Map<String,User>> getUsers( #Field("ids") List<String> param, #QueryMap Map<String,String> options);
and I simply gave my ArrayList of ids. Thank you very much
Gson is able to deal with JSON objects with variable keys like the one you posted. What you have to do, in this case, is to declare a Map<String, ModelClass>, where ModelClass is the content of the JSONObject you want to represent
I have data in a Map object and I want to print it in a json format. I tried using DefaultPrettyPrinter
mapper.writerWithDefaultPrettyPrinter().writeValue(filePath, mapObject);
but the format is not what I expected. I am getting output like this:
{
"arrVals" : ["value-1","value-2"]
}
I want output like this:
{
"arrVals" : [
"value-1",
"value-2"
]
}
You need indentation before Array Values. You can use indentArraysWith method to set the Lf2SpacesIdenter object which will basically add a line feed followed by 2 spaces.
This might solve your problem.
DefaultPrettyPrinter pp = new DefaultPrettyPrinter();
pp.indentArraysWith(new Lf2SpacesIndenter());
mapper.writer(pp).writeValue(filePath, mapObject);
data: [
{
type: "earnings"
info: {
earnings: 45.6
dividends: 4052.94
gains: 0
expenses: 3935.24
shares_bought: 0
shares_bought_user_count: 0
shares_sold: 0
shares_sold_user_count: 0
}
created: "2011-07-04 11:46:17"
}
{
type: "mentions"
info: [
{
type_id: "twitter"
mentioner_ticker: "LOANS"
mentioner_full_name: "ERICK STROBEL"
}
]
created: "2011-06-10 23:03:02"
}
]
Here's my problem : like you can see the "info" is different in each of one, one is a json object, and one is a json array, i usually choose Gson to take the data, but with Gson we can't do this kind of thing . How can i make it work ?
If you want to use Gson, then to handle the issue where the same JSON element value is sometimes an array and sometimes an object, custom deserialization processing is necessary. I posted an example of this in the Parsing JSON with GSON, object sometimes contains list sometimes contains object post.
If the "info" element object has different elements based on type, and so you want polymorphic deserialization behavior to deserialize to the correct type of object, with Gson you'll also need to implement custom deserialization processing. How to do that has been covered in other StackOverflow.com posts. I posted a link to four different such questions and answers (some with code examples) in the Can I instantiate a superclass and have a particular subclass be instantiated based on the parameters supplied thread. In this thread, the particular structure of the JSON objects to deserialize varies from the examples I just linked, because the element to indicate the type is external of the object to be deserialized, but if you can understand the other examples, then handling the problem here should be easy.
Both key and value have to be within quotes, and you need to separate definitions with commas:
{
"key0": "value0",
"key1": "value1",
"key2": [ "value2_0", "value2_1" ]
}
That should do the trick!
The info object should be of the same type with every type.
So check the type first. Pseudocode:
if (data.get('type').equals("mentions") {
json_arr = data.get('info');
}
else if (data.get('type').equals("earnings") {
json_obj = data.get('info');
}
I'm not sure that helps, cause I'm not sure I understand the question.
Use simply org.json classes that are available in android: http://developer.android.com/reference/org/json/package-summary.html
You will get a dynamic structure that you will be able to traverse, without the limitations of strong typing.....
This is not a "usual" way of doing things in Java (where strong typing is default) but IMHO in many situations even in Java it is ok to do some dynamic processing. Flexibility is better but price to pay is lack of compile-time type verification... Which in many cases is ok.
If changing libraries is an option you could have a look at Jackson, its Simple Data Binding mode should allow you to deserialize an object like you describe about. A part of the doc that is probably quite important is this, your example would already need JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES to work...
Clarification for Bruce: true, in Jackson's Full Data Binding mode, but not in Simple Data Binding mode. This is simple data binding:
public static void main(String[] args) throws IOException {
File src = new File("test.json");
ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonParser.Feature. ALLOW_UNQUOTED_FIELD_NAMES, true);
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS,true);
Object root = mapper.readValue(src, Object.class);
Map<?,?> rootAsMap = mapper.readValue(src, Map.class);
System.out.println(rootAsMap);
}
which with OP's sightly corrected sample JSON data gives:
{data=[{type=earnings, info={earnings=45.6, dividends=4052.94, gains=0,
expenses=3935.24, shares_bought=0, shares_bought_user_count=0, shares_sold=0,
shares_sold_user_count=0}, created=2011-07-04 11:46:17}, {type=mentions,
info=[{type_id=twitter, mentioner_ticker=LOANS, mentioner_full_name=ERICK STROBEL}],
created=2011-06-10 23:03:02}]}
OK, some hand-coding needed to wire up this Map to the original data, but quite often less is more and such mapping code, being dead simple has the advantage of being very easy to read/maintain later on.