uniqueResult is deprecated in hibernate 5.2.2 ? how i can do? - spring

hi,everyone i am a newcomer for hibernate. i write code with struts+spring+hibernate ,i encounter a trouble in this code
import org.hibernate.Query;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.integration.entity.User;
public class UserDAOImpl extends HibernateDaoSupport implements UserDAO {
#Override
public User getUser(String name) {
// TODO Auto-generated method stub
String hsql="from User u where u.name='"+name+"'";
User result=(User)((Query) this.getHibernateTemplate().find(hsql)).uniqueResult();
return result;
}
the question is Query and uniqueResult() is deprecated ,how will i modify my code? thanks

The problem is not only in your method. The hole class HibernateDaoSupportis deprecated as it said here
I recommend you to configure your SessionFactory via Spring (as I see you use it) and use createQuery method to pass there your hql. Here is the example:
Configuring session factory:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"
p:packagesToScan="-your-model-"
p:hibernateProperties-ref="-your-properties-"
p:dataSource-ref="-your-datasource-"/>
The DAO method:
private final SessionFactory sessionFactory;
// Injecting session factory via constructor
#Autowired
public UserDAO(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
String hql="from User u where u.name=:name";
public User getByUsername(String name) {
return sessionFactory.getCurrentSession()
.createQuery(hql, User.class)
.setParameter("name", name)
.uniqueResult();
}
Also your code us not secure. You should use params of query for preventing sql injections. I show it in my method. Read about session factory and injecting it in DAO.
Good luck.
EDIT
Also it's just an example. You can configure everything as you wish (via java code, not xml for example)

Related

Spring JPA: javax.persistence.TransactionRequiredException: no transaction is in progress [duplicate]

I am new to Spring Transaction. Something that I found really odd, probably I did understand this properly.
I wanted to have a transactional around method level and I have a caller method within the same class and it seems like it does not like that, it has to be called from the separate class. I don't understand how is that possible.
If anyone has an idea how to resolve this issue, I would greatly appreciate. I would like to use the same class to call the annotated transactional method.
Here is the code:
public class UserService {
#Transactional
public boolean addUser(String userName, String password) {
try {
// call DAO layer and adds to database.
} catch (Throwable e) {
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
}
}
public boolean addUsers(List<User> users) {
for (User user : users) {
addUser(user.getUserName, user.getPassword);
}
}
}
It's a limitation of Spring AOP (dynamic objects and cglib).
If you configure Spring to use AspectJ to handle the transactions, your code will work.
The simple and probably best alternative is to refactor your code. For example one class that handles users and one that process each user. Then default transaction handling with Spring AOP will work.
Configuration tips for handling transactions with AspectJ
To enable Spring to use AspectJ for transactions, you must set the mode to AspectJ:
<tx:annotation-driven mode="aspectj"/>
If you're using Spring with an older version than 3.0, you must also add this to your Spring configuration:
<bean class="org.springframework.transaction.aspectj
.AnnotationTransactionAspect" factory-method="aspectOf">
<property name="transactionManager" ref="transactionManager" />
</bean>
In Java 8+ there's another possibility, which I prefer for the reasons given below:
#Service
public class UserService {
#Autowired
private TransactionHandler transactionHandler;
public boolean addUsers(List<User> users) {
for (User user : users) {
transactionHandler.runInTransaction(() -> addUser(user.getUsername, user.getPassword));
}
}
private boolean addUser(String username, String password) {
// TODO call userRepository
}
}
#Service
public class TransactionHandler {
#Transactional(propagation = Propagation.REQUIRED)
public <T> T runInTransaction(Supplier<T> supplier) {
return supplier.get();
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public <T> T runInNewTransaction(Supplier<T> supplier) {
return supplier.get();
}
}
This approach has the following advantages:
It may be applied to private methods. So you don't have to break encapsulation by making a method public just to satisfy Spring limitations.
Same method may be called within different transaction propagations and it is up to the caller to choose the suitable one. Compare these 2 lines:
transactionHandler.runInTransaction(() -> userService.addUser(user.getUserName, user.getPassword));
transactionHandler.runInNewTransaction(() -> userService.addUser(user.getUserName, user.getPassword));
It is explicit, thus more readable.
The problem here is, that Spring's AOP proxies don't extend but rather wrap your service instance to intercept calls. This has the effect, that any call to "this" from within your service instance is directly invoked on that instance and cannot be intercepted by the wrapping proxy (the proxy is not even aware of any such call). One solutions is already mentioned. Another nifty one would be to simply have Spring inject an instance of the service into the service itself, and call your method on the injected instance, which will be the proxy that handles your transactions. But be aware, that this may have bad side effects too, if your service bean is not a singleton:
<bean id="userService" class="your.package.UserService">
<property name="self" ref="userService" />
...
</bean>
public class UserService {
private UserService self;
public void setSelf(UserService self) {
this.self = self;
}
#Transactional
public boolean addUser(String userName, String password) {
try {
// call DAO layer and adds to database.
} catch (Throwable e) {
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
}
}
public boolean addUsers(List<User> users) {
for (User user : users) {
self.addUser(user.getUserName, user.getPassword);
}
}
}
With Spring 4 it's possible to Self autowired
#Service
#Transactional
public class UserServiceImpl implements UserService{
#Autowired
private UserRepository repository;
#Autowired
private UserService userService;
#Override
public void update(int id){
repository.findOne(id).setName("ddd");
}
#Override
public void save(Users user) {
repository.save(user);
userService.update(1);
}
}
This is my solution for self invocation:
public class SBMWSBL {
private SBMWSBL self;
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public void postContruct(){
self = applicationContext.getBean(SBMWSBL.class);
}
// ...
}
You can autowired BeanFactory inside the same class and do a
getBean(YourClazz.class)
It will automatically proxify your class and take into account your #Transactional or other aop annotation.
Here is what I do for small projects with only marginal usage of method calls within the same class. In-code documentation is strongly advised, as it may look strange to colleagues. But it works with singletons, is easy to test, simple, quick to achieve and spares me the full blown AspectJ instrumentation. However, for more heavy usage I'd advice the AspectJ solution as described in Espens answer.
#Service
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PersonDao {
private final PersonDao _personDao;
#Autowired
public PersonDao(PersonDao personDao) {
_personDao = personDao;
}
#Transactional
public void addUser(String username, String password) {
// call database layer
}
public void addUsers(List<User> users) {
for (User user : users) {
_personDao.addUser(user.getUserName, user.getPassword);
}
}
}
The issue is related to how spring load classes and proxies. It will not work , untill you write your inner method / transaction in another class or go to other class and then again come to your class and then write the inner nested transcation method.
To summarize, spring proxies does not allow the scenarios which you are facing. you have to write the 2nd transaction method in other class
There is no point to use AspectJ or Other ways. Just using AOP is sufficient. So, we can add #Transactional to addUsers(List<User> users) to solve current issue.
public class UserService {
private boolean addUser(String userName, String password) {
try {
// call DAO layer and adds to database.
} catch (Throwable e) {
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
}
}
#Transactional
public boolean addUsers(List<User> users) {
for (User user : users) {
addUser(user.getUserName, user.getPassword);
}
}
}

Spring alternative for Factory

May be its a duplicate, Please feel free to tag... I am a newbie to Spring.
I am implementing a UserService for getting user details from different vendors,
So My class Structure is
Interface UserService ->> UserServiceA, UserServiceB
Which user service to use depends upon a field called provider. my code will look something like
public interface ExternalUserService {
ExternalUserDTO getUserDetail(String username);
}
Implementations -
public class GoogleUserService implements ExternalUserService{
#Override
public ExternalUserDTO getUserDetail(String username) {
return user;
}
}
public class FacebookUserService implements ExternalUserService{
#Override
public ExternalUserDTO getUserDetail(String username) {
return user;
}
}
I want to use it in my code in this fashion, I dont know if this is possible, but giving a try to see if its possible
public class ExternalUserManager(String provider) {
String provider;
#Autowired
ExternalUserService service; //This is supposed to come from some factory, dont know how to get it in spring context.
public void doSomething(String username) {
System.out.println(service.getUserDetail(username));
}
}
Had it been in conventional java programming, I would have created a Factory called UserServiceFactory, which would have made the things straight.
Can someone please help me on how much it is possible with spring, and if its possible, then how can I achieve it? We use Spring boot, so no xml config.
You can use a #Bean annotated method with scope 'prototype' as a factory.
Spring will call this method anytime this bean is injected somewhere.
import org.springframework.beans.factory.config.BeanDefinition;
...
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public ExternalUserService externalUserService(UserServiceFactory factory,UserProviderResolver resolver) {
.. create the user service depending on resolver.getProvider()
}
The UserServiceFactory is used to create the specific service depending on the provider name, as you already described.
Create a class UserProviderResolver whith a method getProvider() that returns the provider name for the current request or user.
You can #Autowire the HttpRequest in the UserProviderResolver to get access to the current request.

org.springframework.orm.hibernate3.HibernateTemplate

We are using hibernate template by using the following package.
org.springframework.orm.hibernate3.HibernateTemplate;
protected HibernateTemplate template = null;
here template is from org.springframework.orm.hibernate3.HibernateTemplate package. I am not able to understand how to interpret this package.
is it the spring hibernate because package name starts with springframework. But there is no such spring hibernate. There is only ORM module i guess in spring.
Can anyone help me understand how to understand this package org.springframework.orm.hibernate3.HibernateTemplate.
update:
below is the exactly repository class I am using
#Repository
#Transactional
public class ABCDImplements ABCD {
private Log logger = LogFactory.getLog(this.getClass());
protected HibernateTemplate template = null;
#Resource(name = "abcSessionFactory")
protected SessionFactory sessionFactory;
#Autowired
public void init(SessionFactory sessionFactory) {
setSessionFactory(sessionFactory);
}
public void setSessionFactory(SessionFactory sessionFactory) {
template = new HibernateTemplate(sessionFactory);
}
}
Spring provides integration with Hibernate 3 and 4 under the form of HibernateTemplate, and the one you show provides integration with Hibernate 3.
The main goal of this class was to provide a Hibernate session via a callback, and another important functionality was to translate Hibernate exceptions to Spring exceptions.
The use of this class is not recommended anymore, have a look at this answer. The recommended way is to use the #Transactional annotation.

Proxy cannot be cast to CLASS

I'm using Spring for wiring dependencies specifically for DAO classes that use Hibernate, but I'm getting an exception that has me puzzled:
$Proxy58 cannot be cast to UserDao
My DAO is configured as follows:
<bean id="userDao" class="com.domain.app.dao.UserDao">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
And I have an interface, abstract base class and a final implementation as follows.
Interface:
public interface Dao {
public void save(Object object);
public Object load(long id);
public void delete(Object object);
public void setSessionFactory(SessionFactory sessionFactory);
}
Abstract Base Class:
public abstract class BaseDao implements Dao {
private SessionFactory sessionFactory;
#Transactional
#Override
public void save(Object object) {
PersistentEntity obj = (PersistentEntity) object;
currentSession().saveOrUpdate(obj);
}
#Transactional
#Override
public abstract Object load(long id);
#Transactional
#Override
public void delete(Object object) {
// TODO: this method!
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session currentSession() {
return sessionFactory.getCurrentSession();
}
}
Implementation:
public class UserDao extends BaseDao implements Dao {
#Transactional(readOnly=true)
#Override
public Object load(long id) {
Object user = currentSession().get(User.class, id);
return user;
}
}
The following throws the exception mentioned above:
UserDao dao = (UserDao) context.getBean("userDao");
This, however, does not throw an exception:
Dao dao = (Dao) context.getBean("userDao");
If anyone can offer any assistance or guidance as to why this exception is happening, I would be very appreciative.
Spring uses JDK dynamic proxies by default ($Proxy58 is one of them), that can only proxy interfaces. This means that the dynamically created type $Proxy58 will implement one or more of the interfaces implemented by the wrapped/target class (UserDao), but it won't be an actual subclass of it. That's basically why you can cast the userDao bean to the Dao interface, but not to the UserDao class.
You can use <tx:annotation-driven proxy-target-class="true"/> to instruct Spring to use CGLIB proxies that are actual subclasses of the proxied class, but I think it's better practice to program against interfaces. If you need to access some methods from the proxied class which are not declared in one of it's interfaces, you should ask yourself first, why this is the case?
(Also, in your code above there are no new methods introduced in UserDao, so there is no point in casting the bean to this concrete implementation type anyway.)
See more about different proxying mechanisms in the official Spring reference.
I was writing unit tests and needed to be able to stub out the DAOs for some calls.
Per This guys post:
http://www.techper.net/2009/06/05/how-to-acess-target-object-behind-a-spring-proxy/
I used his method provided:
#SuppressWarnings({"unchecked"})
protected <T> T getTargetObject(Object proxy, Class<T> targetClass) throws Exception {
if (AopUtils.isJdkDynamicProxy(proxy)) {
return (T) ((Advised)proxy).getTargetSource().getTarget();
} else {
return (T) proxy; // expected to be cglib proxy then, which is simply a specialized class
}
}
Then you can easily call it with the proxy and get the object behind the proxy and manipulate the objects in it directly as needed.

HibernateTemplate is null

I am making a web application on STS. I am using jars of Spring 3.1.0 and HIbernate 4.0.1. I am including jars in project build path.
In DAO layer when I am trying to make a HibernateTemplate object , it is not getting instantiate, It is null there. I don't understand why it is null.
Earlier I was getting an error like NoClassDefinitionFound: org.springframework.orm.hibernate3.HibernateTemplate....Then I included these jars in WEB-INF->lib folder and then this error was removed but still hibernateTemplate object is null. Can there be any issue regarding position of beans.xml in project folders. ? Can anyone help me.
Below is code for my beans.xml and Userinfo.java.
[b]Beans.xml[/b]
Only relevant part of bean.xml
<bean id="hibTemplateBean" class="org.springframework.orm.hibernate3.HibernateTemplate" >
<property name="sessionFactory" ref="sfBean" />
</bean>
[b]UserinfoDao.java[/b]
package com.home.dao;
import org.springframework.orm.hibernate3.HibernateTemplate;
import com.home.pojo.User;
public class UserinfoDao {
public UserinfoDao() {
super();
}
private static HibernateTemplate hibernateTemplate;
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
UserinfoDao.hibernateTemplate = hibernateTemplate;
}
public static void fetchUserInfo(){
try{
User user = (User)hibernateTemplate.get(User.class, 111);
}catch(NullPointerException npe){
npe.printStackTrace();
}
}
}
You are using Hibernate 4 and you are using org.springframework.orm.hibernate3.HibernateTemplate from Hibernate 3 package.
This template is not supported anymore. You can do declarative transaction management.
Your version makes me believe that you are simply accessing your bean with static method:
UserinfoDao.fetchUserInfo();
Looks like you are missing few key points of Spring. First of all you should not use static methods and fields, try with the following class:
public class UserinfoDao {
private HibernateTemplate hibernateTemplate;
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
public void fetchUserInfo(){
try{
User user = (User)hibernateTemplate.get(User.class, 111);
}catch(NullPointerException npe){
npe.printStackTrace();
}
}
}
Now you need to obtain an instance of Spring bean somehow. You cannot simply use new UserinfoDao() operator. You must either declare your bean in XML or via annotations (and declare dependency on HibernateTemplate.
Finally you shouldn't normally catch NullPointerException, but I understand this if for ddebugging purposes.

Resources