I'm developing a Web Application with Spring Framework(Spring Boot) and JDBC (no JPA or ORM) so I'm using Dependency Injection to use Beans through layers. The structure is composed by three main layers: DB (DAOs), Service and Controller. DAOs are injected in other DAOs or in Service layer and Services in other Services and in Controller Layer.
My Database layer is composed by one DAO for each the tables of the database. Each DAOhas the general CRUDand some specific operations according to its needs. In total I have more than 10 tables (nearly 15 maybe).
Example of DAO
public class Dao1 implements Crud<Entity, Integer>{
public Entity findById(Integer id){
//Impl Jdbc
}
public void insert(Entity entity){
//JDbc impl
}
//Other CRUD operations -> Update, delete,...
}
In the Service layer I map Entities (Database objects) to DTos(Data access object).
Problem
I have a #Service class with It is needed to inject too much dependencies (10 dependencies) of data access object.
Why? I've got a complex DTO class which is needed to fill getting some data of each entity (using DAOs) and doing some operations also (Update, insert, delete.....
Example of Service
public class ServiceO{
#Autowired
private Dao1 dao1;
#Autowired
private Dao2 dao2;
//assume there are 10 daos....
public ObjectComplexDTO findObject(int id){
ObjectComplexDTO dto = mapToObjectComplexDTO(dao1.findById(id));
dto.setOtherObjects(mapToOtherObjectDto(dao2.findByCompleDto(id)));
// and so on....
return dto;
}
}
When I reviewed my #Service I saw clearly it`s needed to refactor this class but I'm not sure how.
I have considered the following options:
Create a Class which groups by functionality: but extract data remain too much, 7 dependencies...
Group DAOs (no just one DAO for Entity) and Make more complex SQL and extract more data giving more functionality to the Database Engine in the Entities of this data that only DTOs has and then filled in DAOs layer: the problem is moved to the layer DAO...
Keep the class knowing that it has too many dependencies.
Do you have any idea's to improve this issue?
Just off the top of my head, I would suggest refactoring your DAOs. It sounds like you have one DAO per table. Instead, try to align your DAOs with business requirements in a more Domain-Driven style of design. Your service layer is required to "know" too much about the data layer and is therefore likely to be unnecessarily coupled to it.
Related
So I come from Spring Boot background and I was really impressed how Spring #Transactional annotation just worked seamlessly along with Hibernate.
I am working on a Dropwizard application now that is using Jdbi3. And I have found a similar #Transaction annotation that works quite the same way as Spring but with some pre conditions.
Spring
So according to Spring Guidelines, Repository and Controller are the two interfaces which communicates to the database and HTTP requests respectively, Service Layer was the place where all the business logic belongs.
There was always a case where a single method in service does CRUD operations using multiple repositories. Thus it makes so much sense to make the service method annotate with #Transational.
Jdbi with Dropwizard
So correct me if I am wrong. Here in Jdbi the Repository becomes Dao, Controller becomes Resource and Service remains Service. Maybe different people use different layer architecture, but let's just assume this is the case where my problem lies in.
Problem statement
I wish to achieve the same Transaction Handling in Jdbi as in Spring ideologically because it makes much more sense to me without adding any extra layer.
Here's I'll throw some code, what I wish to achieve:
Dao1.kt
interface Dao1{
#SqlUpdate("INSERT INTO table1...")
fun insert() : Int
}
Dao2.kt
interface Dao2{
#SqlUpdate("INSERT INTO table2...")
fun insert() : Int
}
Service.kt
class Service{
#Transaction
fun save() {
Dao1 =Dao1() //What should be expected way to instantiate
Dao2 =Dao2() //What should be expected way to instantiate
dao1.insert()
dao2.insert()
}
}
Few points to note
I am aware that onDemand can only be used on abstract class or interface, thus I cannot instantiate Service using onDemand. Also i cannot make my Service abstract.
Few articles suggests to make an abstract Repository and use Transaction there. But as per my thought when I think of repository, I see it has a one-to-one mapping with the entity/table. Or maybe related entities. So if I want to update movie and user table in the same service method, putting these two transaction statement under a method in some XRepository sounds very absurd to me. Its a part of business logic and should reside in Service.
I think I can use jdbi.inTransaction and jdbi.useTransaction. But in that case I have to attach each and every Dao manually. Is there a better way to do that?
Thanks
You can use Jdbi's #Transaction to decorate method in your bizlogic classes. It will run underlying db queries in transaction.
Assuming Repository can be composed of multiple Dao's & assuming the flow of control like this, here is how one way to structure your bizlogic (business logic classes) and repositories.
Resource -> BizLogic -> Repository -> Dao
For instance (Kotlin + Dropwizard + Jdbi):
Resource
#GET
#Path("{Id}")
#Produces(MediaType.APPLICATION_JSON)
fun getAccount(
#PathParam("Id") Id: String,
#Suspended asyncResponse: AsyncResponse
) = asyncResponse.with {
accountManager.getAccount(Id)
}
method in BizLogic
#Transaction
suspend fun getAccount(Id: String): List<Account> =
accountRepository.getAccountsById(Id) ?: emptyList()
method in Repository
suspend fun getAccountsById(Id: String): List<Account>? = withContext(Dispatchers.IO){
accountDao.lookupById(Id)
}
Dao
#SqlQuery("select user_id, name, email from users where user_id = :id")
fun lookupById(#Bind("id") Id: String): List<Account>?
Ps: you will need to handle binding of repository/dao with jdbi instance with guice or spring-di
I'm trying to build REST application using following tech stack:
Spring
VueJs
JPA (Hibernate)
This is my first experience in writing Sping application and web app development overall.
I have 4 tables in my DataBase:
Language
Sentence
Rule
User
For example in Rule there is :
Rule create(EntityManagerFactory factory, String type, String hint, String help, Language language);
List<Rule> readAll(EntityManagerFactory factory);
Rule readID(EntityManagerFactory factory, int id);
void update(EntityManagerFactory factory, String type, String hint, String help, Language language);
So there is my questions:
When I create Controllers for each table, I use the CRUD methods to modify (or not) my database, and I return a view for my HTML and VueJS part. But my method need an EntityManagerFactory, should I create a field in each Controllers class or this is not how I'm supposed to do ?
Do I need to create a bean file and configure it or persistence.xml and pom.xml are enough?
Thanks
Seems like your first question can be broken up into multiple concerns.
When I create Controllers for each table, I use the CRUD methods to modify (or not) my database, and I return a view for my HTML and VueJS part. But my method need an EntityManagerFactory, should I create a field in each Controllers class or this is not how I'm supposed to do?
Since you have already accepted an answer that recommends the use of spring-data-jpa. You will be dealing with entities and repositories.
Entities are JPA managed beans that will interact with your database.
#Entity
#Table(name = "rule")
public class Rule {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
long id;
String type;
...
#OneToOne
#JoinColumn(...)
Language language;
}
Repositories will provide all the necessary operations required to perform an action against your database. With JPA you can create an interface that extends CrudRepository which would provide you with some CRUD operations that come free with it. findOne(/* id */), delete(), save()
#Repository
public interface RuleRepository extends CrudRepository<Rule, Long> {
// You can easily specify custom finders
public List<Rule> findByType(String type);
}
But my method need an EntityManagerFactory, should I create a field in each Controllers class or this is not how I'm supposed to do?
It's typically frowned upon to have a request/response object to be JPA entity. See the linked answer for should i use jpa entity in rest request and/or response
There are multiple approaches that you can take to take a controller request and send a response to your client side project.
#Controller
public class RuleController {
#Autowired
private RuleRepository ruleRepository;
// Approach 1: Use Request Parameters - enforce inputs
#PostMapping("/rule/:id")
public Rule postWithRequestParams(#PathParam("id") Long id,
#RequestParam("type") String type,
#RequestParam("hint") String hint,
#RequestParam("languageField1") String languageField1) {
Rule inputRule = new Rule(id, type, hint, new Language(languageField1));
Rule responseRule = ruleRepository.save(inputRule);
return responseRule; // I would imagine you would want to set up a model for the response itself
}
// Approach 2: Use RequestBody - serialize Rule from the request
#PostMapping("/rule/:id")
public Rule postWithRequestParams(#PathParam("id") Long id, #RequestBody Rule inputRule) {
Rule responseRule = ruleRepository.save(inputRule);
return responseRule;
}
Do I need to create a bean file and configure it or persistence.xml and pom.xml are enough?
If you have added spring-boot-starter-data-jpa as a dependency, a lot of the bean configuration has already been done for you.
In your main/src/resources (you should have an application.properties or application.yml)
spring.datasource.url= # JDBC url of the database.
spring.datasource.username= # Login user of the database.
spring.datasource.password= # Login password of the database.
Spring does a lot of the magic and heavy lifting for you.
If you are using spring Boot then you don't need entity manager. All you need to do is to define Datasource in you properties file. And create a Bean in our Configuration class just like:
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource datasource() {
return DataSourceBuilder.create().build();
}
Now rest of the things you can handle with repositories.They will be like:
import org.springframework.data.repository.CrudRepository;
public interface RuleRepository extends CrudRepository<Rule, Long> {
}
In your controllers you will use it like:
#Autowired
private RuleRepository ruleRepository;
#Get
#Path("/getRule/:id")
public Rule find(#PathParam("id")Long id){
return ruleRepository.findOne(id);
}
These dependencies I used in my gradle project. You will find Maven version for same:
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile group: 'mysql', name: 'mysql-connector-java'
You definitely need to have a look on Spring Boot(http://start.spring.io), it allows easier to start web app development. As for persistence layer you could use Spring Data JPA(already includes Hibernate) module which also can be easily integrated with Spring Boot. The beauty of Spring Data that is already have written by default most queries like save(), remove(), find() and so on. You only need to define Objects which will be used by Spring Data.
Update: See my Spring Boot REST API example here
I'm trying to get used to how JSF works with regards to accessing data (coming from a spring background)
I'm creating a simple example that maintains a list of users, I have something like
<h:dataTable value="#{userListController.userList}" var="u">
<h:column>#{u.userId}</h:column>
<h:column>#{u.userName}</h:column>
</h:dataTable>
Then the "controller" has something like
#Named(value = "userListController")
#SessionScoped
public class UserListController {
#EJB
private UserListService userListService;
private List<User> userList;
public List<User> getUserList() {
userList = userListService.getUsers();
return userList;
}
}
And the "service" (although it seems more like a DAO) has
public class UserListService {
#PersistenceContext
private EntityManager em;
public List<User> getUsers() {
Query query = em.createQuery("SELECT u from User as u");
return query.getResultList();
}
}
Is this the correct way of doing things? Is my terminology right? The "service" feels more like a DAO? And the controller feels like it's doing some of the job of the service.
Is this the correct way of doing things?
Apart from performing business logic the inefficient way in a managed bean getter method, and using a too broad managed bean scope, it looks okay. If you move the service call from the getter method to a #PostConstruct method and use either #RequestScoped or #ViewScoped instead of #SessionScoped, it will look better.
See also:
Why JSF calls getters multiple times
How to choose the right bean scope?
Is my terminology right?
It's okay. As long as you're consistent with it and the code is readable in a sensible way. Only your way of naming classes and variables is somewhat awkward (illogical and/or duplication). For instance, I personally would use users instead of userList, and use var="user" instead of var="u", and use id and name instead of userId and userName. Also, a "UserListService" sounds like it can only deal with lists of users instead of users in general. I'd rather use "UserService" so you can also use it for creating, updating and deleting users.
See also:
JSF managed bean naming conventions
The "service" feels more like a DAO?
It isn't exactly a DAO. Basically, JPA is the real DAO here. Previously, when JPA didn't exist, everyone homegrew DAO interfaces so that the service methods can keep using them even when the underlying implementation ("plain old" JDBC, or "good old" Hibernate, etc) changes. The real task of a service method is transparently managing transactions. This isn't the responsibility of the DAO.
See also:
I found JPA, or alike, don't encourage DAO pattern
DAO and JDBC relation?
When is it necessary or convenient to use Spring or EJB3 or all of them together?
And the controller feels like it's doing some of the job of the service.
I can imagine that it does that in this relatively simple setup. However, the controller is in fact part of the frontend not the backend. The service is part of the backend which should be designed in such way that it's reusable across all different frontends, such as JSF, JAX-RS, "plain" JSP+Servlet, even Swing, etc. Moreover, the frontend-specific controller (also called "backing bean" or "presenter") allows you to deal in a frontend-specific way with success and/or exceptional outcomes, such as in JSF's case displaying a faces message in case of an exception thrown from a service.
See also:
JSF Service Layer
What components are MVC in JSF MVC framework?
All in all, the correct approach would be like below:
<h:dataTable value="#{userBacking.users}" var="user">
<h:column>#{user.id}</h:column>
<h:column>#{user.name}</h:column>
</h:dataTable>
#Named
#RequestScoped // Use #ViewScoped once you bring in ajax (e.g. CRUD)
public class UserBacking {
private List<User> users;
#EJB
private UserService userService;
#PostConstruct
public void init() {
users = userService.listAll();
}
public List<User> getUsers() {
return users;
}
}
#Stateless
public class UserService {
#PersistenceContext
private EntityManager em;
public List<User> listAll() {
return em.createQuery("SELECT u FROM User u", User.class).getResultList();
}
}
You can find here a real world kickoff project here utilizing the canonical Java EE / JSF / CDI / EJB / JPA practices: Java EE kickoff app.
See also:
Creating master-detail pages for entities, how to link them and which bean scope to choose
Passing a JSF2 managed pojo bean into EJB or putting what is required into a transfer object
Filter do not initialize EntityManager
javax.persistence.TransactionRequiredException in small facelet application
It is a DAO, well actually a repository but don't worry about that difference too much, as it is accessing the database using the persistence context.
You should create a Service class, that wraps that method and is where the transactions are invoked.
Sometimes the service classes feel unnecessary, but when you have a service method that calls many DAO methods, their use is more warranted.
I normally end up just creating the service, even if it does feel unnecessary, to ensure the patterns stay the same and the DAO is never injected directly.
This adds an extra layer of abstraction making future refactoring more flexible.
Some days ago I heard about spring-boot.
So I started to setup my project from zero, include jpa and dont use older setups from existing projects. But now there is an understanding problem between what I've learned and what I've read about the "easy setup" with spring boot and jpa.
Usually my projects have this structur.
Model (for excample Car)
ModelDao (CarDao with the following code-example)
#Component
public class CarDao {
/** The Hibernate session factory. */
#Autowired
private SessionFactory sessionFactory;
#Transactional
public void save(Car car) {
sessionFactory.getCurrentSession().saveOrUpdate(car);
}
CarServiceImpl thats works with DAO´s (includes methods like findAll(), getCarById() or saveCar(Car car))
But now I only read about #Entity and JPA-repositorys.
Is it right to say that I dont need models and dao's because I have the #Entity-Annotation? And my ServiceImples and JPA-repositorys have the same functionality? What happend with the SessionFactory? Is all managed automatically?
You dont need DAO if you are going to use JPA-Repositories.
As well Session-Factory also not required.
Just you need one Class as model and one interface as repository and you all done.
example:
#Entity
#Table(name="COUNTRY")
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="COUNTRY_ID", nullable = false)
private Integer country_id;
#Column(name="COUNTRY_CODE")
private String country_code;
//Add getter and setter
}
interface
public interface CountryRepository extends PagingAndSortingRepository<Country, Integer> {
}
Yes you need to configure in spring.xml about where your above repository is located
<jpa:repositories base-package="com.repository" />
create transactionManager in spring.xml
and access it by using below code
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"spring.xml");
countryRepository = (CountryRepository) ctx.getBean("countryRepository");
Country country = countryRepository.findOne(1);
Is it right to say that I dont need models and dao's because I have the #Entity-Annotation?
#Entity annotation is used on models your POJOs. #Entity maps the POJO i;e class properties to the db table. How would you write your business logic if you get rid of models.
Service layer, DAO layer are all components of application design. They have their specific role. ServiceImpl proverbially manages the transactions whereas DAO/Repository layer manages the communication with the db.
Here your CarDao class should be annotated with #Repository annotation. It is a DAOImpl class.
And all your transactional methods should move to the Service layer.
And my ServiceImples and JPA-repositorys have the same functionality?
No, as I've already stated they have specific respective functionality. They are not same.
What happend with the SessionFactory? Is all managed automatically?
SessionFactory is always injected into the DAO layer. You can either manage the sessions yourself or let hibernate manage the sessions.
im programming a project and im trying to apply multitier architecture.
Right now ive got 2 EJB, business and persistence and a shared jar. Due a funcional requirment, persistence must be replaceable. I made an Interface called IPersistence.
Then I crated a remote session bean called "persistence" inside the persistence EJB and put the remote interface in the shared library. Now, i need to call an IPersitence using injection from the business. How can i do that? Maybe the whole idea is wrong. I need some advice.
Thanks!
Here is a simple example where you have a car repository/DAO that abstracts the persistence from the business logic by not exposing if it is stored in a database, file, XML etc. The business class then injects an instance to be able to - in this case - save to an database. However you could have made other classes that implemented the CarRepository and provide other means for saving data in your application without touching other parts of your code.
Persistence layer
Interface for the repository/DAO
#Local
public interface CarRepository {
List<Car> findAllCars();
// Many other methods
}
Repository (Domain driven design) or Data Access Object
#Stateless
public class CarSqlRepository implements CarRepository {
#PersistenceContext(unitName = "MyUnit")
private EntityManager entityManager;
public List<Car> findAllCars() {
}
// Many other methods
}
Service/business layer
#Stateless
public class CarService {
#Inject
private CarRepository carRepository;
public List<Car> findAllCars() {
return carRepository.findAllCars();
}
// Many other methods
}