Can hibernate business objects be used as entities in a clean architecture? - java

In our project we use classes generated by eclipse hibernate plugin for persistence.
The generated classes have following structure.
MyClass extends BaseMyClass //POJO's, that are refenced in the hbm
files
MyClassDAO extends BaseMyClassDAO //DAO objects that use hibernate
session objects to provide CRUD API's for working with DB
My question is, would it violate Uncle Bobs clean architecture if we use the POJO classes used in the mapping files as the Entities in the innermost layer.
The hibernate specific DAO classes would belong in this case to the outermost layer and UseCases layer would communicate with this layer via providing an interface to be implemented.

Uncle Bob comments on this during a lecture in Norway while presenting this slide:
Uncle Bob says:
There is no Hibernate above the line. If you are using Hibernate it goes below the line. The application does not know that you are using that framework. It goes below the line. And Hibernate is a lovely tool. It's very good for gathering data out of the database and turning it into data structures. Very nice! But you don't want your application to know that you are using it. You put all that stuff below the line.
Robert C Martin - Clean Architecture, NDC 2012 (53:53 - 54:18)
Thus if you are using Hibernate annotations on the entities, you mix your domain objects with details of the database layer.
Some developers argue that annotations are not so strong dependencies, because if they are not available at runtime they just do not exist. That's true, but you also have to consider other principles.
If you put Hibernate annotations on your entities, the entity classes now have two different reasons to change: the domain logic and the database mapping.
This is a violation of the single responsibility principle. Therefore database mappings will affect your domain objects.
I guess there is a lot of confusion, because of the overloaded term entity. When Uncle Bob talks about entities he means domain. In Hibernate entity means database record.
That's why I usually distinguish them by using the term "domain entity" or "database entity".

Related

Extending JPA to WebServices

After reading some pages from DDD, I read about Repository pattern, then used it in an application successfully (I really liked it); then I noticed that EntityManager is generic-repository-like, but while I was reading about Repository I saw many examples on the web explaining how to impliment Repository pattern, and JPA was a simple Repository implementation between many implementations, like this website: http://www.lestard.eu/2015/generic_repository_part1/
The developer demonstrated in-memory implementations of Repository pattern, and in the second part : http://www.lestard.eu/2015/generic_repository_part2/, showed JPA implementation of repository pattern.
So here my question: while JPA is already like a generic repository, can we extend JPA to use in-memory, web services (e.g: REST CRUD) and entity persisting -- as JPA stands for Java PERSISITENCE API, (I wrote it in capital letters to show that it means a general persistence mechanism) -- as it seems that current JPA is tightly coupled with databases, but its name refer to a general use.
Technically it's possible but I would prefer not to do this and don't have any links to specific implementation standard (like Java JPA). I prefer to hide all of implementation details inside my Repository impl.
Moreover, I definitely don't like idea to put any persisting (like #Entity) or conversion (like #XmlRootElement from JAXB or #JsonProperty) annotations inside my domain objects.
The reason is the simple: if in the future you will change Java JPA to smth new like Java New JPA you'll have to change you domain objects for this too. But it contradicts whole DDD idea.

JPA annotations in entity layer according to Uncle Bob

According to Uncle Bob, the entity layer should know nothing about the database.
What about the JPA annotations then? Don't they violate the architecture proposed by the author? If they do, how to use the entities with JPA?
In a non-ORM world, a clean architecture would (or could) involve having DAO interfaces, with DAO implementations knowing how to retrieve the data from a database (or any other source), and convert and return it as a domain object. An upper layer would then use the DAOs (through the interfaces) to retrieve those objects.
This would allow you to for example create different DAO implementations for different databases, and you could change databases without bothering the rest of the software.
In a JPA/ORM world you can bypass a lot of that if you choose. You can use entity classes as domain objects, create the entity classes in a database agnostic way (i.e. not using any database specific NativeQueries for example). Now that your entities are database agnostic, you can just use NamedQueries in your service layer instead of creating DAOs.
In the end you need to have some layer which knows about the database, but in JPA's case it doesn't even hold true. Your entities are Java objects and it's the JPA implementation layer that is responsible for converting them to and from the database.
In conclusion: there are very few universal truths in software development and you can talk to a dozen uncles and hear a dozen versions of essentially the same "story".

Can a class be annotated as both #Repository and #Entity?

I am pretty new to Hibernate. I am having problem understanding these simple logics. I have understood that #Repository is used by Spring for accessing objects. Also, Hibernate uses #Entity to denote entities which are mapped into database tables. I was just wondering if a single class can be annotated with both #Repository and #Entity as they more or less imply the same.
NO.
Hibernate entities are managed by Hibernate ORM framework, they(and their proxies) are created by hibernate when you access them via get() or load(). They have a completely different (and complex) lifecycle than the Spring beans(they can be attached/detached/proxied/pending for removal)
Spring repositories are singletons, managed by Spring framework. Typically they exist as long as the container instance exists. New Hibernate sessions may be opened and closed, new user sessions engaged and then expired, but there still will be the same singleton instances of repositories.
Please see http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/objectstate.html#objectstate-overview for the possible hibernate object states.
As for the repository instances - typically they are stateless, as they are services.
RE: they more or less imply the same. No they are not the same. There was an old joke
How many C++ programmers does it take to change a light bulb? You're
still thinking procedurally. A properly designed light bulb object
would inherit a change method from a generic light bulb class, so all
you would have to do is send a light-bulb-change message.
But good OOP programmers do not think that way, according to single responsibility principle objects should should have a single reason to change. Repository works with the infrastructure and has nothing to do with the business rules. Infrastructure may change(you may need for example to store you object in XML instead of RDBMS), but this should not affect the classes encapsulating the state of business objects.
You can possibly mitigate this problem by making a reference from the entity class to an abstract repository interface(implement an infamous Active Record pattern - it will be like referencing some abstract bulb socket from the bulb, this does not seem to be a good solution because bulb sockets and bulbs have different lifecycles).
That is where High Cohesion principle starts to play, according to which it's just illogical for an object, whose role is to reflect the abstractions from the model, to perform some completely unrelated things like persistence or transmitting over the network. It's weird when Student class will have print(), saveToXml() or transmitByHttp() methods.
They don't imply the same thing at all.
#Entity
An #Entity is something that represents a "thing" in your business domain. It could be anything - a Customer, an Elephant, a Product. . . It will have attributes that will get persisted to the database as well as methods relating to those attributes (at least it should, unless it's an anaemic entity, but that's an anti-pattern. . . . later, when you're comfortable with the basics check out Spring's #Configurable annotation - this allows you to provide collaborators to your entity).
#Repository
A #Repository, on the other hand provides an interface for retrieving and storing those entities.
There are some frameworks, especially in other languages, that combine the persistence and entity attributes on the same object, however this is not common in Java/Hibernate/Spring.

Using DAOs with composite Objects

I am trying to rewrite a bunch of DAOs here is the setting:
only plain JDBC (no JPA, ORM whatsoever)
no interfaces used
lots of checks before inserting an object
Business objects are strongly linked
My main question is:
How do I persist/retrieve a business object that is composed of multiple other objects?
e.g. does my CustomerDAO know the AddressDAO and retrieve the csutomers adresses from there?
only plain JDBC (no JPA, ORM whatsoever)
Business objects are strongly linked
Not sure why you don't want to use JPA while you want your business objects to be linked, but at least you should use Spring JDBC template that would relieve you from some boilerplate code.
Regarding the other constraints, I would do it as follows:
I would still employ interfaces to define the DAO methods and implement them in a Spring JDBC template backed DAOImpl. Use the DAO everywhere and inject the DAOImpl.
My DAOs will be simply one-to-one mapping to the underlying tables and each DAO wouldn't know about the existence of other DAOs.
My Manager layer will have all the business logic that runs validation checks and prepares the set of objects that need to be persisted, calls the appropriate DAO and appropriate method (CREATE/UPDATE/DELETE) to persist the objects.
Again, the Manager layer will follow the interface-based implementation and the view layer would have manager types injected with the ManagerImpls.
My two cents!
You may Consider Using JOOQ. It is not JPA, but it may easily be used as an alternative solution. It is lightweight enough. It also provides provides a reverse engineer tool, where it builds your Database entities as DAO objects.
I have embed JOOQ in a relevant situation, where the application was fairly engineered designed. I didn't use its DAO functionality, rather than using it as a higher layer to avoid messing with JDBC Layer.
Cheers!
Composite entities are a layer above DAO's. If you want to remove ALL coupling, domain objects persisted by DAOs should be flat without relationships. See Core J2EE patterns CompositeEntity.
Also, it's a good idea not to introduce coupling inbetween the DAO's by putting finders for one in the other. E.g.:
AddressDAO.findForCustomerId(id);
is inferior to using a third DAO to manage the relationship. I.E:
CustomerAddressRelDAO.findAddressForCustomer(id);
If you use a relationship DAO neither address nor customer are dependent on (or aware of) each other.

About Data Objects and DAO Design when using Hibernate

I'm hesitating between two designs of a database project using Hibernate.
Design #1.
(1) Create a general data provider interface, including a set of DAO interfaces and general data container classes. It hides the underneath implementation. A data provider implementation could access data in database, or an XML file, or a service, or something else. The user of a data provider does not to know about it.
(2) Create a database library with Hibernate. This library implements the data provider interface in (1).
The bad thing about Design #1 is that in order to hide the implementation details, I need to create two sets of data container classes. One in the general data provider interface - let's call them DPI-Objects, the other set is used in the database library, exclusively for entity/attribute mapping in Hibernate - let's call them H-Objects. In the DAO implementation, I need to read data from database to create H-Objects (via Hibernate) and then convert H-Objects into DPI-Objects.
Design #2.
Do not create a general data provider interface. Expose H-Objects directly to components that use the database lib. So the user of the database library needs to be aware of Hibernate.
I like design #1 more, but I don't want to create two sets of data container classes. Is that the right way to hide H-Objects and other Hibernate implementation details from the user who uses the database-based data provider?
Are there any drawbacks of Design #2? I will not implement other data provider in the new future, so should I just forget about the data provider interface and use Design #2?
What do you think about this? Thanks for your time!
Hibernate Domain objects are simple POJO so you won't have to create separate DPI-objects, H-Object themselves can be used directly. In DAO you can control whether they come from hibernate or anything else.
I highly recommend reading Chapter 4 "Hitting the database" of Spring in Action, 3rd edition, even if you aren't using Spring in your application. Although my second recommendation would be to use Spring :-)
The DAO pattern is a great way to keep database and ORM logic isolated in the DAO implementation, and you only need one set of entity objects. You can make that happen without Spring, it just takes more work managing your sessions and transactions.
If I understand your post, this is sort of a middle-ground between Design 1 and Design 2. The H-Objects (the entities that Hibernates loads and persists) don't need any Hibernate specific code in them at all. That makes them perfectly acceptable to be used as your DPI-Objects.
I've had arguments with folks in the past who complain that the use of JPA or Hibernate Annotations exposes Hibernate specifics through the DAO interface. I personally take a more pragmatic view, since annotations are just metadata, and don't directly affect the operation of your entity classes.
If you do feel that the annotations expose too much, then you can go old school and use Hibernate Mappings instead. Then your H-Objects are 100% Hibernate free :-)
I recommend design #2. Simply construct domain objects, and let hibernate look after them. Don't write separate classes that are persisted.
Hibernate tries to hide most of the persistence business from you. You may need to add a few small annotations to your entities to help it along. But certainly don't make separate classes.
You may need some very small DAO classes. For example, if you have a Person entity, it would be fairly common practice to have a PersonDAO object that saves a person. Having said that, the code inside the DAO will be very simple, so for a really small project, it may not be worth it. For a large project, it's probably worth keeping your persistence code separate from your business logic, in case you want to use a different persistence technology later.

Categories