So I have such classes
BaseDao
public interface BaseDao<T> {
T save(T entity);
}
UserDao
public interface UserDao extends BaseDao<User> {
User getUserByUserName(String name);
}
GenericDao
public abstract class GenericDao implements BaseDao {
#Autowired
protected SessionFactory sessionFactory;
private Class<?> getEntityClass() {
return ((Class) ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0]);
}
public T save(T entity) {
Integer id = (Integer) sessionFactory.getCurrentSession().save(entity);
return (T) sessionFactory.getCurrentSession().get(getEntityClass(), id);
}
}
UserDaoImpl
#Repository
public class PgUserDaoImpl extends GenericDao<User> implements UserDao {
public User getUserByUserName(String name) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(
User.class);
criteria.add(Restrictions.eq("name", name));
return (User) criteria.uniqueResult();
}
}
GenericService
public class GenericService<T extends GenericDao<E>, E> {
protected T dao;
public GenericService(T dao) {
setDao(dao);
}
#Transactional
public E save(E entity) {
return dao.save(entity);
}
}
UserServiceImpl
#Service("userServiceImpl")
public class UserServiceImpl extends GenericService<PgUserDaoImpl, User>
implements UserService {
#Autowired
public UserServiceImpl(PgUserDaoImpl dao) {
super(dao);
}
#Autowired
private UserAssebmler assebmler;
#Transactional
#Override
public UserDetails loadUserByUsername(String name)
throws UsernameNotFoundException {
.....
}
}
So I write test contoller to save user, but I always get Exception
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
The contoller
#
Controller
#RequestMapping(value = "/test")
public class TestController {
#Autowired
private UserServiceImpl userService;
#RequestMapping(value = "save", method = RequestMethod.GET)
public String test() {
User user = new User();
user.setName("admin");
user.setPassword("21232f297a57a5a743894a0e4a801fc3");
user.setRole(UserRole.ADMIN);
userService.save(user);
return "home";
}
}
Anybody know hot to fix that? Thanks :)
I've solved my question by extending GenericDao class from HibernateDaoSupport class.
Related
I have many services that have repeated code and I want to know how to implement a generic service so all my services can extend it.
Service interfaces example (Repeated code):
#Service
public interface IUserService{
List<User> findAll();
User save(User entity);
User findById(long id);
void delete(User entity);
void deleteById(long id);
long count();
}
#Service
public interface IEventService{
List<Event> findAll();
Event save(Event entity);
Event findById(long id);
void delete(Event entity);
void deleteById(long id);
long count();
}
And their implementations (Now, I have the same code in all the implementations):
#Service
public class EventService implements IEventService{
#Autowired
private IEventDao dao;
#Override
public List<Event> findAll() {
return dao.findAll();
}
#Override
public Event save(Event entity) {
return dao.save(entity);
}
Other CRUD methods...
}
#Service
public class UserService implements IUserService{
#Autowired
private IUserDao dao;
#Override
public List<User> findAll() {
return dao.findAll();
}
#Override
public User save(User entity) {
return dao.save(entity);
}
Other CRUD methods...
}
This is fairly straightforward using Java generics. You can replace the actual class User, Event, etc. with a type parameter.
public interface IGenericService<T> {
List<T> findAll();
T save(T entity);
T findById(long id);
void delete(T entity);
void deleteById(long id);
long count();
}
Then do the same for the implementation:
public class GenericService<T> implements IGenericService<T> {
// The DAO class will also need to be generic,
// so that it can use the right class types
#Autowired
private IDao<T> dao;
#Override
public List<T> findAll() {
return dao.findAll();
}
#Override
public T save(T entity) {
return dao.save(entity);
}
// Other CRUD methods...
}
Even further, you can also create your actual services as:
#Service
class UserService extends GenericService<User> { }
#Service
class EventService extends GenericService<Event> { }
Here's a good tutorial from the Java documentation: Learning the Java Language: Generics
Another one with good examples: The Basics of Java Generics
I'm trying to create an abstract class that performs the common REST operations that are required, but can't work out if what I'm trying to do is possible. I've tried a number of approaches, but have stripped the code below right back to how it should work in my head
Classes updated as per suggestions below. Problem now is that the constructor in the concrete class isn't valid, as CustomerRepository isn't assignable to JpaRepository, though it extends that interface.
AbstractRestController
public abstract class AbstractRestController<T> {
private final JpaRepository<T, Serializable> repository;
public AbstractRestController(JpaRepository<T, Serializable> repository) {
this.repository = repository;
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<JsonResponseBody<T>> getOne(#PathVariable Long id) {
T restObj = repository.findOne(id);
JsonResponseBody<T> response = new JsonResponseBody<>(ResponseStatus.SUCCESS, restObj);
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(response);
}
protected JpaRepository<T, Serializable> getRepository() {
return repository;
}
}
CustomerController
#RestController
#RequestMapping(value = "/api/v1/customer")
public class CustomerController extends AbstractRestController<Customer> {
#Autowired
public CustomerController(CustomerRepository repository){
super(repository);
}
}
CustomerRepository
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}
Indeed, as #dino-tw mentions, you are trying to instantiate an abstract class with an undefined dependency. You can absolutely have an abstract controller class, and even define request handling methods that will be inherited by all subclasses. Try this instead:
public abstract class AbstractRestController<T, ID extends Serializable> {
private final JpaRepository<T, ID> repository;
public AbstractRestController(JpaRepository<T, ID> repository){
this.repository = repository;
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<JsonResponseBody<T>> getOne(#PathVariable ID id) {
T restObj = repository.findOne(id);
JsonResponseBody<T> response = new JsonResponseBody<>(ResponseStatus.SUCCESS, restObj);
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(response);
}
protected JpaRepository<T, ID> getRepository(){ return repository; }
}
#RestController
#RequestMapping(value = "/api/v1/customer")
public class CustomerController extends AbstractRestController<Customer, Long> {
#Autowired
public CustomerController(CustomerRepository repository){
super(repository);
}
}
I am newbie to spring and I am facing following error. please help me out.
Thanks in advance .
User Interface
package com.system.dao;
import java.util.List;
import com.system.model.User;
public interface UserDAO {
public String createOrUpdate(User user);
public List<User> getAllUser();
public String delete(User user);
}
User Interface Implementation
public class UserDAOImpl implements UserDAO {
private NamedParameterJdbcTemplate jdbc;
#Autowired
public void setJdbc(DataSource jdbc) {
this.jdbc = new NamedParameterJdbcTemplate(jdbc);
}
#Transactional
#Override
public String createOrUpdate(User user) {
BeanPropertySqlParameterSource params = new BeanPropertySqlParameterSource(user);
if (user.isUpdate()) {
jdbc.update(
"update login set login_id=:loginId,login_password:loginPassword,user_name=:userName,user_contact=:userContact,user_email=:userEmail where user_id=:userId",
params);
return "User Updated";
} else {
jdbc.update(
"insert into login(login_id,login_password,user_name,user_contact,user_email) values(:loginId,:loginPassword,:userName,:userContact,:userEmail)",
params);
return "User added";
}
}
#Override
public List<User> getAllUser() {
jdbc.query("select * from login", new RowMapper<User>() {
#Override
public User mapRow(ResultSet rs, int num) throws SQLException {
// TODO Auto-generated method stub
User user = new User();
user.setLoginId(rs.getString("login_id"));
user.setLoginPassword(rs.getString("login_password"));
user.setUserContact(rs.getString("user_contact"));
user.setUserEmail(rs.getString("user_email"));
user.setUserId(rs.getInt("user_id"));
user.setUserName(rs.getString("user_name"));
return user;
}
});
return null;
}
#Override
public String delete(User user) {
jdbc.update("delete from login where user_id:userId", new MapSqlParameterSource("userId", user.getUserId()));
return "User deleted";
}
}
User Service
package com.system.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.system.dao.impl.UserDAOImpl;
import com.system.model.User;
#Service
public class UserService {
private UserDAOImpl userDAOImpl;
#Autowired(required=true)
public void setUserDAOImpl(UserDAOImpl userDAOImpl) {
this.userDAOImpl = userDAOImpl;
}
public String createOrUpdate(User user) {
return userDAOImpl.createOrUpdate(user);
}
public List<User> getAllUser() {
return userDAOImpl.getAllUser();
}
public String delete(User user) {
return userDAOImpl.delete(user);
}
}
Context ( dao-context)
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="com.system.dao">
</context:component-scan>
<context:component-scan base-package="com.system.dao.impl">
</context:component-scan>
<context:component-scan base-package="com.system.service">
</context:component-scan>
you are missing #Repository in UserDAOImpl.
#Repository("userDAOImpl")
public class UserDAOImpl implements UserDAO {
To convert the java class to a spring component you need to annotate the class with any of the following
#Controller
#Component
#Repository
#Service
Since UserDAOImpl is the dao belong to the DAO layer, #Repository is the best fit.
read more at
http://howtodoinjava.com/spring/spring-core/how-to-use-spring-component-repository-service-and-controller-annotations/
When I execute from DAO layer(ProjectDAOImpl), I'am able to see the results from database.
However when I execute from results from Service layer, I'am getting null pointer exceptions.
java.lang.NullPointerException
ProjectServiceImpl.fetchProjects(ProjectServiceImpl.java:25)
ProjectServiceImpl.main(ProjectServiceImpl.java:36)
How can I resolve this issue?
DAO Layer Interface and Class
#Remote
public interface ProjectDAO {
List<Project> fetchProjectDetail();
}
#Stateless
public class ProjectDAOImpl implements ProjectDAO {
private EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("projects");
public ProjectDAOImpl() {
}
public List<Project> fetchProjectDetail() {
List<Project> listProject = new ArrayList<Project>();
listProject =
getEntityManager().createNamedQuery("Project.findProjects").getResultList();
return listProject;
}
private EntityManager getEntityManager() {
return entityManagerFactory.createEntityManager();
}
}
Service Layer Interface and Class
#Remote
public interface ProjectService {
List<Project> fetchProjectDetail();
}
#Stateless
public class ProjectServiceImpl implements ProjectService {
private ProjectDAO projectDAO;
public ProjectServiceImpl() {
}
#EJB
public void setProjectDAO(ProjectDAO projectDAO) {
this.projectDAO = projectDAO;
}
#GET
#Path("/projects")
#Produces(MediaType.APPLICATION_JSON)
public List<Project> fetchProjects() {
return getProjectDAO().fetchProjectDetail();
}
public ProjectDAO getProjectDAO() {
return projectDAO;
}
public static void main(String [] args) {
ProjectServiceImpl projectServiceImpl = new ProjectServiceImpl();
projectServiceImpl.fetchProjects();
}
}
I have an abstract DAO:
public abstract class AbstractJpaDAO<T extends Serializable> implements I_AbstractJpaDAO<T> {
private Class<T> clazz;
#PersistenceContext
protected EntityManager entityManager;
public final void setClazz(final Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
#Override
public T findOne(final long id) {
return entityManager.find(clazz, id);
}
#Override
public List<T> findAll() {
return entityManager.createQuery("from " + clazz.getName()).getResultList();
}
#Override
public void create(final T entity) {
entityManager.persist(entity);
}
#Override
public T update(final T entity) {
return entityManager.merge(entity);
}
#Override
public void delete(final T entity) {
entityManager.remove(entity);
}
#Override
public void deleteById(final long entityId) {
final T entity = findOne(entityId);
delete(entity);
}
}
I then extend this DAO in each DAO implementation (code not included) but header something like:
public class UserDAOImpl extends AbstractJpaDAO <User> implements UserDAO {
.....
With each entity, I work with a base interface type, for this example,let's call it UserDAO, and have an associated implementation, let's call it, UserDAOIMPL. To avoid having to define the same methods each Interface to each DAO. As in this longwinded example, i.e :
public interface UserDAO {
User findOne(long id);
List<User> findAll();
void create(User user);
User update(User user);
void delete(User user);
void deleteById(long userID);
User findUserByUserName(String name);
EntityManager returnEntityManager();
}
I would like to instead create a base interface, that all DAOs can extend.
public interface I_AbstractJpaDAO<T> {
.....
}
and then use this in each DAO interface.
public interface userDAO extends I_AbstractJpaDAO<T> { .....
However, I'm getting problems with "both methods have erasure, but neither overrides the other". Something to do with the Serialization thing I suspect. Can anyone help me please?
It means that, your base interface and abstract interface have the methods with the same signature and different return type.
Try this:
public interface userDAO extends I_AbstractJpaDAO<User> { .....