1

I tried to create an abstract Dao. I use Spring + Hibernate. Here's my code.
Main class with configuration:

package ru.makaek.growbox.api;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@ComponentScan(value = "ru.makaek.growbox")
@EnableAutoConfiguration(exclude = HibernateJpaAutoConfiguration.class)
@EnableTransactionManagement
@SpringBootApplication
public class Application {

    @Autowired
    private Environment env;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }


    @Bean
    public DataSource getDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getRequiredProperty("datasource.driver"));
        dataSource.setUrl(env.getRequiredProperty("datasource.url"));
        dataSource.setUsername(env.getRequiredProperty("datasource.username"));
        dataSource.setPassword(env.getRequiredProperty("datasource.password"));
        return dataSource;
    }

    @Bean
    public LocalSessionFactoryBean getSessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(getDataSource());
        sessionFactory.setPackagesToScan(new String[]{"ru.makaek.growbox"});
        return sessionFactory;
    }

    @Bean
    public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory);
        return txManager;
    }

}

Rest controller

package ru.makaek.growbox.api.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import ru.makaek.growbox.api.model.data.entities.Device;
import ru.makaek.growbox.api.service.IStructureService;

@RestController
public class DeviceController extends AbstractController {

    @Autowired
    IStructureService structureService;

    @RequestMapping(value = "/devices", method = RequestMethod.POST)
    public Answer addDevice(@RequestBody Device device) {
        structureService.addDevice(device);
        return ok("Device has been added");
    }

    @RequestMapping(value = "/devices", method = RequestMethod.GET)
    public Answer getDevices() {
        return ok(structureService.getDevices());
    }

    @RequestMapping(value = "/devices/{deviceId}", method = RequestMethod.GET)
    public Answer getDevice(@PathVariable Long deviceId) {
        return ok(structureService.getDevice(deviceId));
    }

}

Service layer. Interface

package ru.makaek.growbox.api.service;

import ru.makaek.growbox.api.model.data.entities.Device;

import java.util.List;

public interface IStructureService {

    void addDevice(Device device);

    List<Device> getDevices();

    Device getDevice(Long deviceId);
}

Service layer. Implementation

package ru.makaek.growbox.api.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.makaek.growbox.api.model.data.dao.base.IDao;
import ru.makaek.growbox.api.model.data.entities.Device;

import java.util.List;

@Service
@Transactional
public class StructureService implements IStructureService {

    IDao<Device> deviceDao;

    @Autowired
    public void setDao(IDao<Device> dao) {
        deviceDao = dao;
        dao.setClazz(Device.class);
    }

    @Override
    public void addDevice(Device device) {
        deviceDao.create(device);
    }

    @Override
    public List<Device> getDevices() {
        return deviceDao.findAll();
    }

    @Override
    public Device getDevice(Long deviceId) {
        return deviceDao.findOne(deviceId);
    }
}

Entity

package ru.makaek.growbox.api.model.data.entities;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity(name = "devices")
@Data public class Device extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}

DAO. Interface

package ru.makaek.growbox.api.model.data.dao.base;

import ru.makaek.growbox.api.model.data.entities.BaseEntity;

import java.util.List;

public interface IDao<T extends BaseEntity> {

    T findOne(final long id);

    void setClazz(Class<T> clazz);

    List<T> findAll();

    void create(final T entity);

    T update(final T entity);

    void delete(final T entity);

    void deleteById(final long entityId);

}

Abstract DAO

package ru.makaek.growbox.api.model.data.dao.base;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import ru.makaek.growbox.api.model.data.entities.BaseEntity;
import ru.makaek.growbox.api.util.GBException;

import java.util.List;

public abstract class AbstractDao<T extends BaseEntity> implements IDao<T> {

    private Class<T> clazz;

    @Autowired
    private SessionFactory sessionFactory;

    public final void setClazz(Class<T> clazz) {
        this.clazz = clazz;
    }

    public T findOne(long id) {
        try {
            return (T) getCurrentSession().get(clazz, id);
        } catch (Exception e) {
            throw new GBException.InternalError(e.getMessage());
        }
    }

    public List<T> findAll() {
        try {
            return getCurrentSession().createQuery("from " + clazz.getName()).list();
        } catch (Exception e) {
            throw new GBException.InternalError(e.getMessage());
        }
    }

    public void create(T entity) {
        try {
            getCurrentSession().persist(entity);
        } catch (Exception e) {
            throw new GBException.InternalError(e.getMessage());
        }
    }

    public T update(T entity) {
        try {
            return (T) getCurrentSession().merge(entity);
        } catch (Exception e) {
            throw new GBException.InternalError(e.getMessage());
        }
    }

    public void delete(T entity) {
        try {
            getCurrentSession().delete(entity);
        } catch (Exception e) {
            throw new GBException.InternalError(e.getMessage());
        }
    }

    public void deleteById(long entityId) {
        try {
            T entity = findOne(entityId);
            delete(entity);
        } catch (Exception e) {
            throw new GBException.InternalError(e.getMessage());
        }
    }

    protected final Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }


}

DAO. Implementation

package ru.makaek.growbox.api.model.data.dao;

import org.springframework.stereotype.Repository;
import ru.makaek.growbox.api.model.data.dao.base.AbstractDao;
import ru.makaek.growbox.api.model.data.entities.Device;

@Repository
public class DeviceDao extends AbstractDao<Device> {
}

I have one trouble. When I call GET http://host:port/devices API method I have null in the clazz variable in the AbstractDao.findAll() method. When I was debugging the code i found one interesting thing: in the service layer method deviceDao.getClazz() returned needed clazz (not null). But in method AbstractDao.findAll() I have null in clazz variable. Why? Please help.
Sorry for my English and formulation. I'm new in this site, Spring and English

1 Answers1

-1

You are overcomplicating things. Because you are using Spring Boot it is possible to just create generic interface that extends CrudRepository and add the methods you need and are not already present in there.

Take a look here https://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html

toucheqt
  • 725
  • 2
  • 8
  • 15
  • I want to use Hibernate. Do I understand correctly that sollution will use spring-data instead Hibernate? – Makarov Oleg Aug 19 '17 at 14:32
  • Hibernate is a JPA implementation, while Spring Data JPA is a JPA Data Access Abstraction. Spring Data offers a solution to GenericDao custom implementations. It can also generate JPA queries on your behalf through method name conventions. With Spring Data, you may use Hibernate, Eclipse Link or any other JPA provider. – toucheqt Aug 20 '17 at 14:57
  • Thank you. Could you advice me some a good book or articles about JPA? – Makarov Oleg Aug 20 '17 at 16:04