Convert string json inside a json to a object java - java

I have a string like this
"{
"scanReference": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"document": {
"status": "data",
"data": {
"firstName": "FULL NAME",
"info": "{\"city\":\"CITY\",\"issueDate\":\"2019-01-01\"}"
},
"country": "USA"
}
}"
I have created class (simple POJO) to convert this to java object and using GSON. I am using the below code to convert to java object.
(gson.fromJson(response, MyClass.class));
But I am receiving the below error when converting , it because "info" is a string not json.
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING
The code works as expected when I made "info" a json and tested it, but it is string here.
Can anyone help me to solve this problem?
PS: Thank you for help.

Create info class within MyClass.
Public class MyClass.class{
private String scanReference;
..........
private Info info
//Setter getter
}

Related

java model mock response json

I am creating a Rest service which calls an external service.
I have this problem: the external service I call responds in two ways depending on the case of Success or Failed. This is json:
json{
"result": "001",
"status": "Success",
"response": {
"codiceCase": "CAS-46759-Q8P7X3",
"guidCase": "88458d32-dd42-ec11-8c62-0022489d2f61"}
}
OR
{
"result": "002",
"status": "Failed",
"errorManagement": {
"errorCode": "E02",
"errorDescription": "field not value in body"
}
}
Well I created 3 simple classes:
class XXX... private String result, status; .... getter & setter
class Response... private String codiceCase, guidCase; ... getter & setter
class ErrorManagement...private String errorCode, errorDescription;... getter & setter
But when I populate with my mock, the json is always formed with the class field that I don't care for example:
{
"result": "001",
"status": "Success",
"response": {
"codiceCase": "CAS-46759-Q8P7X3",
"guidCase": "88458d32-dd42-ec11-8c62-0022489d2f61" },
{
***"errorMessage"**: null}
}
How can I get only 2 of the 3 classes returned as json in my mock?
Thanks for your help.
I suppose you’re using Jackson to deserialize JSON as this is - I think - the default for spring.
With Jackson you can annotate the model class to omit null values in the JSON string representation:
#JsonInclude(Include.NON_NULL)
public class Model { … }

How to deserialize json to nested custom map via gson?

I have the following json
{
"id": "1111",
"match": {
"username1": {
"id": "1234",
"name": "alex"
},
"username2": {
"id": "5678",
"name": "munch"
}
}
}
To deserialize it, I have the following data model class.
class json{
String id;
Match match;
}
class Match {
private Map<String,Profile> profiles
}
class Profile{
private String id;
private String name;
}
I am not getting any deserialization error when I am using gson but the
profiles variable is coming as null.
This is how I am deserializing.
var json = gson.fromJson(data,json.class)
inside the match object there can be a dynamic number of usernames not just two . Why am I getting profile object as null and how can I correctly populate it?
Making changes to json is the last resort here. I can make any other required changes.
The issue is your model. You don't need Match because profiles does not really exist in your JSON. You just json (this one with small changes) and Profile:
class json{
String id;
Map<String,Profile> match;
}
This will work.

POJOs declaration for different api with common fields

I need to create response POJOs class for a couple of APIs i have to call in my microservice . The response has a base structure given below.
{
"requestId": "abcd-1234-3456",
"sourceSystem": "HOME",
"response": {
"statusCode": "200",
"statusMessage": "Successfully Received",
"statusType": "SUCCESS",
"details": [
{
"message" : "hi"
}
]
}
}
Here the object inside the "details" property array can vary and can have different class definitions. Can someone help whether how should i declare my POJOs so that there is a common class for the common fields and a different set of classes for object inside details property . I tried few ways using java generics and #JsonSubType but that is giving some error Unrecognized field "details" during deserialisation.
Why don't you try and define it as object instead :-
class Response{
private String requestId;
private String statusMessage;
private String statusType;
private List<Object> details;
}

Map with object and list of objects to Json

I have got two main model classes: Customer and Product
public class Customer {
String name;
String surname;
int age;
BigDecimal cash;
}
public class Product {
String name;
Category category;
BigDecimal price;
}
I want to build json file with Map<Customer, List<Product>>
When I write to json file data with my method which works correct - I am sure about this - the json file shows this syntax
{
"Customer{name\u003d\u0027Custo1\u0027, surname\u003d\u0027Surname\u0027, age\u003d18, cash\u003d1200}": [
{
"name": "prod1",
"category": "CLOTHES",
"price": 12000
},
{
"name": "prod2",
"category": "ELECTRONIC",
"price": 15000
}
]
}
Then when i want to read this file, the error Exception in thread "main" java.util.NoSuchElementException: No value present occurs so I think that the Customer syntax from json file is not recognized.
So I tried to write data to json file on my own with this syntax below, but it does not work
[
{
"name": "Abc",
"surname": "Def",
"age": 14,
"cash": "2000"
}
:
[
{
"name": "prod1",
"category": "CLOTHES",
"price": 12000
},
{
"name": "prod2",
"category": "ELECTRONIC",
"price": 15000
}
]
]
json converter method:
public void toJson(final T item) {
try (FileWriter fileWriter = new FileWriter(jsonFilename)) {
fileWriter.write(gson.toJson(item));
} catch (Exception e) {
throw new ValidatorException(e.getMessage());
}
}
#Tom is right on the issues you've faced with. I'll explain why and suggest one more solution.
Your first JSON is technically a valid JSON but it cannot be deserialized, because the map keys are results of the Customer.toString() method Gson uses by default. This is why it looks weird, acts like a debug string, and can't be deserialized back: there it is almost always no way to restore an object from the toString() result (toString is designed mostly for debugging/logging purposes providing basic information regarding the state of a particular object that does not need to expose its all internals at all).
Your second JSON is invalid JSON. Period.
Tom's suggestion of making the list of products a part of the customer class is totally fine. Having it implemented like that lets you to serialize everything as a list like this:
[
{
"name": "john",
"products": [
{"name": "prod1"},
{"name": "prod2"}
]
}
]
Hint: separating domain objects (Customer and Product) and representation objects for data transfer (CustomerDto and ProductDto) is usually a fine idea too since it allows to create representation for any concrete representation implementation (one for various JSON implementation libraries, two for other-format-oriented tools, third for persistence, four for UI views, etc), so it might be implemented like converting Map<Customer, List<Product>> to List<CustomerDto> and back (possibly by using mapper-generators like MapStruct).
If for whatever reason it is not possible to reorganize your domain classes or create Gson-friendly DTO-mappings, or you're fine to keep it as simple as possible and you're fine with having not that trivial JSON structure (as long as you understand implications of the format in this solution: evolution, distribution, etc), then you can enable special Gson mode to support this kind of maps. It generates valid JSONs that can be serialized and deserialized back, but the way it is implemented looks a bit of anti-pattern to me because of losing semantics due to using arrays as the data container.
#AllArgsConstructor
#EqualsAndHashCode
#ToString
final class Customer {
final String name;
}
#AllArgsConstructor
#EqualsAndHashCode
#ToString
final class Product {
final String name;
}
public final class MapTest {
private static final Gson gson = new GsonBuilder()
.enableComplexMapKeySerialization()
.create();
private static final TypeToken<Map<Customer, List<Product>>> customerToProducts = new TypeToken<Map<Customer, List<Product>>>() {};
#Test
public void test() {
final Map<Customer, List<Product>> ordersBefore = ImmutableMap.of(
new Customer("john"), ImmutableList.of(new Product("prod1"), new Product("prod2"))
);
final String json = gson.toJson(ordersBefore, customerToProducts.getType());
Assertions.assertEquals("[[{\"name\":\"john\"},[{\"name\":\"prod1\"},{\"name\":\"prod2\"}]]]", json);
final Map<Customer, List<Product>> ordersAfter = gson.fromJson(json, customerToProducts.getType());
Assertions.assertEquals(ordersBefore, ordersAfter);
}
}
Note that it generates JSON like this (index 0 means the key, index 1 means the value):
[
[
{"name": "john"},
[
{"name": "prod1"},
{"name": "prod2"}
]
]
]

How to create a simple json template to send body data with restassured?

So i am trying to build a json to send data to the body of my restassured request, like this structure here:
{
"id": 1,
"category": {
"id": 1,
"name": "duch"
},
"name": "benny",
"photoUrls": [
"string"
],
"tags": [
{
"id": 0,
"name": "string"
}
],
"status": "available"
}
So it is as simple as to copy this as string to the body of the request and i am done, i don't want that at all.
Is there a framework of sorts to give this structure and to change the data dynamically somehow?
I don't want this: (for example)
given().body("{\r\n\"city\": \"Hod Hasharon\",\r\n\"description\": \"Automation Hotel\",\r\n\"name\":\"Nir Great hotel\",\r\n\"rating\":5\r\n}")
.when().post("http://localhost:8090/example/v1/hotels").then().statusCode(201);
I want to be more flexible here, to reference some kind of object (A template with the option to change the data in some places?) that handles this stuff, is there something like that?
I think what you need is using POJO and Jackson to serialize it to json.
public class Payload {
private int id;
private String name;
private List<Tag> tags; //Tag is another class you need to create the same way
//getters, setters
}
And then using objects as payload in your request:
Payload payload = new Payload();
payload.setId(123);
payload.setName("John");
given().contentType("application/json").body(payload).when().post("http://example.com");
Also don't forget to add jackson-databind dependency to your project.
There's more about that in official documentation here: https://github.com/rest-assured/rest-assured/wiki/Usage#object-mapping

Categories

Resources