I have a JSON Object
{
"firstname": "foo",
"account":
{
"city": "bar"
}
}
which I want serialize in a REST backend:
#POST
public Response create(Employee e)
Classes:
public class Employee {
public String firstname;
private Address address;
}
public class Address {
public String city;
}
Unforutanetly, I always receive a 400 status code. But if I do
public Response create(Object o)
everything works fine. Any ideas?
Your JSON does not correspond (map) to your POJO types. In the JSON, you have account, but in your Java type you have address.
Related
I am facing a problem while parsing API response using Retrofit 2.
The API's are already in production and I cannot request a change in API.
Following are two different responses I am getting from server
Success response:
{
"status":0,
"empId":121,
"message":"Data available",
"data":{
"name":"Sam",
"designation": "Software Engineer",
"mob": "1255565456"
}
}
Failure response
{
"status":10,
"empId":121,
"message":"No data available",
"data":""
}
Parsing Classes
class Response{
public int status;
public String message;
public int empId;
public Student data;
}
class Student{
public String name;
public String designation;
public String mob;
}
I am able to parse the success response. But getting the following exception for the failure case.
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING
try this ,
Object getrow = null;
try {
getrow = this.// your object
LinkedTreeMap<Object, Object> tree = (LinkedTreeMap) getrow;
String name = tree.get(<your body>).toString()
} catch (Exception e) {
e.printStackTrace();
}
The way that you can handle this situation is by treating 'data' as a generic object rather than as a String or 'Student'.
p̶u̶b̶l̶i̶c̶ ̶S̶t̶u̶d̶e̶n̶t̶ ̶d̶a̶t̶a̶;̶
public Object data;
While Using data add a check like this
if(data instanceof String){
String parsedData=data.toString();
}else{
Student parsedData= (Student) data;
}
Make Student as an inner class or Response class. and Retrofit will parse the response and will give you the object.
class Response
{
public int status;
public String message;
public int empId;
public Student data;
Class Data
{
public String name;
public String designation;
public String mob;
}
}
I have a simple spring webservice that offers a #PostMapping and takes a json array of elements.
I want spring to automatically validate each element in the list.
#RestController
public class PersonServlet {
#PostMapping
public void insertPersons(#RequestBody #Valid List<PersonDto> array) {
}
}
public class PersonDto {
#NotBlank
private String firstname;
#NotBlank
private String lastname;
}
The following POST request should fail with a validation error that firstname is missing:
[
{
"lastname": "john"
},
{
"firstname": "jane",
"lastname": "doe"
}
]
Result: the request is NOT rejected. Why?
Sidenote: if I just use PersonDto as parameter (not a list), and send a json post request with only one persons, the validation works and correctly rejects the request.
So in general the validation annotations seem to work, but just not when inside the collection!
Workaround: the following triggers the list validation:
public class PersonDtoList extends ArrayList<PersonDto> {
#Valid
public List<PersonDto> getList() {
return this;
}
}
public void insertPersons(#RequestBody #Valid PersonDtoList array) {
}
You should add another class outside the list, for example PostCommand:
public class PostCommand() {
#Valid
private List<PersonDTO> list;
}
and send it on the request:
#RestController
public class PersonServlet {
#PostMapping
public void insertPersons(#RequestBody #Valid PostCommand postCommand) {
}
}
and JSON will be:
{
"list": [
{
"lastname": "john"
},
{
"firstname": "jane",
"lastname": "doe"
}
]
}
And you will have an exception.
I am busy with a Dropwizard application and need to have an array injected to a POJO as one of the parameters of a put method. Unfortunately the array is not properly handled which results in a Bad Request response. To illustrate the JSON passed by the frontend looks like:
{
"name": "Jon",
"surname": "Doe",
"children": ["Chris", "Dave", "Sam"]
}
And my Java representation:
public class Person{
private String name;
private String surname;
private List<String> children;
public Person(){
}
#JsonProperty
public String getName(){
return name;
}
#JsonProperty
public void setName(String name){
this.name=name;
}
#JsonProperty
public String getSurname(){
return surname;
}
#JsonProperty
public void setsurname(String surname){
this.surname=surname;
}
#JsonProperty
public List<String> getChildren(){
return children;
}
#JsonProperty
public void setChildren(List<String> children){
this.children=children;
}
}
And in my resource class:
#PUT
#Timed
#UnitOfWork
#Path("/{userid}")
public Response getData(#PathParam("userid") LongParam userId,
Person person) {
// Do some stuff with the person
}
How can I properly handle the deserialization of the array in the JSON?
EDIT
I am using an angular front-end and I am invoking the method as follows:
function(json){
return $http({
url: API_URL.people+"/update/personID",
method: "PUT",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: json
});
}
Where the json argument contains the name, surname and children as above.
Looks like the GET service is defined incorrectly. It shouldn't have Person defined.
As per http method definition, the GET http method can't have body. So you can't have Person as the input parameter.
If you need to send Person to service, you may need to change the http method to POST or something else (like PUT) based on your requirement.
#GET
#Timed
#UnitOfWork
#Path("/{userid}")
public Response getData(#PathParam("userid") LongParam userId) {
// Do some stuff with the person
}
Turns out the code I provided words like a charm. Upon further investigation I made a mistake in the javascript object which got converted and sent as JSON which caused the error.
I am fetching a JSON using retrofit 2, which carries object if the key has value else an empty array. ex:
If the key i.e address has values it returns object
{
"student": {
"name": "Some name",
"address": {
"house": "5",
"road": "3"
}
}
}
If the key i.e address does not have any value it returns empty array
{
"student": {
"name": "Some name",
"address": []
}
}
In my POJO class I have made my Address class type to object so that retrofit can parse the JSON.
public class Student {
#SerializedName("name")
#Expose
private String name;
#SerializedName("address")
#Expose
private Object address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object getAddress() {
return address;
}
public void setAddress(Object address) {
this.address = address;
}
}
Now how can I check that the address type is object or an array?
I have tried with isArray(), but did not find result.
if(obj.getclass().isArray())
Thanks in advance.
You can check through instanceof is object is JosnObject or JsonArray?
if (address instanceof JSONObject) {
JSONObject jsonObject = (JSONObject) address;
}
else if (address instanceof JSONArray) {
JSONArray jsonArray = (JSONArray) address;
}
You can go for json schema validation where you have to definie everything regrading type and format of json and later on validate your json using
Jackson 2.x libraries and fge/json-schema-validator.
Reference link for more details.
http://wilddiary.com/validate-json-against-schema-in-java/
I wonder why your json is not consistent? I mean if there is no value in address it not supposed to be a JSONArray
Instead it supposed to be like -
"address": {
"house": "",
"road": ""
}
It will easy to parse if you are doing like above -
Now you Pojo will be -
public class Address {
#SerializedName("house")
#Expose
private String house;
#SerializedName("road")
#Expose
private String road;
public String getHouse() {
return house;
}
public void setHouse(String house) {
this.house = house;
}
public String getRoad() {
return road;
}
public void setRoad(String road) {
this.road = road;
}
}
And finally you can get the Address using -
#SerializedName("address")
#Expose
private Address address;
in your Student class
PS,
Server side problems must be fixed by Server side.
Thanks to all. I have found my answer with the help of instanceof.
Instead of checking directly the address obj, I have to convert the value into Object type, i.e
Gson gson = new GsonBuilder().serializeNulls().setLenient().create();
String jsonStr = gson.toJson(obj.getAddress());
Object json = new JSONTokener(jsonStr).nextValue();
And then I can check with JSONObject
if (json instanceof JSONObject) {
// Object
}else{
// Array
}
How can I parse this response without having to create a separate response class for each entity.
{
"data": {
"id": 100,
"first_name": "Michael",
"last_name": "Blankenship"
}
}
I would like to have a generic class that can reference the data object and then just specify what type of class that should be used to parse the response
Something like this:
#Get
Call<User> getUser();
#Get
Call<Status> getStatus();
Without having to have multiple response classes for each type
public class UserResponse {
User data;
}
public class User {
String first_name;
String last_name;
}
public class StatusResponse {
Status data;
}
Workaround for this would create a generic class something like this
public class BaseResponseWrapper <T> {
#SerializedName("data")
private T data;
public BaseResponseWrapper(){
super();
}
public T getData() {
return data;
}
}