Change condition of object with out setters - java

I have object of following class:
#Jacksonized
#Builder
#Getter
public class Request {
private String id;
private String city_id;
private String country_id;
private List<String> product_id;
}
This class doesn't have setters, but does have #Builder. I don't want to build a new object. I need to replace following List with another List:
private List<String> product_id;
How can I change condition of the current object?
Should I use ReflectionUtils or is there something else better?

Related

How to save enum variable to DB (instead enum value itself)

I wonder if it's posible to map Enum VARIABLE and DB. I want to save in database the yellow values (variables of enum)
The enum is used in this class:
#Getter
#Setter
#Table(name = "TIPOS_MOVIMIENTO")
#Entity
public class TipoMovimiento {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column
#Enumerated(EnumType.STRING)
private TipoMov tipo;
public String getTipo() {
return tipo.getTipoNombre();
}
#OneToMany(mappedBy = "tipoMov")
private List<Movimiento> movimientos;
My DTO class:
#Getter
public class TipoMovimientoDto implements DtoEntity {
private TipoMov tipo;
}
I've tried DTO with
#Convert(converter = TipoMovEnumConverter.class)
private TipoMov tipo;
But it doesn't works
Write an AttributeConverter for your enum which will convert your enum data into it's value when store in database.
#Converter(autoApply = true)
public class TipoMovConverter implements AttributeConverter<TipoMov, String> {
#Override
public Integer convertToDatabaseColumn(TipoMov attribute) {
return attribute.getTipoNombre();
}
#Override
public TipoMov convertToEntityAttribute(String value) {
return value == null ? null : TipoMov.findByValue(value);
}
}
Note: Here findByValue is a static method to get enum from value string
0
I got it!!! I never thought this would work.
#Getter
public class TipoMovimientoDto implements DtoEntity {
private TipoMov tipo;
}
I just changed in the code above (Dto):
private TipoMov tipo;
to
private String tipo;
I can't explain how Enum from Entity could have been converted to DTO, using String instead Enum... But that worked!
In case you have the same problem... you need to use Attribute Converter (you can see it in the answer of #User - Upvote don't say Thanks)
Is still necessary to use it in Entity class, above of the enum variable:
#Convert(converter = TipoMovEnumConverter.class)
But not necessary in DTO. Just use String instead Enum in DTO!

Is which the best request parameter mapping strategy in Spring Framework?

I am Java web developer, usually develop Spring MVC.
I have been using #RequestMapping or #RequestParam for mapping to hashMap at Controller.
It is a terrible way. I should always cast type when using value.
But nowadays I try to use #ModelAttribute to write clean code at Controller.
However, there are some problem.
case 1) make DTO for each EndPoint.
We can make DTO for each EndPoint, but DTO will have many duplicated property.
#Getter
#Setter
#ToString
class GetUserInfoDTO {
private String id;
private String name;
}
#Getter
#Setter
#ToString
class PostUserInfoDTO {
private String name;
private Integer age;
private String address;
private String gender;
private String email;
private Date joinDate;
}
in controller,
#GetMapping("/user")
public ResultDTO getUserInfo (#ModelAttribute GetUserInfoDTO){
...
return ResultDTO;
}
#PostMapping("/user")
public ResultDTO postUserInfo (#ModelAttribute PostUserInfoDTO){
...
return ResultDTO;
}
In this case, we can apply independent validation strategy for each End-Point.
for example..
#Getter
#Setter
#ToString
class GetUserInfoDTO {
#NotNull
private String id;
private String name;
}
#Getter
#Setter
#ToString
class PostUserInfoDTO {
#NotNull
private String name;
#NotNull
private Integer age;
#NotEmpty
private String address;
private String gender;
private String email;
private Date joinDate;
}
like this.
But so many model classes made, and so many duplicated property exists.
case 2. make common DTO for each Controller.
We can make DTO for each Controller, and reuse them.
#Getter
#Setter
#ToString
class UserInfoDTO {
private String id;
private String name;
private Integer age;
private String address;
private String gender;
private String email;
private Date joinDate;
}
#GetMapping("/user")
public ResultDTO getUserInfo (#ModelAttribute UserInfoDTO){
//I want only id, name
...
return ResultDTO;
}
#PostMapping("/user")
public ResultDTO postUserInfo (#ModelAttribute UserInfoDTO){
...
return ResultDTO;
}
But In this case, we can only pass specific properties.
If someone send other parameter than id and name, we can't notice. ( 400 error not occur )
Code assistance can't recommend us specific properties that use at single end-point.
I don't like these cases.
In first case, I should make so many models and It's management will be so hard.
Second case, unnecessary properties exists and it hard to validate for each end-point.
Which way is the best?
Or Can you recommend another way for mapping request parameter to model object?

How to create different JSON output for a complex object

I would like to generate different Json output for the same complex Java object depending on the use case.
For example check the following code:
class Employee {
private Long id;
private String name;
private EmployeeDetail detail;
private Department department;
...
}
class Department {
private Long id;
private String name;
private String address;
...
}
class EmployeeDetail {
private Long id;
private int salary;
private Date birthDate;
...
}
If I convert Employee to Json all of the fields from Employee, EmployeeDetail and Department will be present. And it is good for one use case.
However in the second use case I would like to skip Department details except the id field but keep the complete EmployeeDetail.
I know that I can add something similar #JsonView(EmployeeView.Basic.class) to the id field in the Department class and use Json views. However for cleaner code I would like to solve it inside the Employee class something like this:
class Employee {
private Long id;
private String name;
#JsonAllFields
private EmployeeDetail detail;
#JsonIdOnly
private Department department;
...
}
At the moment I use the Jackson library but can switch if required.
i think you can use com.fasterxml.jackson.annotation.
#JsonIgnore is used to ignore the logical property used in serialization and deserialization. #JsonIgnore can be used at setter, getter or field. You can use it in the fields in Department class except on ID. There are so many ways to do it. Either you can allow the only getter in serialization etc.
Example:
#JsonIgnore(false)
private String id;
OR
#JsonIgnoreProperties({ "bookName", "bookCategory" })
public class Book {
#JsonProperty("bookId")
private String id;
#JsonProperty("bookName")
private String name;
#JsonProperty("bookCategory")
private String category;
}
To know more about it, please refer: https://www.concretepage.com/jackson-api/jackson-jsonignore-jsonignoreproperties-and-jsonignoretype
I hope this helps.
Just found a solution using #JsonFilter
Now the Employee class looks like this:
class Employee {
private Long id;
private String name;
private EmployeeDetail detail;
#JsonFilter("departmentFilter")
private Department department;
...
}
And the code to generate the limited json looks like this:
ObjectMapper mapper = new ObjectMapper();
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider.addFilter("departmentFilter", SimpleBeanPropertyFilter.filterOutAllExcept("id"));
mapper.setFilterProvider(filterProvider);
One small cons is that now I also need to define the filter to generate the full, detailed json like this:
filterProvider.addFilter("departmentFilter", SimpleBeanPropertyFilter.serializeAll());

Lombok builder override default constructor

I was setting the value of recordId from the child classes using the default constructor and was not using lombok #Builder initially. Eventually i decided to use the Builder here, but the problem now is lombok Builder overrides my default constructor internally hence the value is never set.
How can I put any hook too make lombok #Builder use my default constructor?
Parent class:
#Getter
#Setter
public abstract class Record {
private String recordId;
}
Child class:
#Getter
#Setter
#Builder
#ToString
#AllArgsConstructor
public class SRecord extends Record {
private static final String RECORD_ID = "REC001";
private String street;
private String city;
public SRecord() {
setRecordId(RECORD_ID); //value of recordId being set
}
}
Lombok's #Builder simply does not use the default constructor. It passes its values to an all-args constructor so that this constructor can fill the new instance with these values. #Builder does not use setters or direct access to the fields to do so. So your default constructor is simply ignored by #Builder.
What you can do is write your own all-args constructor. In it, you set your value for recordId and assign the rest of the fields from the parameters.
I think you should create a constructor in your base class:
#Getter
#Setter
public abstract class Record {
private String recordId;
public Record(String recordId) {
this.recordId = recordId;
}
}
Then use it in the constructor of the inherited class:
#Getter
#Setter
#Builder
public class SRecord extends Record {
private static final String RECORD_ID = "REC001";
private String street;
private String city;
public SRecord(String street, String city) {
super(RECORD_ID);
this.street = street;
this.city = city;
}
}
P.S. If you want to use Lombok Builder with inheritance you can use this technique.

Null fields when I use #JsonProperty for retrieve object from MongoDB by Spring data

I have some problem with Spring JPA, MongoDB and Jackson when I use #JsonProperty to use a different name for the json/db and java field.
I receive json and save them into collections, for example
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Document(collection="message")
public class Message implements java.io.Serializable{
private static final long serialVersionUID = 1L;
#Id
private String id;
#JsonProperty("raw")
private Raw raw;
#JsonProperty("meta")
private Meta meta;
}
with Raw :
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Document(collection="raw")
public class Raw {
private String dlc;
#JsonProperty("can_id")
private String canId;
#JsonProperty("can_data")
private String canData;
}
I'm using lombok for the get,set and constructor. I had the message into database before change the field name (using for instance canData instead of can_data) and when I retrieved the object from database this renamed fields were null. So I removed the message and stored again and finally work, I made this because into mongodb I see _class:"com.domain.Message".
This is the first problem: every time I change my java class all the stored data give me this problem?
But I have problem even with manually inserted json into Mongodb: the fields where I use #JsonProperty are null when I make the query like this:
#Query("{ 'can_id' : ?0 }")
Severity findByCanId(String canId);
Severity is so:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Document(collection="severity")
public class Severity implements java.io.Serializable{
private static final long serialVersionUID = 1L;
#JsonProperty("can_id")
#Indexed
private String canId;
#JsonProperty("can_name")
private String canName;
private Integer ss;
private Integer ps;
private Integer fs;
private Integer os;
}
The query return me a Severity object with canId and canName null.
Do you know how can I fix this problem? Thanks
For the name of field into database I fix using #Field("can_id") but the problem about the changing of java class stil present
You should replace #JsonProperty with #BsonProperty

Categories