Spring: #RequestBody not deserializing serialized JSON field declared using alternate name - java

I have one input request DTO for a Patch call
#Data
public class RequestDTO {
String name;
#SerializedName(value= "requestNumber", alternate = {"requestNo"})
String requestNumber;
}
My Controller method looks something like:
#PatchMapping("/path")
public ResponseEntity<ResponseDTO> updateSomething(#RequestBody #Valid RequestDTO requestDTO) {
//some code here
if(requestDTO.getRequestNumber == null) {
log.error("Deserialization failure");
}
//return something
}
When I try to deserialize request DTO using Gson, I am able to do it with both the field names, requestNumber and requestNo
Example:
Gson gson = new Gson();
String input = "{"name": "abc", "requestNumber": "1"};
RequestDTO requestDTO = gson.fromJson(input, RequestDTO.class);
Assert.assertNotNull(requestDTO.getRequestNumber) //Test passed
And
String input = "{"name": "abc", "requestNo": "1"};
RequestDTO requestDTO = gson.fromJson(input, RequestDTO.class);
Assert.assertNotNull(requestDTO.getRequestNumber) //Test passed
Irrespective of field name is requestNumber of requestNo in input JSON, it is deserialized properly.
But whenever I pass a request DTO of the form {"name": "abc", "requestNo": "1"} to my patch call, on deserialization, value of requestNumber field in the deserialized DTO always turns out to be null. Deserialized DTO looks like:
{
"name": "abc",
"requestNumber": null
}
It works well when input field name is requestNumber. What is the reason behind this?
What is best way to deserialize the value in requestBody with both field names?
I cannot stick to only one field name because my actual DTO (this is dummy one) is used by multiple systems and it is not possible to have only either field name.

Spring uses Jackson Object Mapper for deserializing JSON objects. Since #SerializedName annotation belongs to Gson and not to Jackson, it will not take the alternate value. Use #JsonAlias from Jackson for alternate field names.
#JsonAlias("requestNo")
String requestNumber;
This will help in deserializing values declared using both field names.

Related

How to handle the case when field is not present in Object Java?

I have an object something like this in my database and now my requirement is to find the value of particular field such as name and if present return true,
{
"_id" : "123",
"name" : "Team"
}
but in some case the field name itself doesn't exist. Sample can be something like this:
{
"id":1234
}
In this case I need to return false.
How can I validate if name field exist in particular object?
I was trying to use StringUtils method something like this
StringUtils.isBlank(obj.getName); But its throwing It is throwing java.lang.NullPointerException .
You can use Json schema validator. If your json will be in specific format. Please have a look at Jackson library.
JSONObject class has a method named "has". try this way,
if (json.has("name")) {
String status = json.getString("name"));
}
This will work
You can use Gson Java library to serialize and deserialize Java objects to JSON (as given below).
Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(object, JsonObject.class);
Then, you can use the has method in JsonObject, to check if the key exists in it.
jsonObject.has(key)
Example:
Below is a method to check if given key exists in given json string, and get it's value.
(Instead of String, you can use your object as well. Here, I am considering the jsonStr as a String object, for better understanding.)
private String getValueFromJsonForGivenKey(String key, String jsonStr) {
Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(jsonStr, JsonObject.class);
if (jsonObject.has(key)) {
// The given JSON string has the given key
String value = jsonObject.get(key).getAsString();
return value;
}
return null;
}
For key id and for jsonStr { "id": "1234" }, we get 1234.
For key name and for jsonStr { "id": "1234" }, we get null.
What you can do is to use JSONObject's opt method
eg.
JSONObject jsonObject = new JSONObject(myJSONString);
String name = jsonObject.optString("name");

Jackson: Get non-decoded JSON string value from JSON with dynamic structure (JsonObject)

I'm using a JSON file to specify a template for the request body for HTTP requests to a backend. I'm inserting parameter values into the request body through a custom placeholder syntax:
{
"requestBody": {
"desc": "{descriptionParameter}"
}
}
The placeholder logic looks for {placeholder} patterns in the JSON strings, and replaces them with the respective parameter values.
Now, I also want to have the possibility to specify a request body with literal curly braces, so my idea was to not do any replacement if the curly braces are quoted in the JSON:
{
"requestBody": {
"desc": "\u007BnonReplacedLiteral\u007D"
}
}
However I could not find a way to get hold of the non-decoded JSON string. Is this possible with Jackson?
Here is the code that I'm currently using: I use a Jackson ObjectMapper to parse the JSON into the following object:
public class RequestTemplate {
ObjectNode requestBody;
// ... getters
}
The requestBody object doesn't have a fixed structure, so I can only map it to an ObjectNode and then need to use the tree API from that point on:
Iterator<Entry<String, JsonNode>> propertyIterator = requestBody.fields();
while (propertyIterator.hasNext()) {
Entry<String, JsonNode> property = propertyIterator.next();
String string = property.getValue().textValue();
// string is now the decoded value - how would I get the non-decoded value?
// ... parameter replacement logic
}

How to Parse JSON having data types with values?

I have an issue with JSON data.
In my Json it is having data types with values. not sure how to parse.
ex:
{
"id": "123456",
"name": {
"firstName": {
"String": "Nathon"
},
,
"lastName": {
"String": "Jason"
}
}.
Please help on this
public String map(ObjectNode jsonNode) throws Exception {
return value.get("id");
}
I tried with the above sample code , but i am able to parse only "id"
If you are using Jackson2 then get then name as JsonNode
JsonNode nameNode = value.path("name");
And then again get the firstName and lastName as JsonNode
JsonNode firstName = nameNode.path("firstName");
JsonNode lastName = nameNode.path("lastName");
From JsonNode firstName and JsonNode lirstName get the string value
String name1 = firstName.path("string").asText();
String name2 = lastName.path("string").asText();
Well first of all you don't have to mention the data types in order to parse a JSON appropriately, just create a POJO class matching the structure of JSON then use GSON to parse JSON into a java class
When your json is deserialized into ObjectNode then it is actually represented internally as a map key/value in which value can itself be again a map as is in your case. Visually if you look at it, it would be something like this.
So you would need to follow this structure using get(fieldName) to get the value OR an ObjectNode if it is nested . Remember if the return value is ObjectNode then simply printing it would just return the json fragment it represents, so you would need to call again 'get(fieldName)' on that object.

Rest Assured - deserialize Response JSON as List<POJO>

I have a POJO Artwork. I'm retrieving a List of those objects from a RESTful webservice in the HTTP response body in JSON format. I'm trying to write a Rest Assured-based test that would analyze the returned list. The code looks like this:
Response response = get("/artwork");
List returnedArtworks = response.getBody().as(List.class)
The problem is, I can't get Rest Assured to parse the returned JSON as List<Artwork>. Instead, I get a List<LinkedHashMap>. The map has a proper structure, i.e. could be mapped by Jackson to Artwork object, but I'd like to avoid mapping it manually.
JSON mappings in my model are OK, because when I map single object like this:
Artwork returnedArtwork = response.getBody().as(Artwork.class);
it works fine.
Is it possible to get returnedArtworks as List<Artwork>?
You can do this:
List<Artwork> returnedArtworks = Arrays.asList(response.getBody().as(Artwork[].class));
The trick is to deserialize JSON to an array of objects (because there is no difference between the JSON string of an array or a list), then convert the array to a list.
this solution works for version 3.0.2 (io.restassured):
JsonPath jsonPath = RestAssured.given()
.when()
.get("/order")
.then()
.assertThat()
.statusCode(Response.Status.OK.getStatusCode())
.assertThat()
.extract().body().jsonPath();
List<Order> orders = jsonPath.getList("", Order.class);
This will extract the objects for a structure like this:
public class Order {
private String id;
public String getId(){
return id; }
public void setId(String id){
this.id = id;
}
}
with the given json:
[
{ "id" : "5" },
{ "id" : "6" }
]
By using Google's Gson library you can easily parse it to List<Artwork>. Try below code
Gson gson = new Gson();
List<Artwork> returnedArtworks = gson.fromJson(jsonStr, new TypeToken<List<Artwork>>(){}.getType());
//* where jsonStr is the response string(Json) receiving from your Restful webservice
Rest-assured provide an as(java.lang.reflect.Type) next to the version expecting a Class used in the question.
java.lang.reflect.Type type; //TODO defines the type.
Response response = get("/artwork");
List<Artwork> returnedArtworks = response.getBody().as(type)
In my opinion the way the type variable depends from the serialization lib that is used.
If using Gson, as pointed out by Purushotham's answer, TypeToken can be used. I prefer using it directly in rest-assured:
Type type = new TypeToken<List<Artwork>>(){}.getType();
Response response = get("/artwork");
List<Artwork> returnedArtworks = response.getBody().as(type)
When using Jackson, the solution is to use the TypeFactory (javadoc, source) to tell to which type it should be de-serialized:
Type type = TypeFactory.defaultInstance().constructCollectionLikeType(ArrayList.class, Artwork.class);
Response response = get("/artwork");
List<Artwork> returnedArtworks = response.getBody().as(type)
With REST assured 3.0.2 you can simply check if content exists in the array
when().get("/artwork").then().body("artworks", hasItem("some art");
//or check multiple values in array
when().get("/artwork").then().body("artworks", hasItems("some art", "other art");
This way you will avoid complexity in your code by converting JSON to list more examples how to check response content can be found link

Accessing JsonString using Gson

I am getting a response like this
String result = responseEntity.getBody();
{
"FailureReason": "",
"State": "True",
"UserId": 1038,
"Specified": false,
"Name": "Java"
}
How would i access these JsonString. I am using Gson to form the JsonString. I am JS Guy, when i try to access result.Name [It throws me error]
A good way is to use POJO. Make one POJO that represent the response.
Use,
gson.fromJson(responseStr, responsePojoType);
This will return object of your POJO type. Then use POJO object's getter method to fetch whatever value required.
You can use Android's JSONObject like this:
JSONObject jsonResult = new JSONObject(result);
String name = jsonResult.getString("Name");
int id = jsonResult.getInt("UserId");
check http://www.androidhive.info/2012/01/android-json-parsing-tutorial/

Categories

Resources