about a BeanCurrentlyInCreationException, unresolvable circular reference - spring

Good afternoon, I have a project based on apache-cxf v 2.5.2, spring 2.5.6 and hibernate v v 3.2.1. I'm using annotations to mark the units and objects I persist and am having a problem when deploying the war. Giving me the following exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'storeService': Can not resolve reference to bean 'storeService' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'storeService': Requested bean is Currently in creation: is there an unresolvable loop reference?
this is the applicationContext.xml file
<?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:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
">
<context:component-scan base-package="com.aironman.core" />
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:hibernate.properties"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=${database.hibernate.dialect}
hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider
hibernate.show_sql=true
hibernate.use_sql_comments=true
hibernate.jdbc.batch_size=0
hibernate.hbm2ddl.auto=create-drop
hibernate.default_schema=${hibernate.default_schema}
hibernate.generate_statistics=true
hibernate.cache.use_structured_entries=true
</value>
</property>
<property name="annotatedClasses">
<list>
<value>com.aironman.core.pojos.Usuario</value>
<value>com.aironman.core.pojos.Item</value>
<value>com.aironman.core.pojos.Persona</value>
</list>
</property>
</bean>
</beans>
this is beans.xml
<?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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!-- DECLARACION DE LOS ENDPOINTS DE LOS WEB SERVICES-->
<jaxws:endpoint
id="storeService" implementor="#storeService"
implementorClass="com.aironman.core.cxf.service.StoreServiceImpl"
address="/Store" />
</beans>
both files are included on web.xml
this is implementation end point web service, storeService:
**#Service("storeService")
#WebService(endpointInterface = "com.aironman.core.cxf.service.StoreService")
public class StoreServiceImpl implements StoreService** {
private Log log = LogFactory.getLog(StoreServiceImpl.class);
#Autowired
#Qualifier("servicioUsuarios")
private ServicioUsuarios servicioUsuarios;
#Autowired
#Qualifier("servicioItems")
private ServicioItems servicioItems;
#Autowired
#Qualifier("servicioApuntes")
private ServicioApuntesContables servicioApuntesContables;
[B]public StoreServiceImpl()[/B]{
log.info("CONSTRUCTOR SIN tipo StoreServiceImpl...");
}
some methods... getters and setters ...
}
this is ServicioUsuariosImpl file:
package com.aironman.core.service;
**#Service("servicioUsuarios")
public class ServicioUsuariosImpl implements ServicioUsuarios** {
private static ConcurrentHashMap <String,Usuario>hashMapUsuarios = new ConcurrentHashMap <String,Usuario> () ;
private Log log = LogFactory.getLog(ServicioUsuariosImpl.class);
#Autowired
#Qualifier("servicioEncriptacion")
private ServicioEncriptacion servicioEncriptacion;
#Autowired
#Qualifier("servicioPersistenciaUsuarios")
private ServicioPersistenciaUsuarios servicioPersistenciaUsuarios;
public ServicioUsuariosImpl(){
log.info("Constructor SIN tipo ServicioUsuariosImpl...");
//TODO pendiente cargar el mapa con una llamada al servicioPersistencia
}
#PostConstruct
public void init()
{
log.info("init method on ServicioUsuariosImpl. Initializing hashMap...");
//i need to call persistence layer to fill the hashMap
}
some methods, getters and setters
}
As you can see, this service has inyected a persistent service called servicioPersistenciaUsuarios, which basically uses a dao marked as #repository.
this is ServicioPersistenciaUsuariosImpl implementation file:
package com.aironman.core.service;
**#Service("servicioPersistenciaUsuarios")
public class ServicioPersistenciaUsuariosImpl implements ServicioPersistenciaUsuarios** {
#Autowired
#Qualifier("usuarioHibernateDao")
private UsuarioHibernateDao usuarioHibernateDao;
private Log log = LogFactory.getLog(ServicioPersistenciaUsuariosImpl.class);
public ServicioPersistenciaUsuariosImpl()
{
log.info("Constructor ServicioPersistenciaUsuariosImpl...");
}
some methods, getters and setters
}
this is usuarioHibernateDao implementation file:
package com.aironman.core.hibernate;
**#Repository
public class UsuarioHibernateDao extends HibernateGenericDao<Usuario, String> implements UsuarioDao**
{
private Log log = LogFactory.getLog(UsuarioHibernateDao.class);
[B]#Autowired
public UsuarioHibernateDao(#Qualifier("sessionFactory") SessionFactory sessionFactory) [/B]{
super(sessionFactory);
}
some methods...
}
ServicioUsuariosImpl has another dependencie, servicioEncriptacion, and as you may see, this is the implementation:
package com.aironman.core.service;
#Service("servicioEncriptacion")
public class ServicioEncriptacionImpl implements ServicioEncriptacion
{
private static final String algoritmo = "SHA-256";
private Log log = LogFactory.getLog(ServicioEncriptacionImpl.class);
private static java.security.MessageDigest diggest ;
[B]public ServicioEncriptacionImpl()[/B]
{some code...
}
some methods...
}
this is ServicioItemsImpl implementation file, another dependencie belongs to StoreServiceImpl.
package com.aironman.core.service;
**#Service("servicioItems")
public class ServicioItemsImpl implements ServicioItems**{
private static final ConcurrentHashMap
<String,com.aironman.core.pojos.Item>
//La pk es el isbn del item
hashMapItems = new ConcurrentHashMap<String,com.aironman.core.pojos.Item>() ;
private Log log = LogFactory.getLog(ServicioItemsImpl.class);
#Autowired
#Qualifier("servicioPersistenciaItems")
private ServicioPersistenciaItems servicioPersistenciaItems;
[B]public ServicioItemsImpl()[/B]
{
log.info("Constructor SIN TIPO ServicioItemsImpl");
}
[B]#PostConstruct
public void init()[/B]
{
log.info("init method on ServicioItemsImpl. Initializing hashMap...");
}
some methods, getters and setters
}
this is servicioPersistenciaItems implementation file:
package com.aironman.core.service;
#Service("servicioPersistenciaItems")
public class ServicioPersistenciaItemsImpl implements ServicioPersistenciaItems
{
#Autowired
#Qualifier("itemHibernateDao")
private ItemHibernateDao itemHibernateDao;
private Log log = LogFactory.getLog(ServicioPersistenciaItemsImpl.class);
[B]public ServicioPersistenciaItemsImpl()[/B]
{
log.info("Constructor SIN tipo ServicioPersistenciaItemsImpl...");
}
some methods, getters and setters...
}
and finish, ServicioApuntesContablesImpl implementation file, with no dependencies
package com.aironman.core.service;
[B]#Service("servicioApuntes")
public class ServicioApuntesContablesImpl implements ServicioApuntesContables[/B]{
private Log log = LogFactory.getLog(ServicioApuntesContablesImpl.class);
private static ConcurrentHashMap <ClaveApunteContable,ApunteContable> mapaApuntesContables
= new ConcurrentHashMap <ClaveApunteContable,ApunteContable> ();
//TODO al final tendre que persistir los apuntes contables, por ahora los mantendre en memoria...
[B]public ServicioApuntesContablesImpl()[/B]
{}
some methods
}
in short, the problem is happening when Spring tries to instantiate the endpoint implementation file storeService and do not understand it because I have no typed constructor in any of the files, getters and setters I have the right and above any dependence is used to each other. Can someone please help me and explain what is happening? thank you very much
PD i have not put some code for readability issues and i easyly reach limit caracters, if someone needs to watch, let me know.

Ok, i allready solved my problem. Inside the endpoints.xml file a declared my ws with a id and i d already have declared the implementation ws file with a #Service annotation, so the exception is now clear to me...

Related

Auto wiring with qualifier annotation

I am trying to auto wire my Circle class. I am using a qualifier in order for Spring to able to distinguish between the two Point class beans i have created a qualifier.
public class Circle{
private Point center;
#Autowired
#Qualifier("circleRelated")
public void setCenter(Point center) {
this.center = center;
}
public void draw() {
System.out.println("Drawing Circle");
System.out.println("Centre point is " + center.getX());
}
}
The Point class is as follows
public class Point {
private int x;
public int getX() { return x; }
public void setX(int x) { this.x = x;}
}
The beans.xml is
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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.xsd">
<bean id="circle" class="com.example.Circle"/>
<bean id="pointA" class="com.example.Point">
<qualifier value="circleRelated" />
<property name="x" value="0"/>
<property name="y" value="0"/>
</bean>
<bean id="pointB" class="com.example.Point">
<property name="x" value="-20"/>
<property name="y" value="0"/>
</bean>
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
</beans>
My main class is
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
#SpringBootApplication
public class AutowiredAnnotationApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Circle circle = (Circle) context.getBean("circle");
circle.draw();
}
}
The error I get is
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.example.Point] is defined: expected single matching bean but found 2: pointA,pointB
Why is spring unable to autowire the bean with the given qualifier?
You have to remove this line from your beans.xml:
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
For some reason, it is meddling with your otherwise correct configuration.
The #Qualifier gets the bean id as value. So you have to use "pointA" or "pointB"
public class Circle{
private Point center;
#Autowired
#Qualifier("pointA")
public void setCenter(Point center) {
this.center = center;
}
public void draw() {
System.out.println("Drawing Circle");
System.out.println("Centre point is " + center.getX());
}
}
In general if you skip the #Qualifier - you autowire by type. That means "search in the Spring context a bean of that type and throw an exception if none or more than one is found".
If you add the #Qualifier("someName") that means - "search in the Spring context a bean of that type and with that name and throw an exception if none is found"
Edit:
Take a look at this. I don't think that you need tag at all.
If you wan't to inject some bean using #Autowired the #Qualifier needs the bean id as it's value. For example #Qualifier("pointA") will require a bean with id: pointA.
If you want to inject the bean using only xml you can use ref. You don't need Qualifier for that, only for autowireing.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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.xsd">
<bean id="circle" class="com.example.Circle">
<property name="center" ref="pointA"/>
</bean>
<bean id="pointA" class="com.example.Point">
<qualifier value="circleRelated" />
<property name="x" value="0"/>
<property name="y" value="0"/>
</bean>
<bean id="pointB" class="com.example.Point">
<property name="x" value="-20"/>
<property name="y" value="0"/>
</bean>
</beans>
Edit 2:
See this. I believe that the qualifier tag is taken into account only if you skip the bean id, otherwise the bean id is used.

#Autowired annotation returns null [duplicate]

This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 6 years ago.
When I develop in the Spring Framework, I wanted to get an access to DB using mybatis on the specific class, here is problem.
public class ScheduleManager {
private Scheduler scheduler;
#Autowired
private TriggerService triggerService;
public void doit() {
System.out.println(triggerService);
}
}
At here, value of triggerService is null. I think triggerService was not autowired.
But it is autowired at this class.
#Controller
public class TestController {
#Autowired
private TriggerService triggerService;
#RequestMapping("/scheduletest")
public String scheduleTest() {
System.out.println(triggerService);
ScheduleManager sm = new ScheduleManager();
sm.doit();
}
}
this code print some value not null.
dispatcher-servlet.xml
<?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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.scheduler"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
<property name="contentType" value="text/html;charset=UTF-8"/>
<property name="order" value="0"/>
</bean>
</beans>
TriggerService interface
#Service
public interface TriggerService {
public List<Trigger> getAll();
}
Why does this problem appear?
You create the ScheduleManager instance by yourself:
ScheduleManager sm = new ScheduleManager();
So Spring doesn't know about this object and doesn't do any autowiring.
To resolve this, add the #Component annotation to ScheduleManager and let it also inject in the controller:
#Autowired
private ScheduleManager scheduleManager;
Your TriggerService is only an Interface, how could spring find the acutual implementation.
remove #Service from TriggerService and add it to one of the implementation of TriggerService will fix your problem

Spring injected bean is null

I am using Spring Framework / Data / HATEOAS and trying to add Dozer.
I have the following bean in my spring-config.xml:
<?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:data="http://www.springframework.org/schema/data/jpa"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="POSTGRESQL" />
<property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect" />
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost:5432/cp" />
<property name="username" value="cp_user" />
<property name="password" value="+JMJ+pw0m2d" />
</bean>
<context:component-scan base-package="com.mydomain.data.assembler" />
<data:repositories base-package="com.mydomain.repository" />
<mvc:annotation-driven />
<bean id="dozerFactory" class="org.dozer.spring.DozerBeanMapperFactoryBean" scope="singleton">
<property name="mappingFiles" value="classpath*:/*mapping.xml"/>
</bean>
</beans>
And the following assembler:
#Component
public class UserResourceAssembler {
#Inject
private Mapper dozerBeanMapper;
public UserResource toResource(User user) {
UserResource resource = dozerBeanMapper.map(user, UserResource.class);
resource.add(linkTo(methodOn(UserController.class).get(user.getId())).withSelfRel());
return resource;
}
public User toEntity(UserResource resource) {
User user = dozerBeanMapper.map(resource, User.class);
return user;
}
}
So, - I'm very new to beans and injection - but I guess that the factory bean is ?supposed? to inject the Mapper. But the Mapper is definitely null. I know I'm not doing this right, but what am I doing wrong?
Spring injects its beans into spring managed beans. You are using an unmanaged static context. Change UserResourceAssembler into a managed bean as well:
#Component
public class UserResourceAssembler {
#Inject
private Mapper dozerBeanMapper;
public UserResource toResource(User user) {
}
public User toEntity(UserResource resource) {
}
}
See why can't we autowire static fields in spring.
I would have preferred something like the above. But then I read:
Dozer Singleton Startup Bean injetced as Null
That worked. Here was my implementation.
I removed the bean from spring-config, and the context scan.
I added this class:
#Singleton
public class DozerInstantiator {
public static DozerBeanMapper getInstance(){
return MapperHolder.instance;
}
private static class MapperHolder{
static final DozerBeanMapper instance = new DozerBeanMapper();
}
}
And updated my assembler like this:
public class UserResourceAssembler {
private DozerBeanMapper mapper;
public UserResourceAssembler() {
mapper = DozerInstantiator.getInstance();
}
public UserResource toResource(User user) {
UserResource resource = mapper.map(user, UserResource.class);
resource.add(linkTo(methodOn(UserController.class).get(user.getId())).withSelfRel());
return resource;
}
public User toEntity(UserResource resource) {
User user = mapper.map(resource, User.class);
return user;
}
}

JPA + Spring: UnexpectedRollbackException when Transaction is REQUIRED, REQUIRES_NEW or NESTED

I'm doing my first project with Spring, JPA, and GlassFish 3.1 and I'm having some troubles. I've been looking for a solution for a week, but I have found nothing.
I have an Entity (called Role), a GeneralReposiroty with general methods to access any entity, a RoleRepository which implements particular methods about Role, and a Service class, which calls RoleRepository. Methods of Service class are transactional, but I get RollBackException if the propagation property is REQUIRED, REQUIRES_NEW or NESTED. If propagation is MANDATORY, it's thrown an exception saying:
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:339)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:101)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
...
If it's NOT_SUPPORTED, NEVER or SUPPORT, select queries work fine, but I get the same RollbackException if I try to execute a create, update or delete query.
I've debugged the select queries, and before they throw the RollBackException, the query gets the result fine, and the exception is thrown just at the end of the function. In adition, if I get the Entities with find() of EntityManager and the service method doesn't have the #Transactional anotation, works fine, but if I make it transactional, it crashes with the same exception.
This happens with all entities I have, but I use that to explain the problem.
I think there is something wrong with my Spring configuration, but I don't know what.
This is the full trace of the exception (In some lines there are references to AuthenticationSuccessHandler class, because it's where I call to the service class from):
WARNING: StandardWrapperValve[default]: PWC1406: Servlet.service() for servlet default threw exception
org.springframework.transaction.UnexpectedRollbackException: JTA transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: Transaction marked for rollback.
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:845)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:662)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:632)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:314)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:116)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
at com.citius.reservas.service.service$$EnhancerByCGLIB$$37b50d4.tryJPAFind(<generated>)
at com.citius.reservas.AuthenticationSuccessHandlerImpl.onAuthenticationSuccess(AuthenticationSuccessHandlerImpl.java:47)
...
Caused by: javax.transaction.RollbackException: Transaction marked for rollback.
at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:428)
at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:855)
at com.sun.enterprise.transaction.UserTransactionImpl.commit(UserTransactionImpl.java:208)
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:842)
... 45 more
I have the following entity:
#Entity
#Table(name = "roles", catalog = "reservas")
#XmlRootElement
public class Role implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotNull
#Size(min = 1, max = 50)
private String name;
private static final long serialVersionUID = 1L;
GenericRepository, a general class, which is implemented by all the repositories:
public class GenericRepositoryImpl<T> implements GenericRepository<T> {
#PersistenceContext
private EntityManager em;
private Class<T> type;
public GenericRepositoryImpl( ){
Type t = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) t;
type = (Class) pt.getActualTypeArguments()[0];
}
#Override
public T find(Object pk) {
try{
return em.find(type, pk);
}catch(java.util.NoSuchElementException ex){
return null;
}
}
#Override
public T create(T t) {
em.persist(t);
em.flush();
em.refresh(t);
return t;
}
#Override
public List<T> query(Query q) {
List<T> list= q.getResultList();
if(list==null)
list=new ArrayList<T>();
return list;
}
}
This is the role repository:
#Repository
public class RoleRepositoryImpl extends GenericRepositoryImpl<Role>
implements RoleRepository{
#PersistenceContext
private EntityManager em;
#Override
public Role findByName(String name) {
Query q = (Query) this.em.createNamedQuery("Role.findByName");
q.setParameter("name", name);
Role r = (Role) q.getSingleResult();
return r;
}
#Override
public List<Role> findAll() {
Query q = (Query) this.em.createNamedQuery("Role.findAll");
return this.query(q);
}
}
The Service class:
#Service
public class service {
#Autowired
private RoleRepository roleRepository;
#Transactional
//This throws a RollBackException
public void tryJPAEmpty(){
roleRepository.findByName("example");
}
//This doesn't
public Role tryJPAFind(){
return roleRepository.find(new Integer(1));
}
}
Spring configuration (applicationContext.xml) is:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
">
<context:component-scan base-package="com.***.***" />
<jpa:repositories base-package="com.***.***.repositories" />
<tx:annotation-driven />
<tx:annotation-driven transaction-manager="transactionManager" />
<context:annotation-config />
<beans>
<bean id="EntityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="JPAReservas"/>
</bean>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager" >
<property name="allowCustomIsolationLevels">
<value>true</value>
</property>
</bean>
</beans>
</beans>
Persistence.xml (I have a data source and a connection pool created in my GlassFish server):
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="JPAReservas" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>Reservas_mysql</jta-data-source>
<!--Named queries-->
<mapping-file>META-INF/mapping/Role.xml</mapping-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
</persistence-unit>
</persistence>
And finally, I have named queires in a xml file, like that:
SELECT r FROM Role r
<named-query name="Role.findByName">
<query>SELECT r FROM Role r WHERE r.name = :name</query>
</named-query>
I'm really noob with Spring and JPA, so if you know some improvements, or changes I can do, please tell me.
Ok, I've solved it changing transaction-type to RESOURCE_LOCAL, but at the beggining, Glassfish gives me a lot of troubles. That's the way I solved it:
I've add metadata-complete="true" to the header of web.xml. Here is explained why is this necesary:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0" metadata-complete="true">
I've changed my persistence.xml, because with RESOURCE_LOCAL the application won't use the connection pool of Glassfish, I have to put information about database connection:
<persistence-unit name="JPAReservas" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<mapping-file>META-INF/mapping/User.xml</mapping-file>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/reservas"/>
<property name="javax.persistence.jdbc.user" value="admin"/>
<property name="javax.persistence.jdbc.password" value="adminpassword"/>
</properties>
</persistence-unit>
And at the end, I've changed the applicationContext.xml (Spring configuration), because I can't use the same EntityManager class with RESOURCE_LOCAL as with JTA:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="EntityManagerFactory" />
</bean>
And that's all. I don't know why I can't use JTA like I was doing before, but I've solved it!!! :). Thank you!

Unitils: How can it obtain database properties from Spring

I am using Unitils with Spring for unit testing. I've configured Spring with datasource using a properties file.
My question is how can I use the same datasource or the same properties for Unitils?
Unitils expects a file in the classpath unitils.properties with database configuration parameters like url, user, password and driver.
I've tried to configure Unitils using the properties used in the Spring configuration as below but it is not working.
database.driverClassName=${jdbc.driver.class}
Thanks,
Adi
One potential solution... You could have your Spring configuration read its datasource parameters from the unitils.properties, instead of the other way around. Probably not ideal.
I believe unitils is using spring under the covers, so you might also try adding your datasource context in your unitils tests by using #SpringApplicationContext. If you could figure out the name of the datasource bean setup by unitils when it starts up, you could override it in your context (assuming the unitils datasource bean is created before the other spring beans are which may/may not be true.)
e.g.
#SpringApplicationContext({"correctDataSourceContext.xml"})
EDIT: Another option that will definitely work: https://stackoverflow.com/a/6561782/411229
Basically instantiate Unitils yourself and set the properties manually.
Ryan answer is correct and helpful as well though I've used different approach.
I extended the class PropertiesDataSourceFactory ro override the methods as follows:
public class UnitilsDataSourceFactory extends PropertiesDataSourceFactory {
#Override
public void init(Properties configuration) {
try {
String[] configFiles = new String[] { "applicationContext-test.xml" };
BeanFactory factory = new ClassPathXmlApplicationContext(configFiles);
SystemPropertiesReader systemPropertiesReader = (SystemPropertiesReader) factory.getBean("systemPropertiesReader");
Properties loadProperties = systemPropertiesReader.loadProperties();
super.init(loadProperties);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public DataSource createDataSource() {
DataSource dataSource = super.createDataSource();
return dataSource;
}
}
and also wrote a SystemPropertiesReader as:
public class SystemPropertiesReader {
private Collection<Resource> resources;
public void setResources(final Collection<Resource> resources) {
this.resources = resources;
}
public void setResource(final Resource resource) {
resources = Collections.singleton(resource);
}
#PostConstruct
public Properties loadProperties() throws Exception {
final Properties systemProperties = System.getProperties();
for (final Resource resource : resources) {
final InputStream inputStream = resource.getInputStream();
try {
systemProperties.load(inputStream);
} finally {
//
}
}
return systemProperties;
}
}
and added a bean with the properties file:
<bean id="systemPropertiesReader" class="uk.co.friendslife.eventmanager.domain.dao.SystemPropertiesReader">
<property name="resource">
<value>classpath:/META-INF/em/config/eventmanager_${database_name_lower}.properties</value>
</property>
</bean>
add the following to unitils.properties:
org.unitils.database.config.DataSourceFactory.implClassName=x.y.UnitilsDataSourceFactory
Just want to add some idea and im not sure if it is a best practice or not so correct me if theres something wrong.
MYPROJECT
-src
--TestPackage
---BaseServiceTest.class
---BlogspotServiceTest.class
--hibernate.cfg.xml
-web
--WEB-INF
---blogspot-servlet-test.xml
---jdbc-test.properties
in my case I used my blogspot-servlet-test.xml to call or to create the datasource
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:lang="http://www.springframework.org/schema/lang"
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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
.... some bean configuration
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="file:web/WEB-INF/jdbc.properties"/>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- DAO'S -->
<bean id="blogspotDAO" class="package.BlogspotDAOImpl"/>
<!-- SERVICES -->
<bean id="blogspotService" class="package.BlogspotServiceImpl"/>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
MY jdbc-test.properties file
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.dialect=org.hibernate.dialect.MySQL5Dialect
jdbc.databaseurl=jdbc:mysql://127.0.0.1:3306/dbspringminiblogtest
jdbc.username=root
jdbc.password=
For hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd//hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping class="somePackage.entity.Author"/>
<!-- Other Entity Class to be mapped -->
</session-factory>
</hibernate-configuration>
and i created BaseClass for me to lessen creating of multiple #SpringApplicationContext annotation and it is also use to configure common configuration needed in testing other class, just extends it.
#SpringApplicationContext({"file:web/WEB-INF/blogspot-servlet-test.xml"})
public class BaseServiceTest extends UnitilsJUnit4 {
}
i used #SpringApplicationContext to load the datasource and other bean configurations on my BaseClass and this is how i implement it.
Below : see Spring-Unitils Tutorial
for more details
public class BlogspotServiceTest extends BaseServiceTest{
#Mock
#InjectInto(property = "blogspotDAO")
#SpringBean("blogspotDAO")
private BlogspotDAO blogspotDAOMock;
#TestedObject
#SpringBean("blogspotService")
private BlogspotService blogspotServiceMock;
#Test
public void testAddBlogSpot() {
assertNotNull("BlogspotService Not null",blogspotServiceMock);
}
}
NOTE: please create unitils.properties and unitils-local.properties inside TestPackage to be able to run the program.
For #SpringBean explanation and other annotation please read :
Unitils-EasyMock

Resources