Lombok #delegate annotation not passing values to innerDTO - java

inside my test class
String json="{\n" +
"\t\"masterName\": \"test1\",\n" +
"\t\"masterSubjectName\": \"testsubject\",\n" +
"\t\"masterRoll\": \"534\",\n" +
"\t\"firstName\": \"studentFirstName\",\n" +
"\t\"rollNumber\": \"23\"\n" +
"}";
Student studentDTO=new Gson().fromJson(json, Student.class);
System.out.println(studentDTO);
Student.java
#Data
public class Student {
#Delegate(types = Master.class)
private Master master=new Master();
private String firstName;
private String lastName;
private int rollNumber;
}
Master.java
#Data
public class Master {
private String masterName;
private String masterSubjectName;
private int masterRoll;
}
This gives Response:
Student(master=Master(masterName=null, masterSubjectName=null, masterRoll=0), firstName=studentFirstName, lastName=null, rollNumber=23)
When I parse the json string "json" to the Student class,
Why values not getting passed to "Master.java" inner dto?
I need something like Student(masterName=test1, masterSubjectName=testsubject, masterRoll=534, firstName=studentFirstName,rollNumber=23)

Your 'types' value in #Delegate should be Interface with getter methods for example getMasterName() , getMasterSubjectName... and so on
documentation:
https://projectlombok.org/features/experimental/Delegate

Related

How to add space in expression in MapStruct

I have a requirement to add firstName and lastName from source to fullName in target. I want first & last name to be separated by space. But I am unable to write the proper mapping for it.
My Source and target class-
public class Source {
private int id;
private String firstName;
private String lastName;
private List<String> addressList;
}
public class Target {
private int id;
private String fullName;
private String city;
}
Here is my mapper interface-
#Mapper
public interface SourceTargetMapper {
SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class);
#Mapping(expression = "java(source.getFirstName()+source.getLastName())", target = "fullName")
#Mapping(expression = "java(source.getAddressList().get(0))", target = "city")
Target sourceToTarget(Source source);
#InheritInverseConfiguration
Source targetToSource(Target target);
}
Adding space in middle is giving me error-
#Mapping(expression = "java(source.getFirstName()+" "+source.getLastName())", target = "fullName")
If there is any other solution or any approach for this ?
You will need to escape the quote ".
e.g.
#Mapping(expression = "java(source.getFirstName()+ \" \" +source.getLastName())", target = "fullName")
I found another way to write the Mapping by using decorator pattern as mentioned in the Map Struct documentation by using the decorator pattern.
I will just copy paste the link and example here.
https://mapstruct.org/documentation/dev/reference/html/#customizing-mappers-using-decorators
And here goes the code taken from mapstruct documentation -
#Mapper
#DecoratedWith(PersonMapperDecorator.class)
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper( PersonMapper.class );
PersonDto personToPersonDto(Person person);
AddressDto addressToAddressDto(Address address);
}
public abstract class PersonMapperDecorator implements PersonMapper {
private final PersonMapper delegate;
public PersonMapperDecorator(PersonMapper delegate) {
this.delegate = delegate;
}
#Override
public PersonDto personToPersonDto(Person person) {
PersonDto dto = delegate.personToPersonDto( person );
dto.setFullName( person.getFirstName() + " " + person.getLastName() );
return dto;
}
}

Not able to convert Json String to Java objects

I am unable to convert the given Json String to java Object
Validated the Json format, it is correct.
#JsonIgnoreProperties(ignoreUnknown = true)
public class DevPol {
private String id;
private Header header;
//Setters and Getters
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class Header {
private String name;
private String lastUpdate;
private int priority;
private boolean active;
//Setters and Getters
}
import com.fasterxml.jackson.databind.ObjectMapper;
public class ConvertJsonToJava {
static String apiResult = "[ {\"Id\":\"5899503ad06f7f0008817430\", \"Header\":{ \"name\":\"ClCol\"," +
" \"lastupdate\":\"2017-02-07T04:42:34.654Z\", \"priority\":1, \"active\":true } }," +
" { \"Id\":\"5899503ad06f7f0008817431\",\"Header\":{ \"name\":\"SysPol\"," +
" \"lastupdate\":\"2017-02-07T04:42:34.659Z\", \"priority\":2, \"active\":true } }]";
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
DevPol[] devPOlArr = mapper.readValue(apiResult, DevPol[].class);
for(DevPol devPol: devPOlArr) {
System.out.println(devPol.getId());
}
}
}
I expected the output to be Id values but,the result is
null
null
The issue is upper-case letters in json field names and java class fields.
If it is possible rename 'Id' -> 'id' in json and java. Otherwise you should add json property names to java fields:
public class DevPol {
#JsonProperty("Id")
private String Id;
#JsonProperty("Header")
private Header Header;
//Setters and Getters
}

Java object not populated from json request for inner class

Have searched in different sites but couldn't find correct answer, hence posting this request though it could possible duplicates.sorry for that.
I am sending the below json request to my back-end service and converting to java object for processing. I can see the request body passed to my service but when i convert from json to java object , values are not populating
{
"data":{
"username":"martin",
"customerId":1234567890,
"firstName":"john",
"lastName":"smith",
"password":"p#ssrr0rd##12",
"email":"john.smith#gmail.com",
"contactNumber":"0342323443",
"department":"sports",
"location":"texas",
"status":"unlocked",
"OrderConfigs":[
{
"vpnId":"N4234554R",
"serviceId":"connectNow",
"serviceType":"WRLIP",
"ipAddress":"10.101.10.3",
"fRoute":[
"10.255.253.0/30",
" 10.255.254.0/30"
],
"timeout":1800,
"mapId":"test_map"
}
]
}
}
My Parser class have something like,
JSONObject requestJSON = new JSONObject(requestBody).getJSONObject("data");
ObjectMapper mapper = new ObjectMapper();
final String jsonData = requestJSON.toString();
OrderDTO mappedObject= mapper.readValue(jsonData , OrderDTO .class);
// I can see value coming from front-end but not populating in the mappedObject
My OrderDTO.java
#JsonInclude(value = Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true,value = {"hibernateLazyInitializer", "handler", "created"})
public class OrderDTO {
private String username;
private long customerId;
private String source;
private String firstName;
private String lastName;
private String email;
private String contactNumber;
private String password;
private String department;
private String location;
private String status;
private List<OrderConfig> OrderConfigs;
#JsonInclude(value = Include.NON_NULL)
public class OrderConfig {
private String vpnId;
private String serviceId;
private String serviceType;
private String ipAddress;
private String mapId;
private String[] fRoutes;
private Map<String, Object> attributes;
private SubConfig subConfig;
private String routeFlag;
getter/setters
.....
}
all setter/getter
}
Not sure what I'm missing here. Is this right way to do?
If your are trying to use inner class, correct way to use is to declare it static for Jackson to work with inner classes.
For reference check this
code changes made are
#JsonInclude(value = Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
static class OrderConfig {
Make sure that your json tag names match with variable names of java object
Ex : "fRoute":[
"10.255.253.0/30",
" 10.255.254.0/30"
],
private String[] fRoutes;
OrderConfigs fields will not be initialized, just modify your bean as
#JsonProperty("OrderConfigs")
private List<OrderConfig> orderConfigs;
// setter and getter as setOrderConfigs / getOrderConfigs
See my answer here. (same issue)

Create Object from set of json properties jackson

Please refer below example.
public class Human {
private String name;
private int age;
}
public class Teacher {
private String school;
private Human human;
}
And JSON looks like :
{
"school": "My School",
"age": 20,
"name": "My Name"
}
I want to create Teacher from JSON string which has Human as inner object but should match to same level of JSON properties.
I'm using Jackson API to create java object from JSON.
You can mark the human field as #JsonUnwrapped:
public class Teacher {
private String school;
#JsonUnwrapped
private Human human;
// constructor / setters
}
public class Human {
private String name;
private int age;
// constructor / setters
}
public class Test {
String str = "{ \"school\": \"My School\", \"age\": 20, \"name\": \"My Name\" }";
System.out.println(new ObjectMapper().readValue(str, Teacher.class));
}
That will de-serialize into the format you're looking for.

How can I unwrap a specific field in a JSON using Jackson?

I have a JSON payload that looks like this:
{
"id": 32,
"name": "[Sample] Tomorrow is today, Red printed scarf",
"primary_image": {
"id": 247,
"zoom_url": "www.site.com/in_123__14581.1393831046.1280.1280.jpg",
"thumbnail_url": "www.site.com/in_123__14581.1393831046.220.290.jpg",
"standard_url": "www.site.com/in_123__14581.1393831046.386.513.jpg",
"tiny_url": "www.site.com/in_123__14581.1393831046.44.58.jpg"
}
}
Can I unwrap a specific field and discard all the others? In other words, can I bind this directly to a POJO like this:
public class Product {
private Integer id;
private String name;
private String standardUrl;
}
There are lots of ways. Do you need to deserialize, serialize or both?
One way to deserialize would be to use a creator method that takes the image as a tree node:
public static class Product {
private Integer id;
private String name;
private String standardUrl;
public Product(#JsonProperty("id") Integer id,
#JsonProperty("name") String name,
#JsonProperty("primary_image") JsonNode primaryImage) {
this.id = id;
this.name = name;
this.standardUrl = primaryImage.path("standard_url").asText();
}
}
The creator doesn't have to be a constructor, you could have a static method that is only used for Jackson deserialization.
You'd have to define a custom serializer to reserialize this, though (e.g. a StdDelegatingSerializer and a converter to wrap the string back up as an ObjectNode)
There are different ways to skin this cat, I hope you can use Jackson 2 for this, since it offers great ways to deserialize Json data, one of my favorites deserialization features is the one I'll show you here (using Builder Pattern) because allows you to validate instances when they are being constructed (or make them immutable!). For you this would look like this:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.util.Map;
#JsonDeserialize(builder = Product.Builder.class)
public class Product {
private Integer id;
private String name;
private String standardUrl;
private Product(Builder builder) {
//Here you can make validations for your new instance.
this.id = builder.id;
this.name = builder.name;
//Here you have access to the primaryImage map in case you want to add new properties later.
this.standardUrl = builder.primaryImage.get("standard_url");
}
#Override
public String toString() {
return String.format("id [%d], name [%s], standardUrl [%s].", id, name, standardUrl);
}
#JsonIgnoreProperties(ignoreUnknown = true)
public static class Builder {
private Integer id;
private String name;
private Map<String, String> primaryImage;
public Builder withId(Integer id) {
this.id = id;
return this;
}
public Builder withName(String name) {
this.name = name;
return this;
}
#JsonProperty("primary_image")
public Builder withPrimaryImage(Map<String, String> primaryImage) {
this.primaryImage = primaryImage;
return this;
}
public Product build() {
return new Product(this);
}
}
}
To test it I created this class:
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class Test {
public static void main(String[] args) {
String serialized = "{" +
" \"id\": 32," +
" \"name\": \"[Sample] Tomorrow is today, Red printed scarf\"," +
" \"primary_image\": {" +
" \"id\": 247," +
" \"zoom_url\": \"www.site.com/in_123__14581.1393831046.1280.1280.jpg\"," +
" \"thumbnail_url\": \"www.site.com/in_123__14581.1393831046.220.290.jpg\"," +
" \"standard_url\": \"www.site.com/in_123__14581.1393831046.386.513.jpg\"," +
" \"tiny_url\": \"www.site.com/in_123__14581.1393831046.44.58.jpg\"" +
" }" +
" }";
ObjectMapper objectMapper = new ObjectMapper();
try {
Product deserialized = objectMapper.readValue(serialized, Product.class);
System.out.print(deserialized.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
The output is (using the override toString() method in Product:
id [32], name [[Sample] Tomorrow is today, Red printed scarf], standardUrl [www.site.com/in_123__14581.1393831046.386.513.jpg].
There are two ways to get the response you required. For both methods, we are going to use JsonView.
Create two types of JsonView:
public interface JViews {
public static class Public { }
public static class Product extends Public { }
}
First method
#JsonView(JViews.Public.class)
public class Product {
private Integer id;
private String name;
#JsonIgnore
private Image primaryImage;
#JsonView(JViews.Product.class)
public String getStandardUrl{
return this.primaryImage.getStandardUrl();
}
}
Second way
Using Jackson's #JsonView and #JsonUnwrapped together.
#JsonView(JViews.Public.class)
public class Product {
private Integer id;
private String name;
#JsonUnwrapped
private Image primaryImage;
}
public class Image {
private String zoomUrl;
#JsonView(JViews.Product.class)
private String standardUrl;
}
#JsonUnwrapped annotation flattens your nested object into Product object. And JsonView is used to filter accessible fields. In this case, only standardUrl field is accessible for Product view, and the result is expected to be:
{
"id": 32,
"name": "[Sample] Tomorrow is today, Red printed scarf",
"standard_url": "url"
}
If you flatten your nested object without using Views, the result will look like:
{
"id": 32,
"name": "[Sample] Tomorrow is today, Red printed scarf",
"id":1,
"standard_url": "url",
"zoom_url":"",
...
}
Jackson provided #JsonUnwrapped annotation.
See below link:
http://jackson.codehaus.org/1.9.9/javadoc/org/codehaus/jackson/annotate/JsonUnwrapped.html

Categories