Here is my code:
try {
JSONObject json = (JSONObject) new JSONTokener(result).nextValue();
System.out.println(json);
JSONObject json2 = json.getJSONObject("data");
String test = json2.getString("headline");
System.out.println(test);
} catch (JSONException e) {
e.printStackTrace();
}
My String values start with the object data. So I am trying to get that object first and then capture the the object headline inside that.
My problem is, it is not taking the object data from the string.
Once I reach the line JSONObject json2 = json.getJSONObject("data");, it throws the exception. Please shed some light on this.
"data": [
{
"headline": "Close Update"
"docSource": "MIDNIGHTTRADER",
"source": "MTClosing",
"dateTime": "2015-10-23T16:42:46-05:00",
"link": "Markets/News",
"docKey": "1413-A1067083-1B14K77PVTUM1O7PCAFMI3SJO4",
},
The value for the key data is a JSON array containing one object, and not an object itself.
To get that object inside data, replace your line that throws an exception with the following:
JSONObject json2 = json.getJSONArray("data").get(0);
This gets the data array as a JSONArray object and then gets the 0th element, which is the object you want.
Your data "object", isn't actually an object, it's an array, notice the opening square bracket... I'm assuming in your actual code, it closes with one too.
"data": [{
"headline": "Close Update"
"docSource": "MIDNIGHTTRADER",
"source": "MTClosing",
"dateTime": "2015-10-23T16:42:46-05:00",
"link": "Markets/News",
"docKey": "1413-A1067083-1B14K77PVTUM1O7PCAFMI3SJO4",
}]
Try json.getJSONArray("data")[0] instead... or whatever index you need
try {
JSONObject json = (JSONObject) new JSONTokener(result).nextValue();
System.out.println(json);
JSONObject json2 = json.getJSONArray("data")[0];
String test = json2.getString("headline");
System.out.println(test);
}
catch (JSONException e) {
e.printStackTrace();
Your problem is based on the fact that your service returns and array instead of a single json object, so from here you can follow this suggestions to process directly from the JSONArray Can't access getJSONArray in java, or, at server side you can encapsulate your response array into another object like this (java example):
public class Data<T> {
private List<T> elements;
public ObjectSugetionsDTO(){
And build the response like this:
return new ResponseEntity<Data<YourInternalRepresentation>>(
new Data<YourInternalRepresentation>(yourMethodCallForTheArray()),
HttpStatus.OK);
I have found the second way to be better at keeping my API cleaner and more readable
EDIT: Better way
I whould also suggest the use of retrofit (http://square.github.io/retrofit/), by doing so, your service calls is resumed to (Example of calling and API that retrieves a list of users):
public class UserService {
public static IUserService getUserService() {
return RestAdapterManager.createService(IUserService.class );
}
public interface IUserService{
#GET("/api/users")
public void getAllUsers(Callback<List<User>> callback);
}
}
and the service call itself
UserService.getUserService().getAllUsers(new Callback<List<User>>() {
#Override
public void success(List<User> users, Response response) {
Log.d("Exito! " , "" + users.size());
}
#Override
public void failure(RetrofitError error) {
Log.d("Fail!", error.getUrl());
}
});
The simple inicialization of the connection object
public static <S> S createService(Class<S> serviceClass, String username, String password) {
RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(API_BASE_URL);//Your api base url
RestAdapter adapter = builder.setLogLevel(RestAdapter.LogLevel.FULL).build(); //change the logging level if you need to, full is TOO verbose
return adapter.create(serviceClass);
}
Related
I am creating a REST API using Spring Boot and using org.json for parsing data retrieved from another different service. From this service I am getting JSON data like in following format
{
"my_data":[
{
"user_data":{
"first_name":"FirstTest1",
"last_name":"LastTest1",
"age":"25"
}
},
{
"user_data":{
"first_name":"FirstTest2",
"last_name":"LastTest2",
"age":"35"
}
},{
"user_data":{
"first_name":"FirstTest3",
"last_name":"LastTest3",
"age":"45"
}
}
],
"count":10,
"is_safe":false
}
and I have to transform received data to the following JSON
[
{
"user_data":{
"first_name":"FirstTest1",
"last_name":"LastTest1",
"age":"25"
}
},
{
"user_data":{
"first_name":"FirstTest2",
"last_name":"LastTest2",
"age":"35"
}
},{
"user_data":{
"first_name":"FirstTest3",
"last_name":"LastTest3",
"age":"45"
}
}
]
I know I can use a POJO to map the data and send it (already doing this) but here the issue is that the data received from another service is not fixed e.g. it may or may mot have "first_name" or may have a different field like "country". So, in this situation I can not make POJO beforehand.
After going through some online resources I made some changes and my POST Controller method looks like this.
#PostMapping(path = "/searchusersdata")
public RETURN_SOMETHING searchUsersData(#RequestBody Map<String, String> searchData) {
List<JSONObject> finalDataCollection = new ArrayList<JSONObject>();
//Making some REST API CALL TO GET 'response' using 'searchData'
String someResponse = response.getBody();
JSONObject object = null;
try {
object = new JSONObject(someResponse);
} catch (JSONException e) {
e.printStackTrace();
}
String my_data= object.get("my_data").toString();
JSONArray intermediateJA = null;
intermediateJA = new JSONArray (my_data);
for(int i = 0; i < intermediateJA.length(); i++) {
JSONObject item = intermediateJA.getJSONObject(i);
if (item.keySet().contains("user_data"))
{
Object value = item.get("user_data");
finalDataCollection.add(new JSONObject(value));
}
}
//WHAT TO RESTURN HERE
}
Now, I don't know what to return hare. For a single JSONObject we can use return new ResponseEntity<>(return_data.toMap(), HttpStatus.OK); but for a collection I don't know. I am open to suggestion if I have to do it in entirely different way. I also know that with gson or jackson it might be easier but I have to use org.json.
instead of List , use JsonArray and use ResponseEntity to return it.
Example
JSONArray jsonArray = new JSONArray();
JSONObject jsonObject = new JSONObject();
jsonArray.put(jsonObject);
return new ResponseEntity( jsonArray.toString(), HttpStatus.OK);
Hi I'm trying to send a PUT request using Retrofit that uses $addToSet to my Mlab Server. I can do this using Postman but I'm having trouble doing it using Retrofit.
The collection looks like:
[
{
"_id": {
"$oid": "5abe74bac2ef1603f4045686"
},
"email": "test#gmail.com",
"completedWalks": [
"South Leinster Way"
],
"favWalks": []
}
]
The post man request has the API key, Query, and then $addToSet is passed in the body as so.
And the response is:
I'm trying to do it like this in android.
Retrofit:
#PUT("databases/walks/collections/user")
Call<Update> addCompleted (#Query("apiKey") String apiKey,#Query("q") String Email, #Body Update Query);
My model:
public class Update {
#SerializedName("n")
private String n;
public String getN() {
return n;
}
public Update(String n) {
this.n = n;
}
}
Creating the update object:
String updateComplete = String.format("'$addToSet': {'completedWalks': '%s'}} ", TrailName);
final String query =String.format("{'email': '%s'}",email) ;
final Update queryComplete = new Update(updateComplete);
And the Request:
Call<Update> completeCall = apiService.addCompleted(mlabAPi, query, queryComplete);
completeCall.enqueue(new Callback<Update>() {
#Override
public void onResponse(Call<Update> call, Response<Update> response) {
Toast.makeText(getApplicationContext(),"Walk marked as Complete", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<Update> call, Throwable t) {
Log.e(TAG, t.getMessage());
}
});
But this only overwrites whats in the collection and I have:
[
{
"_id": {
"$oid": "5abe74bac2ef1603f4045686"
},
"n": "'$addToSet': {'completedWalks': 'Kerry Head Cycleway'}} "
}
]
Does anyone know where I'm going wrong, should I not be passing $addToSet as a model because it seems to be overwriting all, how do I pass it then?
Thank You.
#Body Update Query -- Retrofit will encode the object passed to this as JSON (assuming you are using the Gson converter, which it appears you are). That is where this "n": "'$addToSet': {'completedWalks': 'Kerry Head Cycleway'}} " is coming from. You need to structure you Java Object the same as your JSON object for gson to serialize it correctly.
I am not familiar with the mlab api, but from your postman, it looks like you want a request body something like this --
public class UpdateRequest {
#SerializedName("$addToSet")
Map<String, String> addToSet = new HashMap();
}
Update your interface to send this object as the body --
#PUT("databases/walks/collections/user")
Call<Update> addCompleted (#Query("apiKey") String apiKey,#Query("q") String Email, #Body UpdateRequest Query);
And create the request body --
UpdateRequest requestBody = new UpdateRequest();
requestBody.addToSet.put("completedWalks", Trailname);
and create the call --
Call<Update> completeCall = apiService.addCompleted(mlabAPi, query, requestBody);
For further debugging, you can see what is actually being sent in your logcat by adding HttpLoggingInterceptor to your retrofit instance.
See here for setup. Then you can compare what your app is sending vs postman and see where things might be going sideways.
I am working on an Android app and one of its functionnalities is to know when a streamer is streaming by using Twitch API.
When a streamer is streaming, if I connect to https://api.twitch.tv/kraken/streams/ I get a String which I use to build a JSON object like that :
{
"_links":{
"self":"https://api.twitch.tv/kraken/streams/srkevo1",
"channel":"https://api.twitch.tv/kraken/channels/srkevo1"
},
"stream":{
"_id":15361851552,
"game":"Super Smash Bros. for Wii U",
"viewers":42613,
"created_at":"2015-07-18T15:07:59Z",
"video_height":720,
"average_fps":59.319897084,
"_links":{
"self":"https://api.twitch.tv/kraken/streams/srkevo1"
},
"preview":{
"small":"http://static-cdn.jtvnw.net/previews-ttv/live_user_srkevo1-80x45.jpg",
"medium":"http://static-cdn.jtvnw.net/previews-ttv/live_user_srkevo1-320x180.jpg",
"large":"http://static-cdn.jtvnw.net/previews-ttv/live_user_srkevo1-640x360.jpg",
"template":"http://static-cdn.jtvnw.net/previews-ttv/live_user_srkevo1-{width}x{height}.jpg"
},
"channel":{
"_links":{
"self":"https://api.twitch.tv/kraken/channels/srkevo1",
"follows":"https://api.twitch.tv/kraken/channels/srkevo1/follows",
"commercial":"https://api.twitch.tv/kraken/channels/srkevo1/commercial",
"stream_key":"https://api.twitch.tv/kraken/channels/srkevo1/stream_key",
"chat":"https://api.twitch.tv/kraken/chat/srkevo1",
"features":"https://api.twitch.tv/kraken/channels/srkevo1/features",
"subscriptions":"https://api.twitch.tv/kraken/channels/srkevo1/subscriptions",
"editors":"https://api.twitch.tv/kraken/channels/srkevo1/editors",
"videos":"https://api.twitch.tv/kraken/channels/srkevo1/videos",
"teams":"https://api.twitch.tv/kraken/channels/srkevo1/teams"
},
"background":null,
"banner":null,
"broadcaster_language":"en",
"display_name":"srkevo1",
"game":"Super Smash Bros. for Wii U",
"logo":"http://static-cdn.jtvnw.net/jtv_user_pictures/srkevo1-profile_image-e46c53476d9b74c7-300x300.png",
"mature":null,
"status":"Evolution 2015 - Main Stage (July 17-19) all brackets http://evo2015.s3.amazonaws.com/brackets/index.html",
"partner":true,
"url":"http://www.twitch.tv/srkevo1",
"video_banner":"http://static-cdn.jtvnw.net/jtv_user_pictures/srkevo1-channel_offline_image-ee2fc39d6ebb7735-640x360.jpeg",
"_id":30917811,
"name":"srkevo1",
"created_at":"2012-05-30T16:57:11Z",
"updated_at":"2015-07-18T16:18:40Z",
"delay":0,
"followers":82134,
"profile_banner":null,
"profile_banner_background_color":null,
"views":20938144,
"language":"en"
}
}
}
This is how I get the JSON Object :
public class GetStreamStatus extends AsyncTask<Void,Void,String> {
#Override
protected String doInBackground(Void... params) {
String res = bibixChannel.getJson("streams");
return res;
}
#Override
protected void onPostExecute(String s) {
channelStatusString = s;
channelStatusObject = bibixChannel.buildJSON(s);
}
}
The buildJson() method is simply :
protected JSONObject buildJSON(String jsonRaw){
JSONObject json = null;
try{
json = new JSONObject(jsonRaw);
}catch (Exception e){
e.printStackTrace();
}
return json;
}
But after, to know if the streamer is streaming, a part of the JSON string is nulled like that :
If the streamer is streaming, you will get the fist JSON I wrote on the top of that post, else you will get something like that :
{
"_links":{
"self":"https://api.twitch.tv/kraken/streams/bibixhd",
"channel":"https://api.twitch.tv/kraken/channels/bibixhd"
},
"stream":null
}
What I want to do is getting the "stream" part in another instance variable to either recover infos about the stream or to display an offline message.
What i have got from your OP is that the channelStatusObject return you the JSONObject which contains stream key. Now what you want to check is that whether this stream is null or not. So you could do something like :-
protected JSONObject checkStream(JSONObject parentObject){
JSONObject json = (JSONObject) parentObject.get("stream");
return json; // will return null if stream is null else stream JSONObject
}
You can use this method & check its return value to see if stream is null or not.
I want to make a post request with volley to a REST API.
Therefore, I create a JSONObject and put a JSON String generated from a class in it.
JSONObject jsonObject = new JSONObject();
String json = gson.toJson(MyClazz);
try {
jsonObject.put(PARAM, json);
}
catch (JSONException e1) {
e1.printStackTrace();
}
The problem is that the correct calculated JSON String gets escaped and can't be recognized on the back end.
So toJson() gives something like:
{
"device_identifier":"324234234",
"name":"NameMe",
"list":[
{"prop":"A","prop2":-10},
{"prop":"B","prop2":-12}
]
}
The jsonObject's output is like
{
"PARAM":{
\"device_identifier\":\"324234234\",
\"name\":\"NameMe\",
\"list\":[
{\"prop\":\"A\",\"prop2\":-10},
{\"prop\":\"B\","\prop2\":-12}
]
}
}
I need the PARAM for the JSON structure so I can't give it directly to the REST-API. Any ideas how I can avoid the additional escaping?
You could wrap your MyClazz object with a simple wrapper object, and then pass that wrapped object to Gson's toJson method.
Given this class based on your example JSON,
public class MyClazz {
public String device_identifier;
public String name;
public List<Prop> list;
public class Prop {
public String prop;
public Integer prop2;
}
}
here's a possible wrapper implementation. Note the use of com.google.gson.annotations.SerializedName which tells Gson to use the PARAM key in the JSON representation.
public class MyClazzWrapper {
public MyClazzWrapper(MyClazz myClazz) {
this.myClazz = myClazz;
}
#SerializedName("PARAM")
private MyClazz myClazz;
}
And here's an example using it:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
MyClazz myClazz = gson.fromJson("{\"device_identifier\":\"324234234\",\"name\":\"NameMe\",\"list\":[{\"prop\":\"A\",\"prop2\":-10},{\"prop\":\"B\",\"prop2\":-12}]}", MyClazz.class);
MyClazzWrapper wrapped = new MyClazzWrapper(myClazz);
System.out.println(gson.toJson(wrapped));
The above will print:
{
"PARAM": {
"device_identifier": "324234234",
"name": "NameMe",
"list": [
{
"prop": "A",
"prop2": -10
},
{
"prop": "B",
"prop2": -12
}
]
}
}
I am currently using Play v1.2.3. I have an endpoint to which I want to send a json object which will be deserialized into a Java object. So, I have something that looks like this:
public class UserController extends Controller {
public static class FullName {
public String first;
public String last;
}
public static void putName( FullName name ) { ... }
}
##### routes
PUT /user/name UserController.putName
With that in place, I would hope to call the endpoint with the given javascript:
$.ajax({
type: "PUT",
data: { first: "Michael", last: "Bailey" },
url: "/user/name"
});
Unfortunately, with the above setup, it seems that play is not wanting to send the entire data object, but is instead attempting to populate two parameters (first and last). Is there a way to define the endpoint to consume the complete body directly, or does it have to be done by hand?
To cast the entire input body into a Model class:
public static void create(JsonObject body) {
CaseFolder caseFolder = new Gson().fromJson(body, CaseFolder.class);
caseFolder.user = getConnectedUser();
if(caseFolder.validateAndSave()) {
renderJSON(
new JSONSerializer()
.exclude("*.class")
.exclude("user")
.serialize(caseFolder));
} else
error();
}
Also, the above code takes the resulting Model object and serializes it back out to JSON as the response body.
If you want to just access certain fields within the JSON request, you can use:
public static void update(JsonObject body) {
try {
Long id = (long) body.get("id").getAsInt();
CaseFolder cf = CaseFolder.loadAndVerifyOwner(getConnectedUser(), id);
cf.number = body.get("number").getAsString();
cf.description = body.get("description").getAsString();
if(cf.validateAndSave())
ok();
else
error();
}
catch (NullIdException e) {error();}
catch (NotFoundException e) {notFound();}
catch (NotOwnerException e) {forbidden();}
catch (Exception e) {e.printStackTrace(); error();}
}
Play's action method parameter binding mechanism does not accept JSON. You need to bind it manually. In your example, the code could be something like:
public static void putName( String data ) {
FullName fname = new Gson().fromJSON(data, FullName.class);
...
}
Note, Gson is provided with play!framework distribution, so you are free to use it
With your settings play is expecting params with names "name.first" and "name.last" and you are sending "first" and "last". Try with this ajax post
$.ajax({
type: "PUT",
data: {
name: {
first: "Michael",
last: "Bailey"
}
},
url: "/user/name"
});