This question already has answers here:
How to parse JSON Array (Not Json Object) in Android
(11 answers)
Closed 3 years ago.
My app fetches JSON response from server. The response string has multiple rows and columns. I need to print this in java.
Here is my JSON response :
[
{
"name": "name2",
"id": "99",
"email": "ad#e.com"
},
{
"name": "zca",
"id": "96",
"email": "as2c2#d.d",
}
]
this is java part :
OkHttpClient client = new OkHttpClient();
String url = ServerConstants.BROWSE_URL;
//String url = "https://reqres.in/api/users?page=2";
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback()
{
#Override
public void onFailure(Call call, IOException e)
{
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException
{
if (response.isSuccessful())
{
final String myResponse = response.body().string();
//System.out.println(Arrays.asList(new BundleFunctions().MakeArrayListFormJSON(myResponse)));
bundle = new BundleFunctions().MakeBundleFromJSON(myResponse);
//System.out.println("this is size ------- "+bundle.size());
//System.out.println("this is response ------ "+myResponse);
Browse.this.runOnUiThread(new Runnable()
{
#Override
public void run()
{
tv.setText(myResponse);
Set<String> keys = bundle.keySet();
for(String key : keys)
{
Object o = bundle.get(key);
}
}
});
}
}
});
I need a print on each person like this in java :
(Person number is according to array index FCFS)
Person 1 - Name : name2 , id : 99 , email : ad#e.com
Person 2 - Name : zca , id : 96 , email : as2c2#d.d
Please show me the simplest way to do this
JSON is really clear, which is Array of Objects in your case Person object, create Person POJO class
Person
public class Person {
private String name;
private String id;
private String email;
// getters and setters
}
Parse the above json to List<Person> and print each Person as you like them
Your example of JSON doesn't looks multi dimensional array. It's an array with bunch of objects into it. If this is for java, why not use jackson or GSon or library like that to obtain object in an array list! All you have to define is a POJO object with matching variable names with getters and setters.
Related
I am making an application in Android Studio and I want to consume API for cooking recipes, I have the following response from the API that I am consuming with Android Studio and Java:
API Response
"q" : "pollo",
"from" : 0,
"to" : 10,
"params" : {
"sane" : [ ],
"q" : [ "pollo" ],
"app_id" : [ "02" ],
"app_key" : [ "\n66b" ]
},
"more" : true,
"count" : 1000,
"hits" : [ {
"recipe" : {
"uri" : "http://www.edamam.com/ontologies/edamam.owl#recipe_d56f75c72ab67a45174441af1efe4473",
"label" : "Pollo con Crema a las Hierbas",
"image" : "http://cdn.kiwilimon.com/recetaimagen/23127/thumb120x90-15802.jpg",
"source" : "KiwiLimon",
"url" : "http://www.kiwilimon.com/receta/carnes-y-aves/pollo-con-crema-a-las-hierbas",
"shareAs" : "http://www.edamam.com/recipe/pollo-con-crema-a-las-hierbas-d56f75c72ab67a45174441af1efe4473/pollo",
"yield" : 42.0,
And continue with more 'recipe', what I want is to get only the array of hits that all the recipes have to be able to show in my application, the problem is that I get the following error:
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
I understand that it is because it expects an array and it obtains a JSON object, but I do not know how to parse it, I have my Recipe model class and the RecipeService service and I manage everything in MainActivity, I have seen in some answers that I would have to do an intermediate response, but I do not understand how I could implement it in my code, then I show the classes that handle all this.
Recipe Class (Model):
public class Recipe {
private String label;
private String image;
private String source;
private String shareAs;
private List<String> dietLabels;
private List<String> healthLabels;
private List<String> cautions;
private List<String> ingredientLines;
private List<String> ingredients;
private double calories;
private double totalWeight;
private List<String> totalNutrients;
private List<String> totalDaily;
public String getLabel() {
return label;
}
.
.
.
RecipeService Class:
public interface RecipeService {
String API_ROUTE = "/search";
String API_KEY = "&app_key=" + Credentials.API_KEY;
String APP_ID = "&app_id=" + Credentials.APP_ID;
//String query = "";
#GET(API_ROUTE)
Call< List<Recipe> > getRecipe(#Query("q") String q);
}
MainActivity:
private void getRecipes() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://test-es.edamam.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
RecipeService recipeService = retrofit.create(RecipeService.class);
Call<List<Recipe>> call = recipeService.getRecipe("pollo");
System.out.println("GET RECIPES");
System.out.println("HEADERS: "+ call.request().headers());
call.enqueue(new Callback<List<Recipe>>() {
#Override
public void onResponse(Call<List<Recipe>> call, Response<List<Recipe>> response) {
System.out.println("RESPONSE CODE: " + response.code());
for(Recipe recipe : response.body()){
System.out.println("AÑADIENDO: " + recipe.getLabel());
recipes.add(recipe.getLabel());
}
//System.out.println(recipes.toArray().toString());
}
#Override
public void onFailure(Call<List<Recipe>> call, Throwable t) {
System.out.println("HA OCURRIDO UN FALLO");
System.out.println(t.getMessage());
}
});
}
If API response is exactly what you post then the response is INVALID JSON format. You may check your JSON validity by jsonlint.
Secondly, your error says,
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
Which means, POJO is designed for a JSON array, but from the API you are getting a JSON object.
The solution is really simple.
There are tons of plugins in Android Studio like this, or go this online converter tool. Then hopefully you will not get the same error,
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 have a request to build slider image from jsonArray using volley, i don't know how to put value of jsonArray to hashmap<string, string> .. it keep saying null object
error message
Attempt to invoke virtual method 'java.lang.Object
java.util.HashMap.put(java.lang.Object, java.lang.Object)' on a null object reference
JSON array value
[
{"cPID":"62001002280293829",
"image":"http:\/\/ibigcreative.com\/dev\/assets\/images\/slider\/rsch.jpg"},
{"cPID":"62001002020254584",
"image":"http:\/\/ibigcreative.com\/dev\/assets\/images\/slider\/penang.jpg"},
{"cPID":"62001002050264258",
"image":"http:\/\/ibigcreative.com\/dev\/assets\/images\/slider\/guardian.jpg"}
]
and then i wanna put that value like this into hashmap<string, string> inside onCreate()
HashMap<String,String> url_maps = new HashMap<>();
url_maps.put("Hannibal", "http://static2.hypable.com/wp-content/uploads/2013/12/hannibal-season-2-release-date.jpg");
url_maps.put("Big Bang Theory", "http://tvfiles.alphacoders.com/100/hdclearart-10.png");
url_maps.put("House of Cards", "http://cdn3.nflximg.net/images/3093/2043093.jpg");
url_maps.put("Game of Thrones", "http://images.boomsbeat.com/data/images/full/19640/game-of-thrones-season-4-jpg.jpg");
it gonna use for adding picture to my slider(slideshow) inside onCreate()
for(String name : url_maps.keySet()){
DefaultSliderView DefaultSliderView = new DefaultSliderView(getContext());
// initialize a SliderLayout
DefaultSliderView
.image(url_maps.get(name))
.setScaleType(BaseSliderView.ScaleType.Fit)
.setOnSliderClickListener(this);
//add your extra information
DefaultSliderView.bundle(new Bundle());
DefaultSliderView.getBundle()
.putString("extra",name);
mDemoSlider.addSlider(DefaultSliderView);
}
and i don't know how to put values from volley JsonArray, and this is my request but error saying null.
private void getSlider(){
String tag_string_req = "sliderList";
// Showing progress dialog before making http request
JsonArrayRequest mostReq = new JsonArrayRequest(AppConfig.URL_Slider, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
try {
for (int i = 0; i < 5; i++) {
JSONObject jObj = response.getJSONObject(i);
url_maps.put(jObj.getString("cPID"), jObj.getString("image"));
}
}
catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + "Error Data Occured!!" + error.getMessage());
Toast.makeText(getContext(),
error.getMessage(), Toast.LENGTH_LONG).show();
hideDialog();
}
}) ;
AppController.getInstance().addToRequestQueue(mostReq, tag_string_req);
}
the values request was accepted on volley, it show on Logcat .. but null on hashmap .. tell me if i got mistake in my code, sorry just newbie and still study
You are iterating thru just the keys... You need to iterate through the keys and values...
for (url_maps.Entry<String, String> url_map : url_maps.entrySet()) {
String key = url_map.getKey();
String value = url_map.getValue();
// ...
}
ANOTHER WAY TO ATTEMPT THIS IS...
to deserialize your Json into a java object...
ObjectMapper mapper = new ObjectMapper();
string StringJson = "[
{"cPID":"62001002280293829",
"image":"http:\/\/ibigcreative.com\/dev\/assets\/images\/slider\/rsch.jpg"},
{"cPID":"62001002020254584",
"image":"http:\/\/ibigcreative.com\/dev\/assets\/images\/slider\/penang.jpg"},
{"cPID":"62001002050264258",
"image":"http:\/\/ibigcreative.com\/dev\/assets\/images\/slider\/guardian.jpg"}
]";
// For the following line to work you will need to make a URLMaps Class to hold the objects
URLMaps urlMaps = mapper.readValue(StringJson , URLMaps.class);
The URLMaps Class might look like this.
public class URLMaps{
public string name = "";
public string image = "";
//constructor
public URLMaps(string a, string b) {
name = a;
image = b;
}
public string getName() {
return name;
}
public string getImage() {
return image;
}
}
Then to utilize the class you can go with:
urlMaps.getName(), or urlMaps.getValue() in your DefaultSliderView.image()
Also to note, since this is a class you can store an array of them or a list of them, so you can re-purpose your for loop...
For (URLMap urlmap : UrlMaps[]) // where URLMaps is your object that holds multiple instances of URLMaps.
Lastly, it has been a long time since I have coded in Java, so this code is untested, but should help you come to a solution.
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);
}
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
}
]
}
}