I am developing a RESTful API in Spring Boot 2+, for which I need to perform several validations. Nothing really fancy, just the typical #NotNull, #NotEmpty, #Max, #Min, #Email, #Regex, #Future, etc stuff...
Except that I have beans from an API that I must use yet cannot modify. This means that I cannot annotate the fields and methods in those DTOs.
It would be great if I could create mixin-like classes or interfaces with the same structure of the real DTOs I must use in the API, on which I would happily place bean-validation's annotations.
For example, if I had the following DTOs that I couldn't modify:
public class Person {
private String name;
private String dateOfBirth;
private Address address;
// constructors, getters and setters ommited
}
public class Address {
private String street;
private String number;
private String zipCode;
// constructors, getters and setters ommited
}
I would create the following 2 interfaces that mimic their structure and annotate them as I need:
public interface PersonMixin {
#NotBlank String name();
#Past String dateOfBirth();
#Valid #NotNull Address address();
}
public interface AddressMixin {
#NotBlank String street();
#Positive int number();
#NotBlank String zipCode(); // Or maybe a custom validator
}
As you see, the name of the methods in the interfaces match the names of the properties of the bean classes. This is just one possible convention...
Then, ideally, somewhere while the app is loading (typically some #Configuration bean) I would be very happy to do something along the lines of:
ValidationMixinsSetup.addMixinFor(Person.class, PersonMixin.class);
ValidationMixinsSetup.addMixinFor(Address.class, AddressMixin.class);
Except that ValidationMixinsSetup.addMixinFor is pure fantasy, i.e. it doesn't exist.
I know that there exists a similar construct for Jackson regarding JSON serialization/deserialization. I've found it extremely useful many times.
Now, I've been looking at both Spring and Hibernate Validator's source code. But it's not a piece of cake... I've dug into ValidatorFactory, LocalValidatorFactoryBean, TraversableResolver implementations, but I haven't been able to even start a proof-of-concept. Could anyone shed some light into this? I.e. not how to implement the whole functionality, but just how and where to start. I'm after some hints regarding which are the essential classes or interfaces to extend and/or implement, which methods to override, etc.
EDIT 1: Maybe this approach is not the best one. If you think there's a better approach please let me know.
EDIT 2: As to this approach being overly complicated, too convoluted, Rube Goldberg, etc, I appreciate and respect these points of view, but I'm not asking whether validation through mixins is good or bad, convenient or inconvenient, neither why it might be like so. Validation through mixins has pros on its own and I think it could be a good approach for some valid use cases, i.e. having declarative validation instead of scripted or programmatic validation while also separating validation from the model, letting the underlying framework do the actual validation job while I only specify the constraints, etc.
Using programmatic API (as mentioned in the comment) in case of Person you could apply next mappings for your constraints:
HibernateValidatorConfiguration config = Validation.byProvider( HibernateValidator.class ).configure();
ConstraintMapping mapping = config.createConstraintMapping();
mapping.type( Person.class )
.field( "name" )
.constraint( new NotNullDef() )
.field( "number" )
.constraint( new PositiveDef() )
.field( "address" )
.constraint( new NotNullDef() )
.valid();
Validator validator = config.addMapping( mapping )
.buildValidatorFactory()
.getValidator();
And as you are using Spring - you would need to do that in one of your sping config files where you define a validator bean.
Related
I have two APIs referencing the POJO class below.
class Data{
private String name;
private String age;
private String address;
private String phone_number;
}
I need to annotate the fields in this POJO as below.
class Data
{
#JsonProperty(required = true)
private String name; // required field
#JsonProperty(required = true)
private String age; // required field
#JsonInclude( Include.Non_Null)
private String address; // optional field
#JsonIgnore
private String phone_number; // ignore field
}
The annotations need to be applied to only one of API.The other API should not be impacted by this change.
One way of achieving this is to create two separate POJOs, one for each API. But is it possible to achieve the results using the same POJO classes? Is there a way to configure the annotations based on which API is being invoked?
Some repetition is not bad especially if they're used for two different purposes.
Ideally these would be in two different packages as well. That way, you don't have a name clash.
If you want to avoid but I do not recommend it is have
class RequiredData extends Data {
#JsonProperty(required = true)
void setName(String name) {
super.setName(name);
}
}
The annotations need to be applied to only one of API.The other API
should not be impacted by this change.
One way of achieving this is to create two separate POJOs, one for
each API. But is it possible to achieve the results using the same
POJO classes? Is there a way to configure the annotations based on
which API is being invoked?
You can create a library containing the classes that two APIs to have to share and introduce it in both APIs as a dependency.
That would allow to ensure both parts of your System will have the same definition of these domain classes.
Note: you need to have a strong reason for doing so. Because there was a reason to implement them as independent APIs and introducing this dependency creates a coupling between them. If there would be a considerable amount of such classes, then as a consequence APIs would not be able to evolve independently.
What do you think about have persistence models and domain models separated? I've read that you don't have to mix persistence concerns with your business concerns (DDD, Clean Architecture,MartinFowler, Eric Evans and a lot and a lot of much more). Even so, I still see in all projects domain models annotated directly with ORM annotations like that, being the domain model coupled to the persistence mechanism reaching an anemic model and violating other principles.
//PersistenceJPA entity
#Entity
#Table(name="training_cycle")
class TrainingCycle {
#Id
private Long id;
private String name;
#Column(name="discipline_id")
#JoinColumn(name="discipline_id")
private Long disciplineId; //Referencing by Id because Discipline is another Aggregate ROOT
//EmptyConstructor, getters and setters avoided
}
//PersistenceJPA entity
#Entity
#Table(name="training_cycle")
class Discipline {
#Id
private Long disciplineId;
private String name;
//EmptyConstructor, getters and setters avoided
}
So if you want to follow clean principles you need to split Domain and Persistence Model(as shown below)to have Domain model with business behavior(this avoid anemic model and follows the SRP) and because of that you need to map the domain model to the persistence model (with typical methods like mapToEntity(DomainModel DM) and mapToDomain(PersistenceModel PM) maybe in a mapper/tranformer maybe in the repository class) when you want to interact with Datastore and viceversa when you want to retrieve data from database.
class Discipline {
private DisciplineId disciplineId;
private String name;
public Discipline(DisciplineId disciplineId, String name) {
this.disciplineId = disciplineId;
this.name = name
}
}
public class TrainingCycle{
private TrainingCycleId trainingCycleId;
private String name;
private DisciplineId disciplineId;
public TrainingCycle(TrainingCyleId trainingCycleId, String name, DisciplineId disciplineId) {
this.trainingCycleId = trainingCycleId;
this.name = name;
assignDiscipline(disciplineId);
}
public void assignDiscipline(DisciplineId aDisicplineId) {
if(aDisicplineId == null) {
throw new IllegalArgumenException("Discipline cannot be null")
}
this.disciplineId = aDisicplineId;
}
}
#Entity
#Table(name="training_cycle")
class TrainingCycleJpa {
#Id
private Long id;
private String name;
#Column(name="discipline_id")
#JoinColumn(name="discipline_id")
private Long disciplineId; //Referencing by Id because Discipline is another Aggregate ROOT
//EmptyConstructor, getters and setters avoided
}
#Entity
#Table(name="training_cycle")
class DisciplineJpa {
#Id
private Long disciplineId;
private String name;
//EmptyConstructor, getters and setters avoided
}
class TrainingCyleJpaRepository implements TrainigCycleRepository {
public void create(TrainingCycle trainingCycle) {
entityManager.persist(this.mapToEntity(trainingCycle)
}
public TrainingCycle create(TrainingCycleId trainingCycleId) {
return this.mapToDomain(entityManager.find(TrainingCycleId));
}
}
So the discussion/question is Split or not Split Persistence Model from Domain Model? When to split or when not? In the most projects, not to say in all the ones I've seen as an example, I've seen they couple annotations of persistence model in Domain Model when "gurus are allways hawking" DataStore is a detail.
Thanks a lot.
Please check out this very similar question: Are persistence annotations in domain objects a bad practice?
I think that as engineers we should be pragmatic. Any best practices, principles, or "guru suggestions" should help. They should not make things worse. So I suggest to treat them as guidance, not strict rules. For instance, I generally agree that "database is a detail". But we rarely change that detail.
On the other hand, annotations do not execute any code. And the coupling is not so bad. Your domain object can be a JPA entity at the same time, and it will be very clean and useful. By the way, this does not violate the Single Responsibility Principle (SPR). If you thought it does, check out SOLID explanation by its author Uncle Bob
EDIT
#RenéLink I don't agree: Annotations are interpreted and the code that executes them can be exchanged with a different interpreter even with a no-op interpreter. The annotation stays untouched and doesn't care. It's a declarative element, nothing more.
Annotations are source code dependencies, which means that the source code can not be compiled if the annotation is not present on the compile classpath.
It's right that annotations are not hard runtime dependencies. If the annotation class is not available on the classpath the annotation is also not available. Thus you can use bytecode that was compiled with annotations even if the annotations are not present on the classpath.
So annotations are a less restrictive dependency then normal classes, interfaces and so on.
I always try to minimize the dependencies in my code. Let's take a spring example.
In spring you can either implement InitializingBean or you can define a method annotated with #PostConstruct in this case I would use post construct. Often I don't need a #PostConstruct, because I do constructor injection. But if I move the initialization to a java config I can just call an arbitrary 'post construct' method befor returning the bean instance and I don't need a #PostConstruct annotation at all.
I agree that annotation dependencies are less problematic than other classes or interfaces. But keep in mind that the annotations the OP talks about also have another problem. If you mix domain objects with JPA annotations you violate the single responsibility principle. Your domain objects now have more then one reason to change (domain changes and persistence changes).
You will recognize the problem as soon as you add #Transient annotations or you might get merge conflicts because you changed domain logic and a colleague persistence things.
Yes, these annotations are details and should be kept away from the entities of the clean architecture.
Don't be confused about the name entity in the clean architecture and the #Entity annotation from your persistence framework. They are different things.
There is a video of Uncle Bob about clean architecture and at the end he makes it really clear, because he says:
the entities are not instances of database tables. They are usually constructions from many database tables.
In another video he talks about dependency injection and the annotations that these frameworks use. Well, dependency injection has nothing to do with persistence that you asked for, but this video makes clear what Uncle Bob thinks about framework annotations in the use case or entities layer of the clean architechture.
And in this video he makes it really clear that the entities should not have persistence details. It doesn't matter if it is hibernate or JPA.
Is there any approach to convert entity to dto object partially? Or are there any best practices for using the entity, pojo/dto and response object in MVC pattern?
You have couple of approaches. I assume you have a web project.
Manual mapping approach. Create Dto map it manually to your entity. This would involve all the boilerplate code around it - Builders, all argument Constructor, getters, setters whatever approach you will use to populate the DTO.
The different hydration Technics apply in different situations. Builder pattern presumes you would have an immutable objects. Getters and Setters are supported out opf the box by frameworks as Jackson. You may decide to minimize your boilerplate code by using lombok, imutables or other frameworks.
Mapping framework. Another option would be to use a supplied mapper like ObjectMapper, or FastMap there may be other choices. This would remove large portion of manual mapping you would need to establish following aproach 1.
Deserializer. Example of such aproach would be spring-data-rest where your repository returns the entities straight which are than serialized in JSON . Using normal spring MVC this would be to return your entity straight to your controller layer and based on annotations or other means (serializers) map it to your network format JSON, XML whatever you use.
These are the different options. Which one is best depends on your usecase.
One of possible approaches is copy constructor. The example below.
// entity annotations ...
public class EntityExample {
private Long id;
private String name;
private Integer score;
// getters and setters ...
}
public class DtoExample {
private Long id;
pricate String name;
// For serialization and deserialization
public DtoExample() {
}
public DtoExample(EntityExample entity) {
this.id = entity.getId();
this.name = entity.getName();
}
// getters and setters ...
}
spring-data-rest makes it possible to expose #Entity domain objects directly and even provide a DTO projection as follows:
#Projection(name = "personDTO", types = { Person.class })
public interface PersonDTO {
#Value("#{target.firstName} #{target.lastName}") //SPeL
String getFullName();
}
Question: what if I want to construct only some of the dto fields myself? Eg having some kind of condition on the firstname field, and fill it based on this either the one or other way. Is that possible?
Spring mentions a example, but unfortunately it's not complete:
https://spring.io/blog/2014/05/21/what-s-new-in-spring-data-dijkstra
#Projection(name = "summary", types = Order.class)
interface OrderSummary {
#Value("#{#shop.calculateTotal(target)}")
Money getTotal();
}
Here the logic is exported to #shop.calulcateTotal(), BUT they don't tell in the example how this #shop bean is injected here. I assume this is a #Service, but don't know how to get it in.
Says right below the example you posted.
https://spring.io/blog/2014/05/21/what-s-new-in-spring-data-dijkstra
For advanced use cases you can even equip the projection methods with #Value to return the result of a SpEL expression to the marshaller. In our sample here, we invoke a method on a Spring bean named shop and hand the proxy target instance to it to calculate the order total, which could consider rebates, taxes etc.
Since your projections are already managed by spring, you don't really need to inject it. Spring magic takes care of it for you.
The question is where it is better (or in other words: where do you prefer) to put business validation logic of Jpa Entities.
Two ideas are:
In the EntityListener that before save or update would validate the entity
In the service that provides access to jpa persisting methods.
There are pros and cons of both.
When using approach No. 2 it is easier to test as you may just mock the jpa provider and test the validation logic. On the other hand with approach No. 1 the validation would happen at the same moment with validations like #NotNull etc.
I would love to know how do you solve validations in your projects and which is the better way to go.
Thanks.
Here's a general thumb rule that I follow:
When using bean validation, specify
rules that do not require dependencies
on other beans. The moment you depend
on another bean, get your service
layer to handle that dependency.
In other words, if you have a reference to a bean inside another, avoid putting in that #NotNull constraint. Your service layer is best used for that, for you're catching the violation much earlier, and at a more logical point (since other business validations would assume that the beans are available).
As an example, consider the following entity (apologies for it wont compile)
#Entity
public class User
{
#Id
private int id;
#NotNull
private String fullName;
#NotNull
private String email;
private Set<Role> roles; //No bean validation constraints here.
...
public boolean mapRoleToUser(Role role)
{ //Validation is done here. Including checks for a null role.
}
}
#Entity
public class Role
{
#Id
private int id;
#NotNull
private String name;
}
The service layer in this case, is the one that should validate whether the user has a role attached or not. Verification in the pre-persist or pre-update phase is a bit too late, especially when there is a distinct service layer that has business logic, and the rest of the business logic in the domain model (sadly, I haven't seen a good enough application with all of the logic in the domain model alone).