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,
Related
I am not able to map a consumed json to another json to each element by using REST template in Spring Boot
Controller code:
public List<Getrequests> getallrequests() {
List<Getrequests> list=Serviceobj.allrequestdata();
return list;
}
Service code:
public List<Getrequests> allrequestdata() {
String urlGETList = "http://localhost:8082/myapp/userinfo/getusertype/asd454";//get by id call
ResponseEntity<Usertype[]> responseEntity =resttemplateobj.getForEntity(urlGETList, Usertype[].class);
Usertype[]objects = responseEntity.getBody();
List results = admininfoDaoobj.getallrequestsdata();
//results.add(objects);if i un comment this line of code i am getting 1 output means it just add to the list only
return results;
}
Dao code:
public List<Getrequests> getallrequestsdata(){
String hql = "FROM Createrequest";
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
Query<Createrequest> query = getSession().createQuery(hql,Createrequest.class);
List resultlist= query.getResultList();
return resultlist;
}
Getrequests pojo class:
public class Getrequests{
private String userid;
private String username;
private String userphoneno;
.......getters and setters.....
}
User type pojo class:
public class Usertype{
private String usertype;
private String useraddress;
.......getters and setters.....
}
1 output:
[
{
"userid":"asd454",
"username":"satya",
"userphoneno":"1234567890"
},
{
"userid":"asd455",
"username":"satya",
"userphoneno":"1234567890"
}
[
{
"usertype":"admin,agent",
"useraddress:"dsadasd,asdasdsa"
},
{
"usertype":"agent",
"useraddress:"asdasdsa"
},
]
]
2 output
If I comment resultlist.add(objects) in Service code means it's not added to the getrequest list then I am getting below output:
[
{
"userid":"asd454",
"username":"satya",
"userphoneno":"1234567890"
},
{
"userid":"asd455",
"username":"satya",
"userphoneno":"1234567890"
}
]
But I need to map for each userid, I need to display the usertype and user address like below output.
3 Output
[
{
"userid":"asd454",
[
{
"usertype":"admin,agent",
"useraddress:"dsadasd,asdasdsa"
} ]
"username":"satya",
"userphoneno":"1234567890"
},
{
"userid":"asd455",
[
{
"usertype":"agent",
"useraddress:"asdasdsa"
}
]
"username":"satya",
"userphoneno":"1234567890"
}
]
I also tried the rest template call in Dao then also not getting.
How can I map for each userid to display the usertype and user address like as above shown 3 output.
From your snippets, it looks like you want to generate a specific POJO signature.
There are plenty of tools which can give you a stub out of a sample json request.
From your example, i would guess that changing the Getrequests would do the trick,
like :
public class Getrequests{
private String userid;
private String username;
private String userphoneno;
private Usertype userType;
.......getters and setters.....
}
You might need to change it to a list reference as well, depending on your schema and your overall requirement.
EDIT
public class Getrequests{
private String userid;
private String username;
private String userphoneno;
private List<Usertype> userType;
}
If i make the reference a list, then the below samples are the output :
Single object:
{
"userid":"69",
"username":"asd",
"userphoneno":"09876",
"userType":[
{
"usertype":"01",
"useraddress":"1234"
}
]
}
As An array :
[
{
"userid":"94",
"username":"asd",
"userphoneno":"09876",
"userType":[
{
"usertype":"01",
"useraddress":"1234"
}
]
},
{
"userid":"53",
"username":"asd",
"userphoneno":"09876",
"userType":[
{
"usertype":"01",
"useraddress":"1234"
}
]
}
]
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.
Is there any simple methods to return exception in JSON using Rest api?
I've already googled this question, but all solutions i see, was about throwing exceptions during some calculations. But what if income parameters are wrong? I mean what if there is sone string instead of int input parameter?
I created some DTO class for input data:
#XmlRootElement
public class RequestDTO implements Serializable{
private static final long serialVersionUID = 1L;
#XmlElement(name = "request_id")
private String requestId;
#XmlElement(name = "site")
private List<String> sitesIds;
#XmlElement(name = "date_begin")
#JsonSerialize(using = DateSerializer.class)
#JsonDeserialize(using = DateDeserializer.class)
private Date dateBegin;
#XmlElement(name = "date_end")
#JsonSerialize(using = JsonDateSerializer.class)
#JsonDeserialize(using = JsonDateDeserializer.class)
private Date dateEnd;
#XmlElement(name = "volume")
private double volume;
// there is getters and setters
}
If i sent something like 'qwerty' instead of 'volume' field in my json request i'l see error message like Runtime. Is it possible to handle it in someway? I mean to return error in json with such structure?
public class ExceptionDTO {
private String shortExceptionMessage;
private String stackTrace;
public ExceptionDTO(String shotExceptionMessage, String stackTrace){
this.shortExceptionMessage = shotExceptionMessage;
this.stackTrace = stackTrace;
}
public String getShortExceptionMessage() {
return shortExceptionMessage;
}
public String getStackTrace() {
return stackTrace;
}
}
UPD1:
#Provider
#Singleton
public class ExceptionMapperProvider implements ExceptionMapper<Exception>{
#Override
public Response toResponse(final Exception e) {
StringBuilder trace = new StringBuilder();
IntStream.range(0, e.getStackTrace().length)
.forEach(i -> trace.append(e.getStackTrace()[i]).append('\n'));
ExceptionDTO exceptionMessage = new ExceptionDTO(
e.toString(),
trace.toString()
);
return Response.status(500).entity(exceptionMessage).build();
}
}
As it's not really clear if you are interested on checking if field or value of the payload is correct, here are a few ways to work with both.
If you want to check if the value for a field is correct (ie volume field value should be greater than zero etc), check out bean validation. This makes use of annotations on the fields you want to verify.
// for example
#Min(value = 0, message = "invalid message")
private double range;
To use your ExceptionDTO as error response whenever one of those validation fails, you can do so by creating an ExceptionMapper<ConstraintViolationException>. check it here for more details.
If you are checking for the invalid field (ie client sends ragne fields instead of range), have a look at the stack trace on what exception is being thrown. Then register an exception mapper with your ExceptionDTO as body.
For example, if UnrecognizedPropertyException is thrown then you can add:
#Provider
public class UnrecognizedPropertyExceptionMapper implements ExceptionMapper<UnrecognizedPropertyException> {
#Override
public Response toResponse(UnrecognizedPropertyException e) {
ExceptionDTO myDTO = // build response
return Response.status(BAD_REQUEST).entity(myDTO).build();
}
}
If you want to validate input parameters in the request, you should return status code 400 (Bad Request) along with the error details. You can simply send json
{ "error": { "message": "string received for parameter x, where as int expected" } with the response status code 400.
`
I did a bit of research and determined that the best way to encode a Java exception in JSON is to use a convention developed by Oasis that looks like this:
{
"error": {
"code": "400",
"message": "main error message here",
"target": "approx what the error came from",
"details": [
{
"code": "23-098a",
"message": "Disk drive has frozen up again. It needs to be replaced",
"target": "not sure what the target is"
}
],
"innererror": {
"trace": [ ... ],
"context": [ ... ]
}
}
}
details is a list that should have an entry for each nested cause exception in the chain.
innererror.trace should include the stack trace if you wish, as a list of string values.
The response status code should be 400 unless you have a good reason for making it something else, and the code in the structure should match whatever you sent.
Write one method to convert a Java exception to this format, and you are done. Use it consistently and your JS code will be able to handle and display the exception values.
More of the details of the other approaches evaluated and dismissed are covered in this blog post on JSON REST API – Exception Handling
https://agiletribe.purplehillsbooks.com/2015/09/16/json-rest-api-exception-handling/
Here is the java method to convert an exception to this format:
public static JSONObject convertToJSON(Exception e, String context) throws Exception {
JSONObject responseBody = new JSONObject();
JSONObject errorTag = new JSONObject();
responseBody.put("error", errorTag);
errorTag.put("code", 400);
errorTag.put("target", context);
JSONArray detailList = new JSONArray();
errorTag.put("details", detailList);
String lastMessage = "";
Throwable runner = e;
while (runner!=null) {
String className = runner.getClass().getName();
String msg = runner.toString();
runner = runner.getCause();
JSONObject detailObj = new JSONObject();
detailObj.put("message",msg);
int dotPos = className.lastIndexOf(".");
if (dotPos>0) {
className = className.substring(dotPos+1);
}
detailObj.put("code",className);
System.out.println(" ERR: "+msg);
detailList.put(detailObj);
}
JSONObject innerError = new JSONObject();
errorTag.put("innerError", innerError);
JSONArray stackList = new JSONArray();
runner = e;
while (runner != null) {
for (StackTraceElement ste : runner.getStackTrace()) {
String line = ste.getFileName() + ":" + ste.getMethodName() + ":" + ste.getLineNumber();
stackList.put(line);
}
stackList.put("----------------");
runner = runner.getCause();
}
errorTag.put("stack", stackList);
return responseBody;
}
I am using Spring Data with a Mongo DB embedded database and have the following document structure:
{
id : 111
messaage : abcd
commentsList: [
{
id : 123
text: test text
numberOfLikes : 5
numberOfDislikes: 2
}
]
}
I am trying to get a comment by id and update the numberOfLikes field by one and can't seem to get it to work, here is what I've tried and the java class structure:
public class Post {
private String id;
private String message;
private List<Comment> commentsList = new ArrayList<>();
...
}
public class Comment {
private String id;
private String text;
private int numberOfLikes;
private int numberOfDislikes;
...
}
Query query = new Query();
query.addCriteria(Criteria.where("commentsList._id").is("123"));
List<MongoComment> commentList = mongoTemplate.find(query, MongoComment.class);
Currently the returned list is always null.
Since you are trying to get a comment by id and update the numberOfLikes field by one, you essentially want to replicate this mongo shell update operation:
db.post.update(
{ "commentsList.id": "123" },
{
"$inc": { "commentsList.$.numberOfLikes": 1 }
}
)
The equivalent Spring Data MongoDB code follows:
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query;
import static org.springframework.data.mongodb.core.query.Update;
...
WriteResult wr = mongoTemplate.updateMulti(
new Query(where("commentsList.id").is("123")),
new Update().inc("commentsList.$.numberOfLikes", 1),
MongoPost.class
);
The id of the elements in the array "commentsList" is "id" (without the '_').
query.addCriteria(Criteria.where("commentsList.id").is("123"))
That should work.
The "_id" you're trying to query is the identifier Mongodb automatically generates for each document. Your document in the database looks like this:
{
_id: ObjectId("56b46e1d1d1353e38886dcc34f"),
id : 111,
messaage : "abcd",
commentsList: [
{
id : 123,
text: "test text",
numberOfLikes : 5,
numberOfDislikes: 2
}
]
}
I use Gson in my project. But it returns me error
String sig = PortalConfig.getSignature(method, callId, params);
String url = PortalConfig.getUrl(method, callId, sig, params);
String plainResponse = BaseClientCommunicator.executeGetMethod(url);
GsonBuilder builder = new GsonBuilder();
Gson gsonObject = builder.create();
response = gsonObject.fromJson(plainResponse, GetMenuResponse.class);
return response;
example I get a Server-response like this
{
"group":
[
{
"id": "206896",
"name": "Ryż",
"info": "xyz"
},
{
"id": "206897",
"name": "Buraki",
"info": {}
}
]
}
and i have error Expected a string but was BEGIN_OBJECT
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 16151
how should I handle this exception??
public class GetMenuResponse
{
#SerializedName("group")
private group[] group;
//method get and set
//to string method
}
public class group
{
#SerializedName("id")
private String id;
#SerializedName("name")
private String name;
#SerializedName("info")
private String info;
//method get and set
//to string method
}
I do not have access to the database, because I use the API
Problem is at line "info": {} in your json string.
Your class have private String info; String type and in your JSON string it is JSONObject.
It will try to convert JSONObject into String, which give error Expected a string but was BEGIN_OBJECT.GSON API cant able to cast JSONObject into JAVA String.
Value of info in first element of your array group is correct that is "info": "xyz" but same variable value in second element is different.
check value of info if it is String than you need to check your JSON response coming from server, if not than you need to change it's type into class variable.