Spring 3 validation not working - java

I have a user entity in my application which I need to validate.
public class User {
private String userName;
private String password;
public void setUserName(String userName){
this.userName = userName;
}
public getUserName(){
return this.userName;
}
// and so on
}
For this I have created a UsersValidator like below.
public class UserValidator implements Validator {
public boolean supports(Class clazz) {
return User.class.equals(clazz);
}
public void validate(Object obj, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName", "field.required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "field.required");
}
}
and I have a controller like this
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String home(#Valid User user,
BindingResult result) {
if (result.hasErrors()) {
return "loginForm";
} else {
//continue
}
}
The binding result does not have any errors.
What else I need to do in order for the validation to work? Do I have make any changes in the controller or the spring configuration file.
<mvc:annotation-driven />
<context:component-scan base-package="com.myapp" />
<mvc:resources location="/resources/" mapping="/resources/**" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass">
<value>org.springframework.web.servlet.view.tiles2.TilesView</value>
</property>
</bean>
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles.xml</value>
</list>
</property>
</bean>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>com/dimex/resourceBundles/ApplicationResources</value>
<value>com/dimex/resourceBundles/errors</value>
</list>
</property>
</bean>
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="locale"></property>
</bean>
</mvc:interceptors>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en" />
</bean>
EDIT:-
Do I need to have hibernate validator in my classpath. We are not using hibernate in our application.
Please help.
EDIT2:-
When I use validation annotations (#NotNull, #Size etc) directly in my entity class then #Valid annotations in controller works but if I remove them from my entities and try to use the validator written above then #Valid does not work.
Is it like that #Valid annotations only work with the validation annotation in the entities only and not with the validators? In order to use my validators will I have to invoke the validate method in my validator directly?

From what I understand you are trying to combine JSR-303 #Valid annotation with classic spring validation. Why would you want to do this? The equivalent JSR-303 annotations for UserValidator class would be something like below:
#NotNull
#Size(min=1)
private String userName;
#NotNull
#Size(min=1)
private String password
...
The spring documentation illustrates the steps needed to configure JSR-303 validation. You would need hibernate-validator (or another JSR-303 provider) for the above to work. You would also need to configure the validator bean as below.
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
The other answers to this question are in the same line as well.

You need to define the validator to use in your controller using the #InitBinder annotation, for example:
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(new UserValidator());
}

Other way around is to call spring validator initialization from your controller
DataBinder dataBinder = new DataBinder(user);
dataBinder.setValidator(userValidator);
dataBinder.validate();
BindingResult result = dataBinder.getBindingResult();
if(result.hasErrors() == false) {
// error exists
}

You need to put #Component on the Validator implementation so that Spring container can recognize it as:
#Component
public class UserValidator implements Validator {
and use following method in the controller:
#InitBinder(UserVO)
protected void initBinder(WebDataBinder binder) { binder.setValidator(userValidator);
}

If you use JSR-303-style validation with Spring (i.e. a global Validator instance provided by a JSR-303 implementation, such as Hibernate Validator), and you have an #InitBinder-annotated method in your Controller, you must inject the Validator into your Controller and set it in the #InitBinder method:
#Autowired
public void setValidator(Validator validator) {
this.validator = validator;
}
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(this.validator);
}
The WebDataBinder's validator is by default set to null, not (as you would expect) to the global JSR-303 Validator instance, so your models won't be validated by Spring unless you set the Validator instance manually here.
This is only if you have an #InitBinder method. If you don't, everything works as expected.

Related

Annotation equivalent for initializing a list of beans

I have a property initialized inside a bean defined in context.xml like below:
<property name="filters">
<list>
<!-- declared using annotations -->
<ref bean="filter1"/>
<ref bean="filer2"/>
</list>
</property>
Is there any annotation equivalent for this, so I don't require writing a separated method with #PostConstruct and #Autowire filters one by one?
Currently, I did something like below:
#Component
public class Myclass{
#Autowired
private Filter filter1;
#Autowired
private Filter filter2;
private List<Filter> filters;
#PostConstruct
private void setFilters(){
filters = List.of(filter1, filter2);
}
}

Rolling back transactions after exception is thrown

When I throw exception in service method I expected that transactional annotation on service will rollback save operation, but it is not working.
This is my service:
#Service
#Transactional(value = "transactionManager", rollbackFor = Exception.class)
public class OrderServiceImp implements OrderService {
#Autowired
private OrderRepository orderRepository;
#Override
public void doSomeStaff(Long orderId) {
Order order = orderRepository.findOne(orderId);
orderRepository.save(order);
throw new NullPointerException("Test transaction exeption");
}
}
In data.xml I have next configs:
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<jpa:repositories base-package="com.dmitro.repositories" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager"/>
In dispatcher-servlet.xml I declared scan:
<context:component-scan base-package="com.dmitro.service" />
I am using spring-data-jpa 1.8.0.RELEASE. Please help!
#Transactional(value = "transactionManagerForServiceLayer", rollbackFor = Exception.class)
This is the culprit. You should not have different transaction manager for service and repository. To fix it, you need to replace transactionManagerForServiceLayer here to transactionManager and then rollback will work.
Try to throw the Exception in OrderRepositoryImpl to see if it works
public class OrderRepositoryImpl implements OrderRepository {
#Override
public void save() {
throw new SomeRunTimeException();
}
}
public class OrderServiceImp implements OrderService {
#Override
public void doSomeStaff(Long orderId) {
Order order = orderRepository.findOne(orderId);
orderRepository.save(order);
}
}
The DataSource AutoCommit is ON (or True). Turn it OFF (or false).
Problem was in configuration, because I declared services and transaction manager in different spring contexts: transaction manager was in root context and services was in child dispatcher-servlet.xml context.

Spring autowired can not work [duplicate]

This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 7 years ago.
I currently developing an application using Spring Data Neo4j. This is the first time I use Spring framework.
However, the autowired annotation is not working, I always get null. Here is the codes:
public class CreateDiaryTransaction extends Transaction {
#Autowired
DirayRepository repository;
#Override
public Object perform(Map<String, Object> parameters) {
// TODO Auto-generated method stub
Diary diary = (Diary) DiaryFactory.getInstance().create(parameters);
repository.save(diary);
return diary.toJsonRepre();
}
}
Then I test it in a unit test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "/applicationContext.xml" })
public class CreateDiaryTransactionTest {
#Test
public void test() {
Transaction transaction = new CreateDiaryTransaction();
Map<String, Object> parameters = new HashMap<>();
parameters.put("title", "Test");
parameters.put("weather", "sun");
parameters.put("mood", "happy");
parameters.put("html", "link");
parameters.put("images", new ArrayList<Image>());
try {
transaction.execute(parameters);
} catch (Exception e) {
fail("Exception occur");
}
}
}
When I runs this, I got null object exception. However, when I place the repository directly in the unit test, it works fine. Here is another test that works:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "/applicationContext.xml" })
public class DiaryRepositoryTest {
#Autowired
DirayRepository repository;
#Test
#Transactional
public void testSaveDiary() {
Diary diary = (Diary) DiaryFactory.getInstance().create(
new HashMap<String, Object>());
repository.save(diary);
Diary retrivedDiary = repository.findOne(diary.getGraphId());
assertEquals(diary, retrivedDiary);
}
}
And here is my application context:
<context:annotation-config />
<neo4j:config storeDirectory="target/data/pamela"
base-package="com.bond.pamela.domain" />
<neo4j:repositories base-package="com.bond.pamela.persistence" />
<tx:annotation-driven mode="aspectj" />
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean
class="com.bond.pamela.domain.valueObject.converter.ImageToJsonConverter" />
<bean
class="com.bond.pamela.domain.valueObject.converter.JsonToImageConverter" />
</set>
</property>
</bean>
I guess I somehow put the repository outside the spring context, but how can I get it wirte? Thx
You need following in your application context
<context:component-scan base-package="packagename.package" />
Here package name is package in which you have all your classes with annotations.
Have a look at this post for more :
Spring MVC: Difference between context:annotation-config vs context:component-scan
Make sure you have written #Repository or #Component annotation on the implementation of DirayRepository and you have written component-scan in
applicationContext.xml
sample code for DirayRepository
#Repository
public class DirayRepositoryImpl implements DirayRepository {
void save() { ...}
}

Spring Annotation : Converting XML Configuration to Annotation

I am using xml configuration in my Spring Application. Now i would like to convert the existing classes to use annotation(like #service, #Repository etc) instead of xml configuration.
Business Logic(Irrelevant for this question, just for understanding):
Sevice connnects to Americas database and find the skus(products) and deactivates the skus.
Sevice connnects to EMEA database and find the skus(products) and deactivates the skus.
Here is the sample code.
/* Service code, which has 2 instances of SkuDAO, one connecting to US database and one connecting to EMEA database */
public class DeactivationService {
private static final Logger LOG = Logger.getLogger(DeactivationService.class);
private SkuDAO amerdao; //Dependency Injection Amer
private SkuDAO emeadao; //Dependency Injection EMEA
public DeactivationService(SkuDAO amerdao,SkuDAO emeadao) {
this.amerdao=amerdao;
this.emeadao=emeadao;
}
/*
* Step 1: find inactive sku in americas skudao1.find()
* Step 2: find inactive sku in emea skudao2.find()
* Step 3: deactivate sku in americas
* Step 4: deactivate sku in emea
*/
public void deactivateSku() {
List<Sku> totalList = new ArrayList<Sku>();
List<Sku> amerList = amerdao.find();
List<Sku> emeaList = emeadao.find();
amerdao.deactivate(amerList);
emeaList.deactivate(emeaList);
}
}
/* DAO interface */
public interface SkuDAO {
public List<Sku> find();
public void deactivate(List<Sku>);
}
/* DAO Implementation
Here one constructor in which DataSource is injected
*/
public class SkuDAOImpl implements SkuDAO {
private DataSource datasource; //Dependency injection
private JdbcTemplate jdbcTemplate;
public SkuDAOImpl(DataSource datasource) {
this.datasource=datasource;
}
public List<Sku> find() {
//some processing to find the sku, purposely left empty as it is a sample code
}
public void deactivate(List<Sku>) {
//some processing to deactivate the sku, purposely left empty as it is a sample code
}
}
Spring 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:property-placeholder location="file:${dbconfiguration}"/>
<bean id="AmericasDataSource" class="dell.harmony.data.HarmonyBasicDataSource" destroy-method="close" >
<property name="url"><value>${HarmonyAmericasDb.url}</value></property>
<property name="driverClassName"><value>${HarmonyAmericasDb.driverClassName}</value></property>
<property name="username"><value>${HarmonyAmericasDb.username}</value></property>
<property name="password"><value>${HarmonyAmericasDb.password}</value></property>
<property name="initialSize"><value>${HarmonyAmericasDb.initialSize}</value></property>
<property name="maxActive"><value>${HarmonyAmericasDb.maxActive}</value></property>
<property name="maxWait"><value>${HarmonyAmericasDb.maxWait}</value></property>
<property name="maxIdle"><value>${HarmonyAmericasDb.maxIdle}</value></property>
<property name="minIdle"><value>${HarmonyAmericasDb.minIdle}</value></property>
<property name="removeAbandoned"><value>${HarmonyAmericasDb.removeAbandoned}</value></property>
<property name="removeAbandonedTimeout"><value>${HarmonyAmericasDb.removeAbandonedTimeout}</value></property>
</bean>
<bean id="EMEADataSource" class="dell.harmony.data.HarmonyBasicDataSource" destroy-method="close" >
<property name="url"><value>${HarmonyEMEADb.url}</value></property>
<property name="driverClassName"><value>${HarmonyEMEADb.driverClassName}</value></property>
<property name="username"><value>${HarmonyEMEADb.username}</value></property>
<property name="password"><value>${HarmonyEMEADb.password}</value></property>
<property name="initialSize"><value>${HarmonyEMEADb.initialSize}</value></property>
<property name="maxActive"><value>${HarmonyEMEADb.maxActive}</value></property>
<property name="maxWait"><value>${HarmonyEMEADb.maxWait}</value></property>
<property name="maxIdle"><value>${HarmonyEMEADb.maxIdle}</value></property>
<property name="minIdle"><value>${HarmonyEMEADb.minIdle}</value></property>
<property name="removeAbandoned"><value>${HarmonyEMEADb.removeAbandoned}</value></property>
<property name="removeAbandonedTimeout"><value>${HarmonyEMEADb.removeAbandonedTimeout}</value></property>
</bean>
**<!-- Sku Deactivation -->**
<bean id="SkuAmerDao" class="dell.harmony.service.skudeactivation.dao.SkuDAOImpl">
<constructor-arg index="0"><ref bean="AmericasDataSource"/></constructor-arg>
</bean>
<bean id="SkuEMEADao" class="dell.harmony.service.skudeactivation.dao.SkuDAOImpl">
<constructor-arg index="0"><ref bean="EMEADataSource"/></constructor-arg>
</bean>
<bean id="ServiceManager" class="dell.harmony.service.skudeactivation.service.DeactivationService">
<constructor-arg index="0"><ref bean="SkuAmerDao"/></constructor-arg>
<constructor-arg index="1"><ref bean="SkuEMEADao"/></constructor-arg>
</bean>
</beans>
Now i want to convert the above classes to highlighted inside xml("Sku Deactivation") , into annodation.
My code for convertion is as follows:
#Service
public class DeactivationService {
private static final Logger LOG = Logger.getLogger(DeactivationService.class);
private SkuDAO amerdao; //Dependency Injection Amer
private SkuDAO emeadao; //Dependency Injection EMEA
#Autowired(required=true)
public DeactivationService( #Qualifier("SkuAmerDao") SkuDAO amerdao, #Qualifier("SkuEMEADao") SkuDAO emeadao) {
this.amerdao=amerdao;
this.emeadao=emeadao;
}
}
In the above constructor, now 'amerdao' instance, should be injected with AmericasDataSource and 'emeadao' with EMEADataSource, how to do that?
Please note, i dont have a setter in the SkuDAOImpl. Also there is only one datasource instance inside the SkuDAOImpl.
can you given sample code of SkuDAOImpl with annodation.
Any suggestion, to improve the coding from service to dao , if it can be done in a better way. (Not required to answer this)
EDITED NOW: just to be clear with question 1, I would like to remove the below two lines in Spring xml and use annotation instead my DeactivationService. Is it possible?
<bean id="SkuAmerDao" class="dell.harmony.service.skudeactivation.dao.SkuDAOImpl">
<constructor-arg index="0"><ref bean="AmericasDataSource"/></constructor-arg>
</bean>
<bean id="SkuEMEADao" class="dell.harmony.service.skudeactivation.dao.SkuDAOImpl">
<constructor-arg index="0"><ref bean="EMEADataSource"/></constructor-arg>
</bean>
What about:
#Service
public class DeactivationService {
private static final Logger LOG = Logger.getLogger(DeactivationService.class);
#Autowired
#Qualifier("SkuAmerDao")
private SkuDAO amerdao; //Dependency Injection Amer
#Autowired
#Qualifier("SkuEMEADao")
private SkuDAO emeadao; //Dependency Injection EMEA
// no constructor needed.
}
public abstract class BaseDao implements SkuDAO {
private final JdbcTemplate jdbcTemplate;
protected BaseDao() {
this.jdbcTemplate = new JdbcTemplate(getDataSource());
}
protected abstract DataSource getDataSource();
public List<Sku> find() {
//some processing to find the sku, purposely left empty as it is a sample code
}
public void deactivate(List<Sku>) {
//some processing to deactivate the sku, purposely left empty as it is a sample code
}
}
#Repository("SkuAmerDao")
public class SkuAmerDAOImpl extends BaseDao {
#Autowired
#Qualifier("AmericasDataSource")
private DataSource datasource; //Dependency injection
#Override
protected DataSource getDatasource() {
return dataSource;
}
}
#Repository("SkuEMEADao")
public class SkuEMEADAOImpl extends BaseDao {
#Autowired
#Qualifier("EMEADataSource")
private DataSource datasource; //Dependency injection
#Override
protected DataSource getDatasource() {
return dataSource;
}
}
Always the same principle:
class is made a bean by an annotation #Service, #Component, #Repository (those annotations can take the name of the bean as value)
injection of dependency is made on fields with #Autowired and if there are more than one corresponding bean (in your case you have two DataSources), add a #Qualifier to specify which one.
Full documentation here.

UserDao is null, I am wiring the bean wrong and need help

My homecontroller has a UserService object that gets wired using spring correctly (it renders the index page just fine using a method no UserService).
Now I setup hibernate, so inside UserService I have a UserDao object that I am trying to wire using spring.
#Service
public class UserServiceImpl implements UserService{
UserDao userDao;
public String sayHello() {
return "hello from user service impl part 2";
}
public String getTestUser() {
return userDao.getById(1L).getUsername();
}
}
So my HomeController was calling the 'sayHello' method and it was working fine like I said.
#Controller
public class HomeController {
#Autowired
private UserService userService;
#RequestMapping("/")
public ModelAndView Index() {
ModelAndView mav = new ModelAndView();
mav.setViewName("index");
mav.addObject("message", userService.sayHello());
mav.addObject("username", userService.getTestUser());
//userService.getTestUser();
return mav;
}
The call to userService.getTestUser() fails, as the UserDao is null.
My app-config.xml is:
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--<property name="packagesToScan" value="com.blah.core.db.hibernate"/> -->
<property name="configLocation" value="/WEB-INF/classes/hibernate.cfg.xml"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.connection.url=jdbc:mysql://localhost/blah
hibernate.connection.username=dbuser
hibernate.connection.password=123
hibernate.query.substitutions=true 'Y', false 'N'
hibernate.cache.use_query_cache=true
hibernate.cache.use_second_level_cache=true
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
hibernate.jdbc.batch_size=0
</value>
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<bean id="userDao" class="com.blah.core.db.hibernate.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Why is my UserDao null? I must be doing something wrong with the wiring?
Also, if I uncomment out the name=packagesToScan line, do I really need to define a bean for each Dao like I did with UserDao? Will the sessionFactory get wired somehow?
Add #AutoWired annotation to userDao.
#Service
public class UserServiceImpl implements UserService{
#AutoWired
UserDao userDao;
...
}
And make sure you have set up <context:component-scan/> to scan the packages that your #Services and #Controllers are in.
As krock mentioned, your UserDao is not being "wired" properly inside your UserService. Did you even try his suggestion ?

Categories

Resources