Spring #Transactional not working - spring

I previously had a post on this issue that was resolved. However since rebuilding the project with auto wired beans and less XML configuration I find I am revisiting this issue. I have followed the way my previous project implemented this but it doesn't work. Can someone help me with why or what I should change to make it work?
I am on purpose using a non existent table name in the insert user details method to deliberately throw an exception. However the statements for insert user and insert user roles are not rolled back. Please help.
My current design for the registration is like this.
Part of servlet.xml:
<context:component-scan base-package="com.doyleisgod.golfer.controllers"/>
<context:component-scan base-package="com.doyleisgod.golfer.dao"/>
<context:component-scan base-package="com.doyleisgod.golfer.services"/>
<context:component-scan base-package="com.doyleisgod.golfer.validators"/>
Part of application context:
<context:annotation-config />
<tx:annotation-driven />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
Registration controller:
package com.doyleisgod.golfer.controllers;
import javax.validation.Valid;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.doyleisgod.golfer.formdata.RegistrationForm;
import com.doyleisgod.golfer.services.IRegistrationService;
import com.doyleisgod.golfer.validators.RegistrationFormValidator;
/**
* Description: Registration controller provides and processes the registration form.
* #author Chris Doyle
*/
#Controller
#RequestMapping("/registration.htm")
public class RegistrationController {
protected final Log logger = LogFactory.getLog(getClass());
#Autowired private IRegistrationService iRegistrationService;
#Autowired private RegistrationFormValidator registrationFormValidator;
// sets a customer validator for the registration form
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(registrationFormValidator);
}
// Description: Method called by a get request to the registration controller. Returns the
#RequestMapping(method=RequestMethod.GET)
public String registration (Model model){
model.addAttribute(new RegistrationForm());
return "registration";
}
// Description: Method called by a post request to the registration controller. Method calls validation on the registration form using custom validator and returning
// any errors back to the user.
#RequestMapping(method=RequestMethod.POST)
public String processRegistration (#Valid RegistrationForm registrationForm, BindingResult bindingResult, Model model){
logger.info("Received the following registration form details");
logger.info(registrationForm.toString());
if (bindingResult.hasErrors()) {
logger.warn("Registration Validation Failed");
model.addAttribute("validationError", "Please correct the fields marked with errors");
return "registration";
}
try {
iRegistrationService.registerUser(registrationForm);
} catch (Exception e) {
logger.error("An Exception has occured processing the registration form");
model.addAttribute("exceptionError", "An exception has occured, please try again.");
e.printStackTrace();
return "registration";
}
return "redirect:login.htm?registration=sucessful";
}
}
Registration service:
package com.doyleisgod.golfer.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import com.doyleisgod.golfer.dao.IRegistrationDAO;
import com.doyleisgod.golfer.formdata.RegistrationForm;
#Service("IRegistrationService")
public class RegistrationService implements IRegistrationService {
#Autowired private IRegistrationDAO iRegistrationDAO;
private final boolean enabled = true;
private final String roles = "ROLE_USER";
#Override
#Transactional (rollbackFor = Exception.class)
public void registerUser(RegistrationForm registrationForm) throws Exception {
System.out.println("inside the registerUser method. is wrapped in transaction: "+TransactionSynchronizationManager.isActualTransactionActive());
String username = registrationForm.getUsername();
String password = registrationForm.getPassword();
String firstname = registrationForm.getFirstname();
String lastname = registrationForm.getLastname();
String email = registrationForm.getEmail();
int handicap = Integer.parseInt(registrationForm.getHandicap());
String encryptedPassword = ((new ShaPasswordEncoder()).encodePassword(password, username));
iRegistrationDAO.insertUser(username, encryptedPassword, enabled);
iRegistrationDAO.insertRoles(username, roles);
iRegistrationDAO.insertUserDetails(username, firstname, lastname, email, handicap);
}
#Override
public boolean checkUser(String username) {
return iRegistrationDAO.checkUserName(username);
}
}
Registration DAO:
package com.doyleisgod.golfer.dao;
import javax.annotation.Resource;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.support.TransactionSynchronizationManager;
#Repository("iRegistrationDAO")
public class RegistrationDAO extends JdbcTemplate implements IRegistrationDAO {
#Resource private BasicDataSource dataSource;
#Override
public boolean checkUserName(String username) {
int db_user = queryForInt("select count(username) from users where username = ?", username);
if (db_user == 1 ){
return true;
}
return false;
}
#Override
public void insertUser(String username, String password, boolean enabled) throws Exception {
System.out.println("inside the insertuser method. is wrapped in transaction: "+TransactionSynchronizationManager.isActualTransactionActive());
update("insert into users (username, password, enabled) VALUES (?,?,?)", username, password, enabled);
}
#Override
public void insertRoles(String username, String roles) throws Exception {
update("insert into user_roles (username, authority) VALUES (?,?)", username, roles);
}
#Override
public void insertUserDetails(String username, String firstname, String lastname, String email, int handicap) throws Exception {
update("insert into user_detailss (username, first_name, last_name, email_address, handicap)" +
"VALUES (?,?,?,?,?)", username, firstname, lastname, email, handicap);
}
public void setDataSource(BasicDataSource dataSource) {
this.dataSource = dataSource;
}
public BasicDataSource getDataSource() {
return dataSource;
}
}

The reason that moving the context:component-scan tags to the application context xml fixed the transactional behavior is: <tx:annotation-driven /> is a post-processor that wraps #Transactional annotated bean methods with an AOP method interceptor which handles transactional behavior. Spring post-processors, only operate on the specific application context they are defined in.
In your case, you have defined the <tx:annotation-driven /> post-processor in the application context, while the beans annotated with #Transactional are in the servlet application context. Thus, the <tx:annotation-driven /> post-processor only operated on the application context beans, not the servlet context beans. When the context:component-scan tags were moved to the application context, then the <tx:annotation-driven /> post-processor wrapped their transactional methods appropriately.
Hope that makes some sense.
[Edit]
What is the difference between the Application Context and a Servlet Context?
What is a Spring post-processor and how does it work?
What is AOP in Spring?

Related

Spring Web MVC validation by Hibernate Validator doesn't draw Errors in BindingResult

I've been using Hibernate Validator in my Spring project. I'm about to validate my JUser Object automatically. i.e, I want Spring to validate the Object and set errors in BindigResult. But It doesn't work.
pom.xml
<properties>
<spring.version>4.3.5.RELEASE</spring.version>
<spring.security.version>4.0.2.RELEASE</spring.security.version>
<hibernate.version>4.3.11.Final</hibernate.version>
<validation-api.version>1.1.0.Final</validation-api.version>
<hibernate-validator.version>5.4.0.Final</hibernate-validator.version>
</properties>
....
applicationContext.xml
...
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>
<context:annotation-config />
<context:component-scan base-package="my.project.controller" />
<mvc:annotation-driven validator="validator">
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages"/>
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
</bean>
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">
<property name="validator" ref="validator"/>
</bean>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="en" />
</bean>
JUser.java
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
#Entity
public class JUser implements Officeable {
#Id
private Long id;
#Column(unique = true, nullable = false)
private String username;
private String password;
#NotEmpty
private String firstName;
#NotEmpty
private String lastName;
private String tel;
}
UserController.java
import javax.validation.ConstraintViolationException;
....
#RequestMapping(value = "/update", method = RequestMethod.POST)
public String update2(HttpServletRequest request, Model model, #ModelAttribute("user") #Valid JUser user, BindingResult result) {
if (!result.hasErrors()) {
System.out.println("binding result has no errors for user ");
try {
JUser updated = userService.update(user);
model.addAttribute("user", updated);
} catch (MessageException | DataIntegrityViolationException ex) {
result.reject("user", ex.getMessage());
} catch (ConstraintViolationException cvex) {
for (ConstraintViolation cv : cvex.getConstraintViolations()) {
result.rejectValue(cv.getPropertyPath().toString(),cv.getMessageTemplate() , cv.getMessage());
}
}
}
return "user/manage";
}
As you see in the above controller method I want Spring to validate the user Object and set errors in BindigResult. But It does not work.
For example when user has empty firstName I face the output:
output:
binding result has no errors for user
and I have to catch hibernate thrown exceptions by hand:
ConstraintViolationException: may not be empty ...
more description. I've used String #Validated annotation and It did not work as well. I've read more than ten related stackoverflow questions and they didn't solved my problem.
First thing, can you test if validate is working after adding below code?
pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
#Bean // in configuration
public Validator validator() {
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
return validatorFactory.getValidator();
}
#Autowired //in controller
private Validator validator;
public <T> void validate(T t) {
Set validate = this.validator.validate(t);
if(!validate.isEmpty()) {
throw new RuntimeException();
}
}
If this works, then can suggest you further to simplify it.
As per spring-mvc-4.3.xsd
The bean name of the Validator that is to be used to validate
Controller model objects. This attribute is not required, and only
needs to be specified if a custom Validator needs to be configured. If
not specified, JSR-303 validation will be installed if a JSR-303
provider is present on the classpath.
I don't see you wrote any custom validator so you can change
<mvc:annotation-driven validator="validator">
to support the default JSR-303
<mvc:annotation-driven />
Example: Spring 3 MVC and JSR303 #Valid example
Update 1
Could you also try removing validation-api.version
This transitively pulls in the dependency to the Bean Validation API
(javax.validation:validation-api:1.1.0.Final).
You can use the ExceptionHandler approach. Just add this method in your controller class. I haven't tested this with the #ModelAttribute although it should work, I know for sure that it works with #RequestBody.
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public ErrorDTO processValidationError(MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
List<FieldError> fieldErrors = result.getFieldErrors();
// your own custom error dto class
ErrorDTO errorDto = constructErrors(fieldErrors);
return errorDto;
}
If you are using HibernateValidator you must tell to use the HibernateValidator class
By looking the LocalValidatorFactoryBean javadoc
When talking to an instance of this bean through the Spring or JSR-303 Validator interfaces, you'll be talking to the default Validator of the underlying ValidatorFactory. This is very convenient in that you don't have to perform yet another call on the factory, assuming that you will almost always use the default Validator anyway. This can also be injected directly into any target dependency of type Validator!
So you should use the setProviderClass method in order to specify what class to use
Here it's what I did (i'm using annotation based config but it's the same):
WebMvcConfig
#Override
public Validator getValidator() {
LocalValidatorFactoryBean lvfb = new LocalValidatorFactoryBean();
lvfb.setProviderClass(HibernateValidator.class);
return lvfb;
}
Model:
#Entity
#Table(name = "CANDIDATO")
public class Candidato extends AbstractModel {
private static final long serialVersionUID = -5648780121365553697L;
.
.
.
private String corsoLaurea;
.
.
.
#Column(name="CORSO_LAUREA", nullable=true)
#NotEmpty
public String getCorsoLaurea() {
return corsoLaurea;
}
}
controller method
#RequestMapping(method = { RequestMethod.PUT }, value = { "/salvaModificheCandidato" })
public ResponseEntity<BaseResponse<String>> modificaCandidato(#RequestBody #Valid ModificaCandidatoDto dto, BindingResult bindResult) throws Exception
{
BaseResponse<String> result = null;
HttpStatus status = null;
try
{
this.candidatoSvc.modificaCandidato(dto);
result = new BaseResponse<String>();
status = HttpStatus.OK;
result.setDescrizioneOperazione("Aggiornamento candidato terminato correttamente");
result.setEsitoOperazione(status.value());
result.setPayload(Collections.EMPTY_LIST);
}
catch (Exception e)
{
result = new BaseResponse<String>();
status = HttpStatus.INTERNAL_SERVER_ERROR;
String message = "Errore nella modifica del candicato con ID "+dto.getIdCandidato()+"; "+e.getMessage();
logger.error(message, e);
result.setDescrizioneOperazione(message);
result.setEsitoOperazione(status.value());
}
return new ResponseEntity<BaseResponse<String>>(result, status);
}
With this configuration I find in bindinresult errors for both the DTO and the Model
I hope this can be useful
EDITED PART
I saw that your issue is to have the bindingresult not empty when you try to persist your object; I changed my code in this way
No change to the model (I used the hibernate validation NotEmpty annotation)
I changed my service method in this way:
#Override
#Transactional(transactionManager = "hibTx", rollbackFor = CandidatiDbException.class, readOnly = false)
public void modificaCandidato(ModificaCandidatoDto dto, BindingResult brErrors) throws CandidatiDbException {
try
{
dao.modificaCandidato(dto, brErrors);
} catch (Exception e)
{
String message = "Errore nella modifica del candidato con ID "+dto.getIdCandidato()+"; "+e.getMessage();
logger.error(message, e);
throw new CandidatiDbException(message);
}
}
As you can see I passed the BindingResult object to the method
Then I changed my DAO impl in this way:
public class CandidatoDaoImpl<T> implements ICandidatoDao<T> {
#Autowired
#Qualifier("candValidator")
Validator validator;
public void modificaCandidato(ModificaCandidatoDto dto, BindingResult brErrors) {
Session sessione = getSession();
sessione.setCacheMode(CacheMode.IGNORE);
Candidato candidato = sessione.load(Candidato.class, dto.getIdCandidato());
.
.
.
validator.validate(candidato, brErrors);
if( !brErrors.hasErrors() )
{
sessione.saveOrUpdate(candidato);
}
}
}
Finally I updated my WebMvcConfig in this way:
#Configuration
#EnableWebMvc
#Import(SharedSpringConfig.class)
#PropertySource( value={"classpath:configuration.properties"}, encoding="UTF-8", ignoreResourceNotFound=false)
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Bean(name="candValidator")
public Validator validator()
{
LocalValidatorFactoryBean lvfb = new LocalValidatorFactoryBean();
lvfb.setProviderClass(HibernateValidator.class);
return lvfb;
}
#Override
public Validator getValidator() {
return validator();
}
}
In this way when I have some error on the object I want to persist I have the BindingResult object not empty and no exception is raised
I hope this can be useful
Angelo

Spring JAAS Authentication with database authorization

I am using Spring security 4.0. My login module is configured in Application server so I have to do authentication using JAAS but my user details are stored in database, so once authenticated user object will be created by querying database. Could you please let me know how to achieve this i.e. LDAP authentication and load user details from database. Also how cache the user object using eh-cache, so that the user object can be accessed in the service / dao layer.
This can be achieved using CustomAuthentication Provider. Below are the codes.
import java.util.Arrays;
import java.util.List;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.authentication.jaas.JaasGrantedAuthority;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.sun.security.auth.UserPrincipal;
public class CustomAutenticationProvider extends DaoAuthenticationProvider implements AuthenticationProvider {
private AuthenticationProvider delegate;
public CustomAutenticationProvider(AuthenticationProvider delegate) {
this.delegate = delegate;
}
#Override
public Authentication authenticate(Authentication authentication) {
Authentication a = delegate.authenticate(authentication);
if(a.isAuthenticated()){
a = super.authenticate(a);
}else{
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
return a;
}
private List<GrantedAuthority> loadRolesFromDatabaseHere(String name) {
GrantedAuthority grantedAuthority =new JaasGrantedAuthority(name, new UserPrincipal(name));
return Arrays.asList(grantedAuthority);
}
#Override
public boolean supports(Class<?> authentication) {
return delegate.supports(authentication);
}
/* (non-Javadoc)
* #see org.springframework.security.authentication.dao.DaoAuthenticationProvider#additionalAuthenticationChecks(org.springframework.security.core.userdetails.UserDetails, org.springframework.security.authentication.UsernamePasswordAuthenticationToken)
*/
#Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
if(!authentication.isAuthenticated())
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
}
UserDetails required for DAOAuthentication
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import com.testjaas.model.User;
import com.testjaas.model.UserRepositoryUserDetails;
#Component
public class AuthUserDetailsService implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("loadUserByUsername called !!");
com.testjaas.model.User user = new User();
user.setName(username);
user.setUserRole("ROLE_ADMINISTRATOR");
if(null == user) {
throw new UsernameNotFoundException("User " + username + " not found.");
}
return new UserRepositoryUserDetails(user);
}
}
RoleGrantor - This will be a dummy class required for Spring JAAS authentication
import java.security.Principal;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.springframework.security.authentication.jaas.AuthorityGranter;
public class RoleGranterFromMap implements AuthorityGranter {
private static Map<String, String> USER_ROLES = new HashMap<String, String>();
static {
USER_ROLES.put("test", "ROLE_ADMINISTRATOR");
//USER_ROLES.put("test", "TRUE");
}
public Set<String> grant(Principal principal) {
return Collections.singleton("DUMMY");
}
}
SampleLogin - This should be replaced with your login module
import java.io.Serializable;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
public class SampleLoginModule implements LoginModule {
private Subject subject;
private String password;
private String username;
private static Map<String, String> USER_PASSWORDS = new HashMap<String, String>();
static {
USER_PASSWORDS.put("test", "test");
}
public boolean abort() throws LoginException {
return true;
}
public boolean commit() throws LoginException {
return true;
}
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options) {
this.subject = subject;
try {
NameCallback nameCallback = new NameCallback("prompt");
PasswordCallback passwordCallback = new PasswordCallback("prompt",false);
callbackHandler.handle(new Callback[] { nameCallback,passwordCallback });
this.password = new String(passwordCallback.getPassword());
this.username = nameCallback.getName();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public boolean login() throws LoginException {
if (USER_PASSWORDS.get(username) == null
|| !USER_PASSWORDS.get(username).equals(password)) {
throw new LoginException("username is not equal to password");
}
subject.getPrincipals().add(new CustomPrincipal(username));
return true;
}
public boolean logout() throws LoginException {
return true;
}
private static class CustomPrincipal implements Principal, Serializable {
private final String username;
public CustomPrincipal(String username) {
this.username = username;
}
public String getName() {
return username;
}
}
}
Spring XML configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<security:http auto-config="true">
<security:intercept-url pattern="/*" access="isAuthenticated()"/>
</security:http>
<!-- <security:authentication-manager>
<security:authentication-provider ref="jaasAuthProvider" />
</security:authentication-manager> -->
<bean id="userDetailsService" class="com.testjaas.service.AuthUserDetailsService"></bean>
<bean id="testService" class="com.testjaas.service.TestService"/>
<bean id="applicationContextProvider" class="com.testjaas.util.ApplicationContextProvider"></bean>
<security:authentication-manager>
<security:authentication-provider ref="customauthProvider"/>
</security:authentication-manager>
<bean id="customauthProvider" class="com.testjaas.security.CustomAutenticationProvider">
<constructor-arg name="delegate" ref="jaasAuthProvider" />
<property name="userDetailsService" ref="userDetailsService" />
</bean>
<bean id="jaasAuthProvider" class="org.springframework.security.authentication.jaas.JaasAuthenticationProvider">
<property name="loginConfig" value="classpath:pss_jaas.config" />
<property name="authorityGranters">
<list>
<bean class="com.testjaas.security.RoleGranterFromMap" />
</list>
</property>
<property name="loginContextName" value="JASSAuth" />
<property name="callbackHandlers">
<list>
<bean class="org.springframework.security.authentication.jaas.JaasNameCallbackHandler" />
<bean class="org.springframework.security.authentication.jaas.JaasPasswordCallbackHandler" />
</list>
</property>
</bean>
</beans>
Sample jaas config
JASSAuth {
com.testjaas.security.SampleLoginModule required;
};

java.lang.NullPointerException on #Inject Dao

I'm trying to Inject a DAO into #Service component, but I get this error :
Exception in thread "main" java.lang.NullPointerException at
it.cle.project.service.impl.TestEntityServiceImpl.getListTestEntity(TestEntityServiceImpl.java:24).
Fails to call the DAO which is null despite the annotation #Autowired
Below my code:
context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- INIZIO IMPOSTAZIONI LEGATE ALLE ANNOTATIONS -->
<tx:annotation-driven/>
<context:property-placeholder location="classpath:hibernate.properties"/>
<context:component-scan base-package="it.cle.project.service.impl" />
<context:component-scan base-package="it.cle.project.dao.hbn" />
<context:component-scan base-package="it.cle.project.dao.hibernate" />
<!-- FINE IMPOSTAZIONI LEGATE ALLE ANNOTATIONS -->
<!-- INIZIO IMPOSTAZIONI LEGATE AD ALTRI FILE DI CONFIGURAZIONE -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:hibernate.properties"/>
</bean>
<!-- FINE IMPOSTAZIONI LEGATE AD ALTRI FILE DI CONFIGURAZIONE -->
<!-- INIZIO IMPOSTAZIONI LEGATE ALLA CONNESSIONE -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory" />
<util:properties id="hibernateProperties">
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl_auto}</prop>
</util:properties>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean "
p:dataSource-ref="dataSource" p:packagesToScan="it.cle.project.model"
p:hibernateProperties-ref="hibernateProperties" />
<!-- FINE IMPOSTAZIONI LEGATE ALLA CONNESSIONE -->
App.java
package it.cle.project;
import it.cle.project.model.TestEntity;
import it.cle.project.service.impl.TestEntityServiceImpl;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App
{
public static void main( String[] args )
{
ApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
System.out.println( "Hello World!" );
TestEntity testEntity = new TestEntity();
testEntity.setCampoUno("Campo Uno");
testEntity.setCampoDue("Campo Due");
testEntity.setEmail("email#test.it");
TestEntityServiceImpl testEntityServiceImpl = new TestEntityServiceImpl();
List<TestEntity> testEntitys = testEntityServiceImpl.getListTestEntity();
}
}
DAO Interface
package it.cle.project.dao;
import java.io.Serializable;
import java.util.List;
public interface Dao<T extends Object> {
void create(T t);
T get(Serializable id);
T load(Serializable id);
List<T> getAll();
void update(T t);
void delete(T t);
void deleteById(Serializable id);
void deleteAll();
long count();
boolean exists(Serializable id);
}
TestEntityDAO interface
package it.cle.project.dao;
import it.cle.project.model.TestEntity;
import java.util.List;
public interface TestEntityDao extends Dao<TestEntity> {
List<TestEntity> findByEmail(String email);
}
AbstractHbnDao Abstract class:
package it.cle.project.dao.hibernate;
import it.cle.project.dao.Dao;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.Date;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;
#Service
public abstract class AbstractHbnDao<T extends Object> implements Dao<T> {
#Autowired
private SessionFactory sessionFactory;
private Class<T> domainClass;
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
#SuppressWarnings("unchecked")
private Class<T> getDomainClass() {
if (domainClass == null) {
ParameterizedType thisType =
(ParameterizedType) getClass().getGenericSuperclass();
this.domainClass =
(Class<T>) thisType.getActualTypeArguments()[0];
}
return domainClass;
}
private String getDomainClassName() {
return getDomainClass().getName();
}
public void create(T t) {
Method method = ReflectionUtils.findMethod(
getDomainClass(), "setDataCreazione",
new Class[] { Date.class });
if (method != null) {
try {
method.invoke(t, new Date());
} catch (Exception e) { /* Ignore */ }
}
getSession().save(t);
}
#SuppressWarnings("unchecked")
public T get(Serializable id) {
return (T) getSession().get(getDomainClass(), id);
}
#SuppressWarnings("unchecked")
public T load(Serializable id) {
return (T) getSession().load(getDomainClass(), id);
}
#SuppressWarnings("unchecked")
public List<T> getAll() {
return getSession()
.createQuery("from " + getDomainClassName())
.list();
}
public void update(T t) { getSession().update(t); }
public void delete(T t) { getSession().delete(t); }
public void deleteById(Serializable id) { delete(load(id)); }
public void deleteAll() {
getSession()
.createQuery("delete " + getDomainClassName())
.executeUpdate();
}
public long count() {
return (Long) getSession()
.createQuery("select count(*) from " + getDomainClassName())
.uniqueResult();
}
public boolean exists(Serializable id) { return (get(id) != null); }
}
HbnTestEntityDao class DAO
package it.cle.project.dao.hbn;
import it.cle.project.dao.TestEntityDao;
import it.cle.project.dao.hibernate.AbstractHbnDao;
import it.cle.project.model.TestEntity;
import java.util.List;
import org.springframework.stereotype.Repository;
#Repository
public class HbnTestEntityDao extends AbstractHbnDao<TestEntity> implements TestEntityDao {
#SuppressWarnings("unchecked")
public List<TestEntity> findByEmail(String email) {
return getSession()
.getNamedQuery("findContactsByEmail")
.setString("email", "%" + email + "%")
.list();
}
}
TestEntityService interface service
package it.cle.project.service;
import it.cle.project.model.TestEntity;
import java.util.List;
public interface TestEntityService {
void createTestEntity(TestEntity testEntity);
List<TestEntity> getListTestEntity();
List<TestEntity> getTestEntityByEmail(String email);
TestEntity getTestEntity(Integer id);
void updateTestEntity(TestEntity testEntity);
void deleteTestEntity(Integer id);
}
TestEntityServiceImpl
package it.cle.project.service.impl;
import it.cle.project.dao.TestEntityDao;
import it.cle.project.model.TestEntity;
import it.cle.project.service.TestEntityService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
#Service
#Transactional
public class TestEntityServiceImpl implements TestEntityService {
#Autowired
private TestEntityDao testEntityDao;
public void createTestEntity(TestEntity testEntity) {
testEntityDao.create(testEntity);
}
public List<TestEntity> getListTestEntity() {
return testEntityDao.getAll();
}
public List<TestEntity> getTestEntityByEmail(String email) {
return testEntityDao.findByEmail(email);
}
public TestEntity getTestEntity(Integer id) {
return testEntityDao.get(id);
}
public void updateTestEntity(TestEntity testEntity) {
testEntityDao.update(testEntity);
}
public void deleteTestEntity(Integer id) {
testEntityDao.deleteById(id);
}
}
Any ideas?
Thanks.
Your TestServiceImpl should be spring managed bean and should be fetched from Spring application context (by injection or by explicit asking the context). As the component scanning is at work, your TestServiceImpl is already managed with Spring's own supplied name (com...TestServiceImpl becomes testServiceImpl). You can give it your name like
#Service("myTestServiceImpl")
The instead of creating the bean yourself you can query this named bean from application context and use it.
That's some wall of text. I stopped at:
TestEntityServiceImpl testEntityServiceImpl = new TestEntityServiceImpl();
You created an unmanaged bean. Spring has no control over that. Put TestEntityServiceImpl into your spring context.

No Session found for current thread (HIBERNATE)

OK JAVA guru ))
I really new to spring and I got into this trouble with "No session found the current thread" when I refer to the following page JSP security after login. Up to this point everything is working.
I need your help guys!!!!!
Here is my controller for that page:
package employee.controller;
import employee.service.AdminService;
import employee.service.UserService;
import org.apache.log4j.Logger;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.annotation.Resource;
/**
* #author serge
*
* Handles and retrieves the common or admin page depending on the URI template.
* A user must be log-in first he can access these pages. Only the admin can see
* the adminpage, however.
*/
#Controller
#RequestMapping("/main")
public class MainController {
protected static Logger logger = Logger.getLogger("controller");
#Resource(name = "adminService")
private AdminService adminService;
#Resource(name = "userService")
private UserService userService;
/**
* Handles and retrieves a /WEB-INF/jsp/employee-page.jsp
*
* containing all employee
*
* #return the name of the JSP page
*/
#Secured("ROLE_USER")
#RequestMapping(value = "/employee-list",method = RequestMethod.GET)
public String getEmployeeListPage(Model model) {
logger.debug("Received request to show all employee page");
// Retrieve all employee and attach to model
model.addAttribute("all-employee", userService.findAllEmployee());
return "employee-page";
}
/**
* Handles and retrieves /WEB-INF/jsp/admin-page.jsp that only admins can see
*
* #return the name of the JSP page
*/
#Secured("ROLE_ADMIN")
#RequestMapping(value = "/admin", method = RequestMethod.GET)
public String getAdminPage() {
logger.debug("Received request to show admin page");
return "admin-page";
}
}
This is user service that had been called from controller:
package employee.service.impl;
import employee.DAO.EmployeeInfoDAO;
import employee.model.EmployeeInfo;
import employee.service.UserService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* #author serge
*
* Reader level
*
* Service to Retrieve info about Employees
*/
#Service("userService")
#Transactional
public class UserServiceImpl implements UserService {
protected static Logger logger = Logger.getLogger("service");
private EmployeeInfoDAO emplInfoDAO;
#Autowired
public void setEmployeeDao(EmployeeInfoDAO emplInfoDAO) {
this.emplInfoDAO = emplInfoDAO;
}
/**
* Retrieving Employee Information by id
*
* #return EmployeeInfo object
*/
#Override
#Transactional
#Secured("ROLE_USER")
public EmployeeInfo findEmployeeByID(Integer id) {
logger.debug("Retrieving Employee with id= " + id);
EmployeeInfo employeeInfo = new EmployeeInfo();
employeeInfo.setId(id);
emplInfoDAO.find(employeeInfo);
return employeeInfo;
}
/**
* Retrieving all Employees
*
* #return List of EmployeeInfo object
*/
#Override
#Secured("ROLE_USER")
#Transactional(readOnly = true)
public List<EmployeeInfo> findAllEmployee() {
logger.debug("Retrieving all Employee");
return emplInfoDAO.findAll();
}
/**
* Retrieving Employees by last name
*
* #return List of EmployeeInfo object
*/
#Override
#Secured("ROLE_USER")
#Transactional(readOnly = true)
public List<EmployeeInfo> findAllByLastName(String lastName, Object paramValue) {
lastName = "lastName";
logger.debug("Retrieving Employee by last name: " + paramValue);
return emplInfoDAO.findAllByParam(lastName, paramValue);
}
/**
* Retrieving Employees by first name
*
* #return List of EmployeeInfo object
*/
#Override
#Secured("ROLE_USER")
#Transactional(readOnly = true)
public List<EmployeeInfo> findAllByFirstName(String firstName, Object paramValue) {
firstName = "firstName";
logger.debug("Retrieving Employee by first name: " + paramValue);
return emplInfoDAO.findAllByParam(firstName, paramValue);
}
}
And this is custom DAO support, not sure if this is right way to do that.... :
package employee.DAO.impl;
import employee.DAO.DAO;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
public class CustomHibernateDaoSupport<T> implements DAO<T> {
//was extending HibernateDaoSupport
private Class<T> clazz;
private SessionFactory sessionFactory;
public CustomHibernateDaoSupport(Class<T> clazz) {
this.clazz = clazz;
}
#Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
private Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
#Override
#Transactional
public void save(T entity) {
getCurrentSession().save(entity);
}
#Override
#Transactional
public void update(T entity) {
getCurrentSession().update(entity);
}
#Override
#Transactional
public void delete(Serializable key) {
Object entity = getCurrentSession().get(clazz, key);
if (entity != null) {
getCurrentSession().delete(entity);
}
}
#Override
#Transactional
public T find(Serializable key) {
return (T) getCurrentSession().get(clazz, key);
}
#Override
#Transactional
public List<T> findAll() {
return getCurrentSession().createCriteria(clazz).list();
}
#Override
#Transactional
public List<T> findAllByParam(final String paramName, final Object paramValue) {
return getCurrentSession().createCriteria(clazz)
.add(Restrictions.eq(paramName, paramValue))
.list();
}
}
And of course configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<!-- Activates annotations -->
<context:annotation-config />
<mvc:annotation-driven/>
<!-- Scans for annotated components in base-package-->
<context:component-scan base-package="employee" />
<bean class="employee.service.impl.AdminServiceImpl"/>
<bean class="employee.service.impl.UserServiceImpl"/>
<!-- Shared Hibernate SessionFactory in a Spring application context. -->
<bean id = "transactionManager" class = "org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="annotatedClasses">
<list>
<value>employee.model.UserInfo</value>
<value>employee.model.EmployeeInfo</value>
<value>employee.model.EmployeeDiv</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- for database, imports the properties from database.properties -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:database.properties"/>
</bean>
</beans>
after a successful login, I called /employee-list and got this instead of the page:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.HibernateException: No Session found for current thread
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
...
org.hibernate.HibernateException: No Session found for current thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:941)
employee.DAO.impl.CustomHibernateDaoSupport.getCurrentSession(CustomHibernateDaoSupport.java:31)
employee.DAO.impl.CustomHibernateDaoSupport.findAll(CustomHibernateDaoSupport.java:64)
...
Please help me understand where is my mistake, maybe I made a wrong configuration?
If you have dispatch-servlet.xml, add the
<tx:annotation-driven />
Or there is an alternative:
Please see this:
this blog

#PostConstruct method is not called in Spring

SampleBean:
package com.springexample;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class SampleBean {
private BeanTypeOne beanOne;
private BeanTypeTwo beanTwo;
public void init() {
System.out.println("This is from the init() method");
}
#PostConstruct
public void initAnnotation() {
System.out.println("This is from the initAnnotation() method");
}
and config file like this :
<bean id="SampleBean" class="com.springexample.SampleBean">
<property name="beanOne" ref="beanOneOne"></property>
<property name="beanTwo" ref="beanTwoOne"></property>
</bean>
And I don't have default-init-method attribute set on the beans tag.
Can any body tell why the #PostConstruct method does not get called.
You need <context:annotation-config/> (or <context:component-scan/>) to enable #PostConstruct handling.

Resources