I am not being able to persist entity in JPA, although findAll works
here.
Here is the JpaDAO
package aop.web.teacher.dao;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import org.apache.log4j.Logger;
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.support.JpaDaoSupport;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public abstract class JpaDAO extends JpaDaoSupport {
protected Class entityClass;
private static Logger log = Logger.getLogger(JpaDAO.class);
#SuppressWarnings("unchecked")
public JpaDAO() {
ParameterizedType genericSuperclass = (ParameterizedType) getClass()
.getGenericSuperclass();
this.entityClass = (Class) genericSuperclass
.getActualTypeArguments()[1];
}
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void persist(E entity) {
getJpaTemplate().persist(entity);
}
#Transactional
public void remove(E entity) {
getJpaTemplate().remove(entity);
}
#Transactional
public E merge(E entity) {
return getJpaTemplate().merge(entity);
}
#Transactional
public void refresh(E entity) {
getJpaTemplate().refresh(entity);
}
#Transactional
public E findById(K id) {
return getJpaTemplate().find(entityClass, id);
}
#Transactional
public E flush(E entity) {
getJpaTemplate().flush();
return entity;
}
#SuppressWarnings("unchecked")
#Transactional
public List findAll() {
Object res = getJpaTemplate().execute(new JpaCallback() {
public Object doInJpa(EntityManager em) throws PersistenceException {
Query q = em.createQuery("SELECT h FROM "
+ entityClass.getName() + " h");
return q.getResultList();
}
});
return (List) res;
}
#SuppressWarnings("unchecked")
#Transactional
public Integer removeAll() {
return (Integer) getJpaTemplate().execute(new JpaCallback() {
public Object doInJpa(EntityManager em) throws PersistenceException {
Query q = em.createQuery("DELETE FROM " + entityClass.getName()
+ " h");
return q.executeUpdate();
}
});
}
}
Here is the TestDao class
package aop.web.teacher.dao;
import java.util.Date;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import aop.web.teacher.rmodels.Teachermaster;
#Service
#Repository
public class TestDaoImpl extends JpaDAO implements TestDao {
#Autowired
EntityManagerFactory entityManagerFactory;
#PersistenceContext
private EntityManager em;
#PostConstruct
public void init() {
super.setEntityManagerFactory(entityManagerFactory);
}
public int saveTeacher() {
List teacherList = findAll();
Teachermaster m1 = teacherList.get(0);
logger.info("Found " + m1.getId() + " and " + m1.getRace());
m1.setRace(m1.getRace() + "::" + System.currentTimeMillis());
logger.info("New " + m1.getId() + " and " + m1.getRace());
persist(m1);
return 0;
}
}
Here is the spring context xml
http://pastebin.com/pKqzW9h1
Here the findAll works
but when we make a change to the attribute of the Teachermaster
then persist or merge does not seem to save the entity...
If we flush it we get exception
javax.persistence.TransactionRequiredException: no transaction is in progress
Please advise
Spring uses proxy-based AOP, therefore aspects (including transactional aspect) are not applied when methods are called from the same class.
Generally speaking
#Transactional annotations should be usually placed on service methods rather than on DAO methods
Your saveTeacher() looks like a service method, it would be better to place it in the separate service class and annotate as #Transactional
You don't need persist() in saveTeacher() - changes made to persistent objects should be saved automatically
Beware of dynamic proxy vs target class proxy distinction (regarding to TestDao) - see the links below
See also:
7.6.1 Understanding AOP proxies
10.5.1 Understanding the Spring Framework's declarative transaction implementation
You are calling a local method when invoking persist() from your test class. This way the proxy that would create transactions is not invoked so your call to persist() has no transaction.
The way to do this properly is to have the test class not extend the object under test but have it injected. This way the proxy will be triggered and the transaction will be created.
By the way, I must add that I find your class design a little bit beculiar. May I suggest creating a structure like the following?
DAO interface:
public interface FooDao {
void persist(Foo foo);
// ...
}
DAO implementation:
public class FooDaoImpl implements FooDao {
#PersistenceContext
private EntityManager entityManager;
#Transactional
public void persist(Foo foo) {
entityManager.persist(foo);
}
}
Test class:
#RunWith(SpringJunit4ClassRunner.class)
#ContextConfiguration(...)
public class FooDaoTest {
#Autowired
private FooDao fooDao;
#Test
public void testPersist() {
// do some testing
}
}
You can, if you wish, extract most of the logic in the DAO implementations into a generic superclass.
Related
Just wanna ask as I am stuck in the test cases and getting error as "Actually, there were zero interactions with this mock".
I have created an Dao Implementation class which is doing CRUD operation.
public class EmployeeDaoImpl implements EmployeeDao {
#Override
public void saveEmployee(EmployeeDetails employee) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
session.save(employee);
transaction.commit();
session.close();
}
}
And for this above class I am building the test using Mockito. So for my above saveEmployee method Session, TRansaction I have made it as Mock object and now I need to check session , save method and transaction as well.
So I have written the Mockito code below:
/**
*
*/
package sandeep.test;
import static org.junit.Assert.*;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import junit.framework.Assert;
import org.hibernate.Session;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import sandeep.DAO.EmployeeDao;
import sandeep.DAOImpl.EmployeeDaoImpl;
import sandeep.DAOImpl.HibernateUtil;
import sandeep.pojo.EmployeeDetails;
import static org.mockito.Mockito.*;
/**
* #author sandeep
*
*/
#RunWith(MockitoJUnitRunner.class)
public class EmployeeDaoImplTest {
#Mock
EmployeeDetails edt;
#Mock
Session session ;
#Mock
Transaction transaction;
#InjectMocks
EmployeeDaoImpl edi = new EmployeeDaoImpl();
#Before
public void setUp() throws Exception {
//eimpl = new EmployeeDaoImpl();
//emp= mock(EmployeeDao.class);
}
#After
public void tearDown() throws Exception {
}
#Test
public void testSaveEmployee(){
edi.saveEmployee(getEmployeeDetails());
// But here i am getting the error as zero interactions
verify(session, times(1)).save(EmployeeDetails.class);
}
public EmployeeDetails getEmployeeDetails(){
edt = new EmployeeDetails();
edt.setEname("sandeep");
edt.setId(2);
edt.setEnumber("hoi");
return edt;
}
}
I have debugged the code and the code is passing onto all the breakpoints in my IDE and when I execute this the 3 values it will be added to the database but my test case will fail as there are zero interactions.
The Session mock in your test is not the same object used in EmployeeDaoImpl#saveEmployee
Implement a constructor for EmployeeDaoImpl with a Session argument and use that argument in the saveEmployee() method. This allows your #InjectMocks to work as intended.
#RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
#Mock
Session session;
#InjectMocks
EmployeeDaoImpl edi;
#Test
public void testSaveEmployee(){
edi.saveEmployee();
verify(session, times(1)).save();
}
}
class Session {
void save() {
System.out.println("saving");
}
}
interface EmployeeDao {
void saveEmployee();
}
class EmployeeDaoImpl implements EmployeeDao {
private Session session;
public EmployeeDaoImpl(Session session) {
this.session = session;
}
#Override
public void saveEmployee() {
session.save();
}
}
I losted many time try solve this issuer, but I am in the same place. I suspect that I mixed something of CDI with EJB.
The problem is persist and delete only don't work.
Caused by: javax.persistence.TransactionRequiredException: WFLYJPA0060: Transaction is required to perform this operation (either use a transaction or extended persistence context)
at org.jboss.as.jpa.container.AbstractEntityManager.transactionIsRequired(AbstractEntityManager.java:866)
at org.jboss.as.jpa.container.AbstractEntityManager.persist(AbstractEntityManager.java:579)
at com.oki.scope.console.model.dao.GenericDAO.save(GenericDAO.java:29)
at com.oki.scope.console.model.dao.GenericConsoleDAO.save(GenericConsoleDAO.java:12)
at com.oki.scope.console.service.ServidorServiceImp.salvar(ServidorServiceImp.java:27)
at com.oki.scope.console.service.ServidorServiceImp$Proxy$_$$_WeldClientProxy.salvar(Unknown Source)
at com.oki.scope.console.managedBean.consulta.ServidorMB.salvar(ServidorMB.java:65)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.sun.el.parser.AstValue.invoke(AstValue.java:292)
at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304)
at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87)
... 40 more
My DAO
public class GenericDAO<T, K> {
protected EntityManager em;
private Class<T> entityClass;
public GenericDAO(Class<T> entityClass, EntityManager em) {
this.entityClass = entityClass;
this.em = em;
}
#Transactional
protected void save(T entity) {
em.persist(entity);
}
Generic DAO:
import javax.persistence.EntityManager;
public abstract class GenericConsoleDAO<T, K> extends GenericDAO<T, K> {
public GenericConsoleDAO(Class<T> entityClass, EntityManager em) {
super(entityClass, em);
}
public void save(T t){
super.save(t);
}
}
DAO Factory:
package com.oki.scope.console.model.dao;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.ejb.Singleton;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
#Singleton
#TransactionManagement(TransactionManagementType.CONTAINER)
public class DAOConsoleFactory {
private final static String UNIT_NAME = "scope-console";
private static Map<String, Object> mapa = Collections.synchronizedMap(new HashMap<String, Object>());
#PersistenceContext(unitName = UNIT_NAME )
private EntityManager entityManager;
#Produces public ServidorDAO criaServidorDAO(){ return getDAO(ServidorDAO.class); }
#Produces public ConexaobdDAO criaConexaoDAO(){ return getDAO(ConexaobdDAO.class); }
#Produces public ContratoDAO criaContratoDAO(){ return getDAO(ContratoDAO.class); }
#Produces public EmpresaDAO criaEmpresaDAO(){ return getDAO(EmpresaDAO.class); }
#Produces public LojaDAO criaLojaDAO(){ return getDAO(LojaDAO.class); }
//#Produces public RedeAutorizadoraDAO criaRedeAutorizadoraDAO(){ return getDAO(RedeAutorizadoraDAO.class); }
#Produces public RedeDAO criaRedeDAO(){ return getDAO(RedeDAO.class); }
#Produces public RoteadorDAO criaRoteadorDAO(){ return getDAO(RoteadorDAO.class); }
#Produces public TerminalDAO criaTerminalDAO(){ return getDAO(TerminalDAO.class); }
#Produces public TipoHeaderDAO criaTipoHeaderDAO(){ return getDAO(TipoHeaderDAO.class); }
#SuppressWarnings("unchecked")
public <E> E getDAO(Class<E> classe){
String key = classe.getSimpleName();
if (!mapa.containsKey(key))
{
try {
mapa.put(key, classe.getDeclaredConstructor(EntityManager.class).newInstance(entityManager));
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
System.out.println("Classe "+ key +" não possui um construtor que tenha EntityManager como parametro.");
}
}
return (E)mapa.get(key);
}
}
My class:
#Named
#ApplicationScoped
public class ServidorServiceImp implements ServidorService {
#Inject private ServidorDAO dao;
#Override
public List<Servidor> getLista() {
return dao.getLista();
}
#Override
public void salvar(Servidor servidor) {
if (servidor.getId()==0){
dao.save(servidor);
}
else
{
dao.update(servidor);
}
}
#Override
public void remover(Servidor servidor) {
dao.delete(servidor);
}
}
In trying to enhance performance, you have circumvented what the container is supposed to be doing for you, which is instantiating a bean inside a transaction.
I would say remove the #Singleton and #TransactionManagement(TransactionManagementType.CONTAINER) from DAOConsoleFactory and allow the EJB transaction to be handled by the EJB bean that's using the DAO's.
UPDATE: Also, #ApplicationScoped is not an EJB annotation Class ServidorServiceImp needs to be an EJB bean so, it should be annotated with #Stateless or perhaps #Statefull and remove the #ApplicationScoped. It reads like a stateless EJB bean, so there is no need to make it application scoped.
Again, it seems to me you are concentrating too much on trying to optimize performance without having a good understanding of how EJB's are supposed to work in a container. I would recommend getting everything to work and follow architectural best practices, especially in the "Session Façade" concept. Some of these posts may help: What is the point of a Facade in Java EE? or Why use Facade pattern for EJB session bean.
Solved: Before 2 day suffering. The problem was in my Class. Where is #Named
#ApplicationScoped, I changed to #Statefull.
I have a java bean being used to send JSON messages to a spring #RestController and I have bean validation setup and running just fine using #Valid. But I want to move to Protobuf/Thrift and move away from REST. It is an internal API and a lot of big companies have done away with REST internally. What this really means is that I no longer have control of the message objects - they are generated externally. I can't put annotations on them anymore.
So now my validation has to be programmatic. How do I do this? I have coded up a Validator and it works just great. But it doesn't use the nice #Valid annotation. I have to do the following:
#Service
public StuffEndpoint implements StuffThriftDef.Iface {
#Autowired
private MyValidator myValidator;
public void things(MyMessage msg) throws BindException {
BindingResult errors = new BeanPropertyBindingResult(msg, msg.getClass().getName());
errors = myValidator.validate(msg);
if (errors.hasErrors()) {
throw new BindException(errors);
} else {
doRealWork();
}
}
}
This stinks. I have to do this in every single method. Now, I can put a lot of that into one method that throws BindException and that makes it one line of code to add to every method. But that's still not great.
What I want is to see it look like this:
#Service
#Validated
public StuffEndpoint implements StuffThriftDef.Iface {
public void things(#Valid MyMessage msg) {
doRealWork();
}
}
And still get the same result. Remember, my bean has no annotations. And yes, I know I can use the #InitBinder annotation on a method. But that only works for web requests.
I don't mind injecting the correct Validator into this class, but I would prefer if my ValidatorFactory could pull the correct one based on the supports() method.
Is this possible? Is there a way to configure bean validation to actually use Spring validation instead? Do I have to hijack a Aspect somewhere? Hack into the LocalValidatorFactory or the MethodValidationPostProcessor?
Thanks.
Its pretty complicated thing to combine Spring validation and JSR-303 constrains. And there is no 'ready to use' way. The main inconvenience is that Spring validation uses BindingResult, and JSR-303 uses ConstraintValidatorContext as result of validation.
You can try to make your own validation engine, using Spring AOP. Let's consider, what we need to do for it. First of all, declare AOP dependencies (if you didn't yet):
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.8</version>
</dependency>
I'm using Spring of version 4.2.4.RELEASE, but of cause you can use your own. AspectJ needed for use aspect annotation. Next step, we have to create simple validator registry:
public class CustomValidatorRegistry {
private List<Validator> validatorList = new ArrayList<>();
public void addValidator(Validator validator){
validatorList.add(validator);
}
public List<Validator> getValidatorsForObject(Object o) {
List<Validator> result = new ArrayList<>();
for(Validator validator : validatorList){
if(validator.supports(o.getClass())){
result.add(validator);
}
}
return result;
}
}
As you see it is very simple class, which allow us to find validator for object. Now lets create annotation, that will be mark methods, that need to be validated:
package com.mydomain.validation;
#Target({ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface CustomValidation {
}
Because of standard BindingException class is not RuntimeException, we can't use it in overriden methods. This means we need define our own exception:
public class CustomValidatorException extends RuntimeException {
private BindingResult bindingResult;
public CustomValidatorException(BindingResult bindingResult){
this.bindingResult = bindingResult;
}
public BindingResult getBindingResult() {
return bindingResult;
}
}
Now we are ready to create an aspect that will do most of the work. Aspect will execute before methods, which marked with CustomValidation annotation:
#Aspect
#Component
public class CustomValidatingAspect {
#Autowired
private CustomValidatorRegistry registry; //aspect will use our validator registry
#Before(value = "execution(public * *(..)) && annotation(com.mydomain.validation.CustomValidation)")
public void doBefore(JoinPoint point){
Annotation[][] paramAnnotations =
((MethodSignature)point.getSignature()).getMethod().getParameterAnnotations();
for(int i=0; i<paramAnnotations.length; i++){
for(Annotation annotation : paramAnnotations[i]){
//checking for standard org.springframework.validation.annotation.Validated
if(annotation.annotationType() == Validated.class){
Object arg = point.getArgs()[i];
if(arg==null) continue;
validate(arg);
}
}
}
}
private void validate(Object arg) {
List<Validator> validatorList = registry.getValidatorsForObject(arg);
for(Validator validator : validatorList){
BindingResult errors = new BeanPropertyBindingResult(arg, arg.getClass().getSimpleName());
validator.validate(arg, errors);
if(errors.hasErrors()){
throw new CustomValidatorException(errors);
}
}
}
}
execution(public * *(..)) && #annotation(com.springapp.mvc.validators.CustomValidation) means, that this aspect will applied to any public methods of beans, which marked with #CustomValidation annotation. Also note, that to mark validated parameters we are using standard org.springframework.validation.annotation.Validated annotation. But of cause we could make our custom. I think other code of aspect is very simple and does not need any comments. Further code of example validator:
public class PersonValidator implements Validator {
#Override
public boolean supports(Class<?> aClass) {
return aClass==Person.class;
}
#Override
public void validate(Object o, Errors errors) {
Person person = (Person)o;
if(person.getAge()<=0){
errors.rejectValue("age", "Age is too small");
}
}
}
Now we have make tune the configuration and all ready to use:
#Configuration
#ComponentScan(basePackages = "com.mydomain")
#EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig{
.....
#Bean
public CustomValidatorRegistry validatorRegistry(){
CustomValidatorRegistry registry = new CustomValidatorRegistry();
registry.addValidator(new PersonValidator());
return registry;
}
}
Note, proxyTargetClass is true because we will use cglib class proxy.
Example of target method in service class:
#Service
public class PersonService{
#CustomValidation
public void savePerson(#Validated Person person){
....
}
}
Because of #CustomValidation annotation aspect will be applied, and because of #Validated annotation person will be validated. And example of usage of service in controller(or any other class):
#Controller
public class PersonConroller{
#Autowired
private PersonService service;
public String savePerson(#ModelAttribute Person person, ModelMap model){
try{
service.savePerson(person);
}catch(CustomValidatorException e){
model.addAttribute("errors", e.getBindingResult());
return "viewname";
}
return "viewname";
}
}
Keep in mind, that if you will invoke #CustomValidation from methods of PersonService class, validation will not work. Because it will invoke methods of original class, but not proxy. This means, that you can invoke this methods only from outside of class (from other classes), if you want validation to be working (eg #Transactional works same way).
Sorry for long post. My answer is not about 'simple declarative way', and possible you will do not need it. But I was curious resolve this problem.
I marked #Ken's answer as correct because it is. But I have taken it a little further and wanted to post what I have made. I hope anybody coming to this page will find it interesting. I might try to get it in front of the Spring folks to see if it might be something included in future releases.
The idea is to have a new annotation to replace #Valid. So I called it #SpringValid. Using this annotation would kick off the system put together above. Here are all the pieces:
SpringValid.java
package org.springframework.validation.annotation;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Target({METHOD, FIELD, CONSTRUCTOR, PARAMETER})
#Retention(RUNTIME)
public #interface SpringValid {
}
SpringValidationAspect.java
package org.springframework.validation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
#Aspect
#Component
public class SpringValidationAspect {
private SpringValidatorRegistry springValidatorRegistry;
#Autowired
public SpringValidationAspect(final SpringValidatorRegistry springValidatorRegistry) {
this.springValidatorRegistry = springValidatorRegistry;
}
public SpringValidatorRegistry getSpringValidatorRegistry() {
return springValidatorRegistry;
}
#Before("#target(org.springframework.validation.annotation.Validated) "
+ "&& execution(public * *(#org.springframework.validation.annotation.SpringValid (*), ..)) "
+ "&& args(validationTarget)")
public void beforeMethodThatNeedsValidation(Object validationTarget) {
validate(validationTarget);
}
private void validate(Object arg) {
List<Validator> validatorList = springValidatorRegistry.getValidatorsForObject(arg);
for (Validator validator : validatorList) {
BindingResult errors = new BeanPropertyBindingResult(arg, arg.getClass().getSimpleName());
validator.validate(arg, errors);
if (errors.hasErrors()) {
throw new SpringValidationException(errors);
}
}
}
}
Spring's examples show classes annotated with #Validated so I wanted to keep that. The above aspect only targets classes with #Validated at the class-level. And, just like when you use #Valid, it looks for the #SpringValid annotation stuck to a method parameter.
SpringValidationException.java
package org.springframework.validation;
import org.springframework.validation.BindingResult;
public class SpringValidationException extends RuntimeException {
private static final long serialVersionUID = 1L;
private BindingResult bindingResult;
public SpringValidationException(final BindingResult bindingResult) {
this.bindingResult = bindingResult;
}
public BindingResult getBindingResult() {
return bindingResult;
}
}
SpringValidatorRegistry.java
package org.springframework.validation;
import org.springframework.validation.Validator;
import java.util.ArrayList;
import java.util.List;
public class SpringValidatorRegistry {
private List<Validator> validatorList = new ArrayList<>();
public void addValidator(Validator validator) {
validatorList.add(validator);
}
public List<Validator> getValidatorsForObject(Object o) {
List<Validator> result = new ArrayList<>();
for (Validator validator : validatorList) {
if (validator.supports(o.getClass())) {
result.add(validator);
}
}
return result;
}
}
Just like the first answer, a place to register all classes that implement Spring's org.springframework.validation.Validator interface.
SpringValidator.java
package org.springframework.validation.annotation;
import org.springframework.stereotype.Component;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface SpringValidator {
}
This is just extra sauce to make it easier to register/find Validators. You could register all your Validators by hand, or you could find them via reflection. So this part is not required, I just thought it made things easier.
MyConfig.java
package com.example.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.SpringValidationAspect;
import org.springframework.validation.SpringValidatorRegistry;
import org.springframework.validation.annotation.SpringValidator;
import java.util.Map;
import javax.validation.Validator;
#Configuration
public class MyConfig {
#Autowired
private ApplicationContext applicationContext;
#Bean
public SpringValidatorRegistry validatorRegistry() {
SpringValidatorRegistry registry = new SpringValidatorRegistry();
Map<String, Object> validators =
applicationContext.getBeansWithAnnotation(SpringValidator.class);
validators.values()
.forEach(v -> registry.addValidator((org.springframework.validation.Validator) v));
return registry;
}
#Bean
public SpringValidationAspect springValidationAspect() {
return new SpringValidationAspect(validatorRegistry());
}
}
See, scan your classpath and look for #SpringValidator classes and register them. Then register the Aspect and away you go.
Here is an example of such a Validator:
MyMessageValidator.java
package com.example.validators;
import com.example.messages.MyMessage;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.SpringValidator;
#SpringValidator
public class MyMessageValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return MyMessage.class.isAssignableFrom(clazz);
}
#Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "firstField", "{javax.validation.constraints.NotNull}",
"firstField cannot be null");
MyMessage obj = (MyMessage) target;
if (obj.getSecondField != null && obj.getSecondField > 100) {
errors.rejectField(errors, "secondField", "{javax.validation.constraints.Max}", "secondField is too big");
}
}
}
And here is the service class that uses the #SpringValid annotation:
MyService.java
package com.example.services;
import com.example.messages.MyMessage;
import org.springframework.validation.annotation.SpringValid;
import org.springframework.validation.annotation.Validated;
import javax.inject.Inject;
#Validated
public class MyService {
public String doIt(#SpringValid final MyMessage msg) {
return "we did it!";
}
}
Hope this makes sense for someone at some point. I personally think it is quite useful. A lot of companies are starting to move their internal APIs away from REST and to something like Protobuf or Thrift. You can still use Bean Validation but you have to use XML, and it isn't all that nice. So I hope this will be helpful to people who want to still do programmatic validation.
Hope it helps someone. I've got it working by adding the following configuration:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
#Configuration
public class ValidatorConfiguration {
#Bean
public MethodValidationPostProcessor getMethodValidationPostProcessor(){
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.setValidator(this.validator());
return processor;
}
#Bean
public LocalValidatorFactoryBean validator(){
return new LocalValidatorFactoryBean();
}
}
The service is then annotated the same way (#Validated on the class and #Valid on the parameter) and can be injected into another bean where the method can be called directly and validation happens.
Out team is currently programming a JavaEE webapplication for use on a Tomcat appserver.
We want to handle persistence using Hibernate (5.0.1). To access the database entities, we use EntityManagers (not from JPA, they were implemented by us, see below) which provide methods to list, create and delete rows in the associated tables. The model classes use Hibernate Annotations for the mapping.
We also have a static class PersistenceController which initializes Hibernate's SessionFactory and provides a static method to get a newly opened session.
Of course we want to be able to use unit tests to test the functionality of our classes, so the PersistenceController is a little thorn in our eyes.
Someone else recommended me to move everything from the PersistenceController into the EntityManager base class. He wasn't sure if this would have any side consequences though.
So I thought "let's ask the hive mind". What would be the best practice in this case?
(If more code is needed, I'm happy to provide it)
PersistenceController
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
public class PersistenceController {
private static final SessionFactory sessionFactory;
static {
final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure() // configures settings from hibernate.cfg.xml
.build();
try {
sessionFactory = new MetadataSources(registry).buildMetadata()
.buildSessionFactory();
} catch (Exception e) {
// The registry would be destroyed by the SessionFactory, but we had
// trouble building the SessionFactory
// so destroy it manually.
StandardServiceRegistryBuilder.destroy(registry);
throw e;
}
}
public static Session openSession() {
return sessionFactory.openSession();
}
}
EntityManager
import java.util.List;
public abstract class EntityManager<T extends PersistenceEntity> {
public abstract List<T> listAll();
public abstract void save(T entity);
public abstract void delete(T entity);
}
ProductManager
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.Transaction;
import etepat.model.product.Product;
public class ProductManager extends EntityManager<Product> {
public ProductManager() {
super();
}
#Override
public List<Product> listAll() {
try (Session session = PersistenceController.openSession()) {
Transaction transaction = null;
try {
transaction = session.beginTransaction();
#SuppressWarnings("unchecked")
List<Product> returned = session.createCriteria(Product.class)
.list();
transaction.commit();
return returned;
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
}
}
return new ArrayList<Product>();
}
#Override
public void save(Product entity) {
// TODO Auto-generated method stub
}
#Override
public void delete(Product entity) {
// TODO Auto-generated method stub
}
}
The idea of your EntityManager(better call BaseDao or GenericDao) is good but needs some improvements.
First, base CRUD methods don't have to be abstract. They can simply persist/load/delete/list on generic type T. That way you don't have to write these methods on each subclass. See this generic dao approach https://github.com/athanasiosem/Hibernate-Generic-Dao-Java/blob/master/src/main/java/com/demien/hibgeneric/dao/GenericDAOImpl.java
Second is, you're managing transactions manually, is there a good reason to do so?
With container managed transactions(using annotations) you don't need to, and they greatly simplify your code by eliminating the boilerplate try{...}catch{//rollback}.
Basically, with a GenericDao<T> and container managed transactions you don't need this code at all, your classes sublass the GenericDao<ConcreteType> with concrete types and they're ready to do CRUD on database without a single line of code.
I am following this tutorial to create my first Spring Hibernate JSF app, and in this tutorial http://marco-ng.blogspot.com/2014/02/primefaces-jsf2-spring-security-spring.html?showComment=1440293840519#c5483896447188701172 the developer used a UserDAO and CustomerDAO which are one for getting login name and the other to manager customers. For my sample, I'm using one class User merging the two used functions (User will login, and then he will manager totality of Users).
My Question is, can I simply merge those two DAO in one UserDAO :
User DAO :
package spring.dao;
import spring.model.User;
public interface UserDAO {
public User getUser(String login);
}
Custommer DAO :
package spring.dao;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import spring.dao.CustomerDAO.ComponentScan;
import spring.model.Customer;
import java.util.List;
#Repository
public class CustomerDAO {
public #interface ComponentScan {
}
#Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void addCustomer(Customer customer) {
getSessionFactory().getCurrentSession().save(customer);
}
public void deleteCustomer(Customer customer) {
getSessionFactory().getCurrentSession().delete(customer);
}
public void updateCustomer(Customer customer) {
getSessionFactory().getCurrentSession().update(customer);
}
public Customer getCustomerById(int id) {
List list = getSessionFactory().getCurrentSession().createQuery("from Customer where id=?").setParameter(0, id).list();
return (Customer)list.get(0);
}
public List<Customer> getCustomers() {
List list = getSessionFactory().getCurrentSession().createQuery("from Customer").list();
return list;
}
}
The goal of all this is about using Management functions as long as Login from same class. And as I'm following a tuto to learn, I can't know the exceptions or things that are impossible to do before asking about them.
Thank you
NO both DAO should remain sepparated.
You can (and should for what you explain) create a single service for all the management, in this service ManagementBS for example you must inject DAO's with #Autowired annotation.
What you can do is a BasicDAO using reflection for basic operation like save, getById, delete... shared between all classes.
The DAO can't be merged because login needs an interface which is has no superclass but an interface. This means both DAO remains but both inherit data from model UserDAO.