Annotations in domain objects with JPA violates Database is a detail - java

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.

Related

Persisting nested or related objects for testing created with builder pattern and JPA/Hibernate

Let's take the following classes which are a simplification of more complex classes and their relationships.
#Data
#Builder
public class UserAccount {
private String username;
private String password;
private Language contactLanguage;
public static UserAccount.UserAccountBuilder defaultUserAccount() {
return UserAccount.builder()
.username("default_username")
.password("default_password")
.contactLanguage(defaultLanguage().build());
}
}
#Data
#Builder
public class Language {
private String name;
private String iso2;
private String iso3;
public static Language.LanguageBuilder defaultLanguage() {
return Language.builder()
.name("default_language_name")
.iso2("default_iso2")
.iso3("default_iso3");
}
}
Using Lombok's #Builder annotation, I can easily construct an object like this, especially for testing:
UserAccount.builder()
.username("foo")
.password("bar")
.contactLanguage(Language.builder()
.name("English")
.iso2("EN")
.iso3("ENG")
.build())
.build();
// Or even like this...
defaultUserAccount().build();
This works fine for unit tests or any tests where such generated objects are only required to exist in memory.
However I'd also like to use this approach for integration tests with an underlying database (using Spring Boot 2.4 + JPA + Hibernate). And this is where some issues come up I couldn't solve so far. Let's have a look:
Each UserAccount needs to have a contactLanguage, but Language lives on its own. Other entities might use it as well. When constructing a user account with defaultUserAccount().build(), then persisting this entity fails because the Language object has not been persisted yet. There is no persist cascade on contactLanguage because I don't want "any" Language being created upon creating a UserAccount.
My only idea would be to use defaultLanguage().build() and persist this before defaultUserAccount().build(). But I feel that this will become complex and flaky as soon as there are more levels of nested builders or relationship to other entites.
Another thing is: Even if I managed to persist the defaultLanguge, I would run into a collision as soon as another test calls defaultUserAccount().build() because then the langauge already exists and cannot be inserted again.
Are there any patterns or approaches for persisting such test data objects?
Update #1
After more searching, I found this question on SO which looks almost identical.

Do you directly pass hibernate / jpa entity-objects via http or is there an better alternative?

first of all I want to state that I'm fairly new to this JPA / Hibernate thing and also micronaut is new for me (I have much experience in for example PHP, Python, "Desktop Java", C++ and so on).
I cannot get rid of the feel that I'm misunderstanding something in the concept when I'm passing entities via the micronaut #Body annotation as they come in detached and I have to merge them into the persistence context manually using em.merge(entity).
Please consider the following example (shortened to just show the important portions):
MyEntity.java:
import javax.persistence.*;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
#Entity
#Table(name = "entities")
#Getter
#Setter
#ToString
public class Entity{
#Id
#Column
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
#Column
protected String name;
}
MyController.java:
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.*;
#Controller("/entities")
public class EntitiyCrudController {
#Inject
private final EntityManager entityManager;
#Post("/create")
public HttpResponse create(#Body Entity entity) {
try {
entity = entityManager.merge(entity);
return HttpResponse.ok(entity);
} catch (ConstraintViolationException exception) {
return HttpResponse.badRequest();
}
}
}
Please note that the samples are just copied together, so there might be some errors, but I think this is more a question that is about the right approach to choose.
During my research all examples I've seen so far are about persisting entities that are not detached. Sometimes I've seen people using DTOs (exact copies of the entity classes on the property level but without the jpa / hibernate annotations). I think this approach also have some smell as I have to build a whole new class which has the exact same properties.
I would have no big problem using DTOs if there weren't the transfering of the properties of the dto to the entity (calling dto getter, calling entity setter). Is there a "clean" way to do this without transfering every property manually (maybe some reflection based library or an annotation processor). Then I could load an entity from the persistence context via the dto id and then update my entity fields and trigger an update.
In summary my problems are:
- Passing Entities directly is leading to the entities being detached (So for example the micronaut- data package cannot do updates this way)
- Using DTOs one ends up copying property by property which is very verbose
So which is the right way posting an object via json to a webserver and saving or updating it?
If something isn't understandable I'm happy to clarify it!
IMO DTO approach is the way to go ahead when passing data to UI layer from persistence layer.
Try using Dozer entity copier (https://www.baeldung.com/dozer). This will help you reduce lot of boiler-plate code of copying from one entity to another.
The approach you describe has nothing wrong by itself. But you have to be aware what you are doing, you are coupling your rest interface with your DB implementation. Deppending on your requirements this will probably be a problem. For instance, if your application need Optimistic Concurrency, you will need to add a #Version field in your entity, and you will automatically expose this information through the web service.
Generally you want to have control over the data that is exposed and generally you want to decouple the DB implementation of the rest API. And by the way, generally you also want to have a domain object with business logic for validation, business rules...

Mapping JSON object to Hibernate entity

I'm going to start a project of a REST application managed with Spring and with Hibernate for my model.
I know that Spring allows you to get Java object from the HTTP Request (with #Consumes(JSON) annotation). Is there any conflict if this Java object is also a Hibernate entities? And is nested object working (like #ManyToOne relation)?
Maven dependency
The first thing you need to do is to set up the following Hibernate Types Maven dependency in your project pom.xml configuration file:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
Domain model
Now, if you are using PostgreSQL, you need to use the JsonType from Hibernate Types.
In order to use it in your entities, you will have to declare it on either class level or in a package-info.java package-level descriptor, like this:
#TypeDef(name = "json", typeClass = JsonType.class)
And, the entity mapping will look like this:
#Type(type = "json")
#Column(columnDefinition = "json")
private Location location;
If you're using Hibernate 5 or later, then the JSON type is registered automatically by the Postgre92Dialect.
Otherwise, you need to register it yourself:
public class PostgreSQLDialect extends PostgreSQL91Dialect {
public PostgreSQL92Dialect() {
super();
this.registerColumnType( Types.JAVA_OBJECT, "json" );
}
}
The JsonType works with Oracle, SQL Server, PostgreSQL, MySQL, and H2 as well. Check out the project page for more details about how you can map JSON column types on various relational database systems.
Yes, this wouldn't be a problem and is actually a fairly common practice.
In the recent years I have come to realize that sometimes, however, it is not a good idea to always build your views based on your domain directly. You can take a look at this post:
http://codebetter.com/jpboodhoo/2007/09/27/screen-bound-dto-s/
It is also known as "Presentation Model":
http://martinfowler.com/eaaDev/PresentationModel.html
The idea behind that is basically the following:
Imagine you have the domain entry User, who looks like that :
#Entity
#Data
public class User {
#Id private UUID userId;
private String username;
#OneToMany private List<Permission> permissions;
}
Let's now imagine you have a view where you wanna display that user's name, and you totally don't care about the permissions. If you use your approach of immediately returning the User to the view, Hibernate will make an additional join from the Permissions table because event though the permissions are lazily loaded by default, there is no easy way to signal to the jackson serializer or whatever you are using, that you don't care about them in this particular occasion, so jackson will try to unproxy them (if your transaction is still alive by the time your object is put for json serialization, otherwise you get a nasty exception). Yes, you can add a #JsonIgnore annotation on the permissions field, but then if you need it in some other view, you are screwed.
That a very basic example, but you should get the idea that sometimes your domain model can't be immediately used to be returned to the presentation layer, due to both code maintainability and performance issues.
We were using such approach to simplify design and get rid of many dtos (we were abusing them too much). Basically, it worked for us.
However, in our REST model we were trying to do not expose other relations for an object as you can always create another REST resources to access them.
So we just put #JsonIgnore annotations to relations mappings like #OneToMany or #ManyToOnemaking them transient.
Another problem I see that if you still like to return these relations you would have to use Join.FETCH strategy for them or move transaction management higher so that transaction still exists when a response is serialized to JSON (Open Session In View Pattern).
On my opinion these two solutions are not so good.
You can map the json request without using any library at REST web-services (Jersy)
this sample of code:
This hibernate entity called book:
#Entity
#Table(name = "book", schema = "cashcall")
public class Book implements java.io.Serializable {
private int id;
private Author author; // another hibernate entity
private String bookName;
//setters and getters
}
This web-services function
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String addBook(Book book) {
String bookName=book.getName();
return bookName;
}
This is sample json request:
{
"bookName" : "Head First Java",
"author" : {
"id" : 1
}
}
Since you are just starting, perhaps you could use Spring Data REST?
This is the project: http://projects.spring.io/spring-data-rest/
And here are some simple examples:
https://github.com/spring-projects/spring-data-book/tree/master/rest
https://github.com/olivergierke/spring-restbucks
As you can see in the examples, there are no extra DTOs beyond the #Entity annotated POJOs.

Validating Jpa Entities: In service or by lifecycle listeners

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).

POJO vs EJB vs EJB 3 [duplicate]

This question already has answers here:
Difference between DTO, VO, POJO, JavaBeans?
(7 answers)
Closed 7 years ago.
Does anyone have any example of what a Java Class might look like as a POJO, EJB, and EJB 3? I'm trying to understand these java technologies but am having trouble. I was hoping it would help if I could see what an implementation of all three would look like.
POJO stands for Plain-Old-Java-Object - just a normal Java class as opposed to older technologies that required changing the class in specific ways to make it work with their framework.
class MyService {
public String sayHello() { return "hello world"; }
}
As such POJOs can be used anywhere a normal class can be used. However if you want to build an enterprise application out of them you still need some framework - Spring is a good example of a framework that can work directly with POJOs.
EJB2 is no longer relevant so you can ignore it - unless you need to maintain some legacy code. To satisfy your curiosity the same example as above would require several classes and xml descriptors to make it run - it's easy to see why it became obsolete.
EJB3 is the latest standard for developing enterprise applications which replaces EJB2 and is based on concept of taking POJOs and annotating them so that they can be used in enterprise app.
#Stateless
class MyService {
public String sayHello() { return "hello world"; }
}
As you can see it's very similar to POJOs. In fact most application written for EJB3 can easily be converted to work with Spring, and usually the other way works too.
via: http://swik.net/POJO+ejb3
EJB3 entities are plain POJOs. Actually they represent the exact same concept as the Hibernate persistent entities. Their mappings are defined through JDK 5.0 annotations (an XML descriptor syntax for overriding is defined in the EJB3 specification). Annotations can be split in two categories, the logical mapping annotations (allowing you to describe the object model, the class associations, etc.) and the physical mapping annotations (describing the physical schema, tables, columns, indexes, etc). We will mix annotations from both categories in the following code examples. EJB3 annotations are in the javax.persistence.* package. Most JDK 5 compliant IDE (like Eclipse, IntelliJ IDEA and Netbeans) can autocomplete annotation interfaces and attributes for you (even without a specific "EJB3" module, since EJB3 annotations are plain JDK 5 annotations).
for the example: http://www.laliluna.de/ejb-3-tutorial-jboss.html
#Entity
#Table(name="book")
#SequenceGenerator(name = "book_sequence", sequenceName = "book_id_seq")
public class Book implements Serializable {
Entity defines that this is an entity bean. The second defines the table name. The last one defines a sequence generator.
POJO
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
// setter & getter for age omitted
public String toString() {
return "Person " + name;
}
}
This can be used as an EJB3 as well.
Regarding EJB2 please forget that it exists and do not invest any time on it unless you absolutely have to (e.g work on legacy code).
Even this class (#Stateless class MyService) mentioned above is similar to POJO, it is not a traditionally-definied POJO since it has dependency on the javax.ejb package. I wish this dependency was just like a soft reference (DB concept) instead of being required. This article mentioned some ideas regarding this: How to Fix Java POJO Annotations

Categories

Resources