Using Data annotation on Java DTO class - java

I have confusion in using Data annotation to DTO class. Here is my sample class.
#Data
public class MyClass {
private Long id;
private String name;
}
I've read online that using Data annotation specifically on DTO class will allow the values of the fields to be changed by use of the generated setters.
Should I remove the lombok Data annotation? And implement the getters and setters manually.
Thanks :)

I would avoid #Data for DTOs since it has too many pitfalls. First of all as you mentioned it is mutable which you don't really want for a DTO. And despite it being mutable, it implements equals() and hashCode() which is only asking for trouble.
You can use #Value for an immutable DTO. For an incoming DTO you may need to add lombok.anyConstructor.addConstructorProperties to your lombok.config, which will allow libraries like jackson to deserialize to your POJO without a default constructor.

The annotation #Data comes from the Project Lombok which is designed to use reflection via annotations mostly. This annotation assures generation of all the setters, getters, a constructor with all the required arguments and overridden Object::toString, Object::equals and Object::hashCode methods.
Briefly said, this annotation "completes" a simple POJO object and generates all the boilerplate without a need to use IDE.
They named the annotation #Data because they support the idea of the understanding objects as data containers only.
As far as I understand, the generation happens only for the missing getters/setters (let's speak about them for brevity). The generated getters/setters are in their pure form as you know:
public int getId() { return this.id; }
public void setId(int id) { this.id = id; }
You can use more verbose setter/getter performing validation or anything similar which override the generated ones. You can both use #Data annotation and write your ones manually.

DTO is used to transmit data information, some information is actually we do not want users to be able to change or access, such as the user password, we do not want to pass to the front end when the user can see the encrypted password, or we do not want users to modify the password while changing their information, and what works in this serialization process is setter and getter, and data annotations that automatically generate getters and setters for all fields.
For example
#Data
class User{
private String userName;
private String pwd;
}
This class, will have all setter and getter. When you trans to web, you will see
{userName: "123", pwd: "xxx"}
This is terrible.
But if you use DTO
class User{
private String userName;
private String pwd;
public String getUserName(){
return userName;
}
}
They only see
{userName: "123"}

By default the #Data lombok annotation will generate setters and getters for all fields in the class.
If you want an immutable data transfer object, annotate it as #Value instead.
If you want a mixure of some immmutable values and some mutable values in your MyClass type, for instance you might want the id field to be immutable and the rest mutable, you would use the #Setter annotation on the field you want to be immutable, specifying an AccessLevel of NONE. For instance:
#Data
public class MyClass {
#Setter(AccessLevel.NONE)
private Long id;
private String name;
}
This will generate a getter but no setter for the id, and a getter and setter for the name.

Related

How to avoid adding #Valid on each and every inner-class fields during the hibernate-validator?

I am currently developing an application within that I am adding a few validations on an inner class such as #NotNull, #Min, #Max, etc.
To make the validations work I need to add the #Valid on each and every field which is making use of the inner class. Is there a way to avoid adding the #Valid on each and every object rather add some annotations on the Class so it can be applicable to all the fields within that class?
I am currently using the following library to achieve the validations:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator</artifactId>
</dependency>
I tried to add the #Validated on the class but seems like this annotation is not available in this maven dependency. Can someone please let me know what I need to change?
Following is a simple example that is working but I would like to remove #Valid that I have to add on each field. If I do not add #Valid then those inner classes won't be validated.
public class Book {
#NotNull(message="Book ID cannot be NULL")
private int bookId;
#Valid
private List<Author> author;
#Valid
private List<Publication> author;
}
public class Author {
#NotNull(message="Author ID cannot be NULL")
private int authorID;
#NotNull(message="Author Name cannot be NULL")
private String name;
}
public class Publication {
#NotNull(message="Publication ID cannot be NULL")
private int authorID;
#NotNull(message="Publication Name cannot be NULL")
private String name;
}
There is no way to do what you want to do, except if you write your own Quarkus extension that will add the annotations at build time.
It will be some rather involved work, though, as you will need to add some bytecode transformation to add the annotations where you want them.
Also, you should add the #Valid annotations inside the List e.g. List<#Valid Publication> rather than at the field level. It's more optimized this way.

How to overcome the FCBL_FIELD_COULD_BE_LOCAL issue in FindBugs?

In FindBugs, I am getting an issue like FCBL_FIELD_COULD_BE_LOCAL on the class name line of this code:
#Entity
#Table(name = "Student")
#Immutable
#Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class RetrievableStudent extends BaseStudent
{
#Id
#Column(name = "STUDENT_ID")
private long studentId;
#Column(name = "STUD_NOTE")
private String studenetNote;
}
How can I resolve this issue?
In order to resolve that issue you need to use you fields somewhere in your class. What FindBugs is telling you is that your fields in your class are never used as the fields.
How you using your fields that were retrieved from database? Maybe you need to add getters? For now, your fields are useless (unless you don't using them with reflection, which is not good).
My POJO has already getters setters, equals, hashcode.
It worked when I tried adding #JsonProperty annotation, as my POJO is built for API response purposes.
If the POJO is for ORM purposes (means database entity) the on getters and setters #Column annotation should work.

How to impose common constraint on class with javax.validation library?

I am using Bean Validation constraints to validate class instances at run time. I have many DTOs where each has multiple fields often with a common constraint. I want to add a constraint to the class so that it applies to all the properties of the class. (As lombok #NotNull constraint).
e.g
class Person {
#NotNull
private String name;
#NotNull
private String address;
#NotNULL
private String contact;
}
I want to make it something like this.
#NotNull
class Person {
private String name;
private String address;
private String contact
}
You cannot do this with plain Bean Validation. So just adding #NotNull to the class won't work.
One potential approach could be to utilize XML configuration. The idea would be to have your own annotation MyNotNull. Your framework would need to scan for these annotations and build the programmatic configuration for the class in question. This could for example be done via a annotation processor during compile time. Once you have the constraint mapping XML files add them to your jar and reference them in validation.xml. That's just a basic idea. Personally, I am not sure whether it is worth the effort.

Java JPA implementation - how are properties read/set?

I am reading the Beginning Java EE6 Platform and Glassfish 3 book and I have some minor difficulties at understanding Access type on field/properties. What is the difference between the two of them?
Is it how the properties are read/set by the JPA implementation (in this case EclipseLink)? Like, if it is property access the values are read/set through possible validations etc that can be placed in the get/set method, while the field access option does not do setting/getting values through these methods but straight on the fields? And does the type get set by where I am placing the #Id annotation?
The #Access annotation type indicates how the JPA should set or get the field in your object. An AccessType.FIELD the JPA will set the field directly with reflection and will not use any provided setter method., very useful if your class tracks the "dirtyness" of a field through the setter methods. In contrast setting #Access(value=AccessType.PROPERTY) will instruct the JPA to use the setter and getter methods when it accesses fields.
You can prove this to yourself by adding logging or System.out.printlns to your setter methods and then making changes to the #Access annotation. For example:
#Id
#Access(value=AccessType.PROPERTY)
private Long Id;
public void setId(Long id) { System.out.println("SET"); this.Id = id; }
Will print SET and this:
#Id
#Access(value=AccessType.FIELD)
private Long Id;
public void setId(Long id) { System.out.println("SET"); this.Id = id; }
Will NOT!
It also does not matter where you place the annotations, at least in Hibernate ;-).

What is the best approach to write a data access object (DAO)?

I was trying to write a user authentication system in Java. So I wrote some DAO class. First I did write a class named Persistence which is abstract. It is responsible for holding some common attributes. And wrote a class named User extending Persistence class. Those classes are –
public abstract class Persistance {
private Date createdDate;
private Date lastUpdatedDate;
private long version;
private boolean isDeleted;
//getter and setters
}
and the user class
public class User extends Persistance{
private String username;
private String password;
private String passwordConfired;
// getters and setters
}
My questions are- what is the best way to write variable name, which one is good, createdDate or dateCreated, deleted or isDeleted etc.
And is this approach is okay or is there more good approach ?
And how to implement data versioning?
To write a DAO, typically you create an interface that defines the behavior of the DAO.
interface MyObjDao {
public int save(MyObj myObj);
public void delete (MyObj myObj);
// as many methods as you need for data acess
}
and then you create the actual implementation
class MyObjDaoImpl implements MyObjDao {
// implement methods here
}
The advantages of this are:
1) Because you define an interface, mocking DAOs is easy for any testing framework
2) The behavior is not tied to an implementation -- your DAOImpl could use jdbc, hibernate, whatever
Your Persistance class is really a base class for all entities -- i.e. all classes instances of which get saved, where you want to represent some common fields in one place. This is a good practice -- I wouldn't call the class Persistance, something like BaseEntity is better (IMHO). Be sure to have javadocs that explain the purpose of the class.
With respect to variable names, as long as they make sense and describe what they are for, its good.
so dateCreated or createdDate are both fine; they both get the idea across.
You are mixing a DAO (data access object) and a VO (value object) - also known as a DTO (data transfer object) - in the same class.
Example using an interface for DAO behavior (blammy and kpow might be webservice, oracle database, mysql database, hibernate, or anything meaningful):
public interface UserDTO
{
boolean deleteUser(String userId);
UserVO readUser(String userId);
void updateUser(String userId, UserVO newValues);
}
package blah.blammy;
public class UserDTOImpl implements UserDTO
{
... implement it based on blammy.
}
package blah.kpow;
public class UserDTOImpl implements UserDTO
{
... implement it based on kpow.
}
Example VO:
public class UserVO
{
String firstName;
String lastName;
String middleInitial;
... getters and setters.
}
I prefer to identify the target of the delete using an ID instead of a VO object. Also, it is possible that an update will change the target identified by user ID "smackdown" to have user ID "smackup", so I generally pass an id and a VO.
A good approach would be to use JPA with all of its features, this tutorial was really helpful.
It explains how to use the #PrePersist and #PreUpdate annotations for setting create and update timestamps. Optimistic locking is supported by the #Version annotation.
My questions are- what is the best way to write variable name, which
one is good, createdDate or dateCreated, deleted or isDeleted etc.
createdDate or dateCreated is very subjective. In databases, I have mostly seen createdDate though. Between deleted and isDeleted, I prefer (again subjective) deleted. I think the getter method can be named isDeleted().

Categories