I am able to inject EntityManager in my Service class without defining any persistence-unit.
This is my configuration:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
<jpa:repositories base-package="com.example"></jpa:repositories>
In my Service class:
#PersistenceContext
private EntityManager entityManager;
// THIS WORKS!
final Session session = entityManager.unwrap(Session.class);
Is it because of the jpa:repositories ?
Spring ORM package's LocalContainerEntityManagerFactoryBean class makes this possible. It uses DefaultPersistenceUnitManager class to build an instance of PersistenceUnitInfo which can then be provided to PersistenceProvider class's createContainerEntityManagerFactory. Hibernate implements this interface so that Spring can create an instance of EntityMangerFactory class.
DefaultPersistenceUnitManager class is the one that creates a persistenceUnit called default and finds all the entity classes going through the classes on the classpath. Same information acquired from the persistence.xml has been taken in with a alternative approach like this without having a physical persistence.xml file.
Finally Spring uses JpaVendorAdapter configured to get the JPA provider- specific EntityManagerFactory instance.
Spring data JPA specific <jpa:repositories base-package="...." /> or #EnableJpaRepositories uses to scan all the beans annotated with #Repository to provide dynamic queries and other features. This is not an exhaustive explanation but you see how this "magic" happens.
You can find more on grepcode or download the sources to explore more.
Related
Premise
I have a Spring 5.1.5 project with Hibernate 5.4.1
The compilation goes through fine but while running test cases for a particular package I see multiple tests failing. All with the same error:
javax.persistence.TransactionRequiredException: no transaction is in progress at com.project.server.package.dao.impl.SomeDAOImplTest.someTest(SomeDAOImplTest.java:54)
The Problem
Now I know that Hibernate 5 enforces the check for a transaction and it doesn't find one here and throws an exception. My question is why does it do that given I have transactions initialized via spring context.
My test case:
#ContextConfiguration({ "classpath:/spring/applicationContext-package-dao--test.xml" })
public class SomeDAOImplTest extends AbstractDAOTest {
#Autowired
private SomeDAO someDAO;
private className obj;
#Before
public void setUp() {
obj = new ClassName();
obj.setId(3);
someDAO.saveOrUpdate(obj);
}
My applicationContext-package-dao--test.xml:
<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">
<import resource="classpath:/spring/applicationContext-persistence-datasource-test.xml" />
<import resource="classpath:/spring/applicationContext-package-dao.xml" />
</beans>
The imported context applicationContext-persistence-datasource-test.xml has a bean txProxyTemplate as below:
<beans>
.
.//other beans
.
<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager" />
</bean>
<bean id="transactionManager" class="com.desktone.transaction.DtResourcelessTransactionManager" />
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
.
.//other beans
.
</beans>
The other applicationContext-package-dao.xml has the bean definition for SomeDAO which has txProxyTemplate as it's parent.
<bean id="SomeDAO" parent="txProxyTemplate">
<property name="target">
<bean class="com.project.server.package.dao.impl.SomeDAOImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="saveOrUpdate">PROPAGATION_REQUIRED</prop>
<prop key="delete">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
The saveorupdate call from SomeDAOImplTest calls SomeDAOImpl whose spring context config is applicationContext-package-dao.xml and has the Hibernate saveorupdate() call.
Things I have Tried:
Manually adding #Transactional tag to SomeDAOImplTest. (still throws no tx error)
Experimenting with PROPAGATION.REQUIRES_NEW (still throws no tx error) & PROPAGATION.MANDATORY(says marked mandatory but no tx).
Made sure the autowire is initialzing the bean.
Primary Suspicion
I suspect somehow the someDAO bean is initialized but txProxyTemplate bean isn't, so no transactionManager is in place. However, I have found no clues to coroborate this.
For me, this was happening because of a very fundamental issue. I'll explain the issue and the fix will be intuitive to everyone afterward.
When a Spring application runs all the beans are loaded in a single/global context. So even if some spring bean configuration depends on a transaction bean(for me it was txProxyTemplate) which isn't present in the same package at runtime it will be able to access it.
However, that's not true for a test case. My tests were reporting no transaction in progress since they couldn't load the txProxyTemplate and actually start a transaction. So my tests never ran in a transaction and I didn't know any better until I upgraded to Hibernate 5 and they put a hard constraint on this.
As you might have guessed defining the txProxyTemplate in the same spring config helped me work past this issue.
Good learning.
There are many variations on the setup of multiple persistence contexts within spring, but none that explain the problem that I am facing.
I have an application context structure like this:
core AC
`-- web-root AC
In my core application context i have defined both my two datasources and a transactionManager as well as a single EntityManagerFactory bean:
<!-- core applicationContext.xml -->
<beans ...>
<context:annotation-config/>
...
<!-- Container managed datasources -->
<jee:jndi-lookup id="module1DS" jndi-name="jdbc/module1DS" expected-type="javax.sql.DataSource"/>
<jee:jndi-lookup id="securityDS" jndi-name="jdbc/securityDS" expected-type="javax.sql.DataSource"/>
<bean id="transactionManager" class="org.springframework.transaction.jta.WebSphereUowTransactionManager"/>
<bean id="securityEMF" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="securityPU"/>
<property name="jtaDataSource" ref="securityDS"/>
<property name="packagesToScan" value="com.example.security.model"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter"/>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.websphere.WebSphereLoadTimeWeaver"/>
</property>
</bean>
</beans>
In the web-root application context i have defined an additional EMF:
<!-- module1 applicationContext.xml -->
<beans...>
....
<bean id="module1EMF" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="module1PU"/>
<property name="jtaDataSource" ref="module1DS"/>
<property name="packagesToScan" value="com.example.module1.model"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter"/>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.websphere.WebSphereLoadTimeWeaver"/>
</property>
</bean>
</beans>
Now I have a couple entities defined under the com.example.core.model package in the core module and also a single entity defined in the com.example.module1.model package in module1 (which is a war in an ear).
There is a service defined in core that gets the EntityManager injected into with the securityPU PersistenceContext and performs a named query on an entity in the database:
#Service("coreThingService")
public class CoreEntityThingServiceImpl implements CoreEntityThingService {
#PersistenceContext(unitName = "securityPU")
#Qualifier("securityEMF")
private EntityManager em;
#Override
public List<CoreEntityThing> getCoreEntityThingById(String id) {
// select a from CoreEntityThing a where a.id = :id
TypedQuery<CoreEntityThing> query = em.createNamedQuery("CoreEntityThing.findById", CoreEntityThing.class);
query.setParameter("id", id);
return query.getResultList();
}
}
nevermind about my unusual logic here, the point is that when this service is injected into the web-tier inside a #Controller and invoked, I get the following error:
org.apache.openjpa.persistence.ArgumentException: An error occurred while parsing the
>query filter "select a from CoreEntityThing a where a.id = :id". Error message: The
>name "CoreEntityThing" is not a recognized entity or identifier. Perhaps you meant
>Module1Entity, which is a close match. Known entity names: [Module1Entity]
I have Inspected the injected em:
#PersistenceContext(unitName = "securityPU")
#Qualifier("securityEMF")
private EntityManager em;
and have found it to be the securityPU as expected, what i didn't expect however is when it said that it couldn't find the entities (even though the packagesToScan property of the securityEMF was correctly pointing to the right package).
More strangely, it suggested an entity in the 'child' PU -- Module1Entity -- that should not have been picked up in the securityEMF.
What am i doing wrong?
UPDATE 1: I have updated my application context xml descriptions to make clear how i have created my PUs
UPDATE 2: It appears my classes are being scanned as I can see them in the persistence unit at runtime, what is really intriguing, is that up until the invokation of the createNamedQuery method on the EntityManager proxy is called (using method.invoke(targetPU, name) where method is the createNamedQuery function and targetPU is the securityEMF PU), The PU remains as the securityEMF. I can't go any deeper into code to see what createNamedQuery is actually doing, but during this invokation, the described error is thrown! what on earth is happening?!
To make things clearer, The error message's query string:
"select a from CoreEntityThing a where a.id = :id"
sits on top of my CoreEntityThing class!
package com.example.core.model.security;
...
#Entity
#NamedQuery(name = "CoreEntityThing.findById", query = "select ...")
public class CoreEntityThing { ... }
so it is finding the entity, then claiming it knows nothing about it!
UPDATE 3: I've read in this blog post about a supposed limitation of JPA PersistenceUnits having limited modularity. can anyone point me to more documentation about this limitation and any examples of multi module enterprise solutions using multiple datasources. This has to be a common concern for a large number of sizable projects.
I'm using java 1.6 and spring 3.0.4, I want to realize a java functionality that
calculate new data values
update one-by-one the existing values on the database
If in any of this step there's an error I want to rollback the whole transaction and come back to the previous state.
I already realized all this pieces of code, I just want to put them together. How I can manage this with the existing spring values that are working with #Entity and #Column annotations?
Thanks!
Short answer: as you're using Spring, the easiest would be to use the transaction management, creating a service that represents this transaction unit and annotate the method with #Transactional
In practice, you need to configure a PlatformTransactionManager in your application. As you seem to use JPA, the JpaTransationManager seems like an obvious choice. To enable the processing of the #Transactional annotation, you can either use #EnableTransactionManagement or the <tx:annotation-driven/> namespace. Both are explained in the Javadoc of #EnableTransactionManagement
By default, a runtime exception thrown from that annotated method will manage a transaction rollback. If your code is using checked exceptions, you'll have to configure the rollbackFor attribute of the annotation.
There are more details and examples available in the documentation
For people that need the same configuration, here you can find how I solved this problem, integrating Hibernate with Spring.
<!-- session factory activate the transaction modules for the specified classes -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="configLocation" value="classpath:config-hibernate.xml" />
<property name="packagesToScan">
<list>
<!-- Additional packages required to be added if entities located elsewhere -->
<value>com.some.package.dao</value>
<value>com.some.package.model</value>
<value>com.some.package.SpecificClass</value>
</list>
</property>
<property name="mappingResources" ref="mappingResources"/>
<bean id="mappingResources" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<!-- here you can add your hibernate mapping query that you want to use on transaction -->
<value>config-hibernate-mapping.xml</value>
</list>
</property>
</bean>
<!-- This will activate transactional annotation -->
<tx:annotation-driven transaction-manager="transactionManager" />
#Service
#Transactional
public class SpecificClass {
// write your method, everyone of them will be transactional
// and there will be a commit in case of success or rollback in case of exception
}
I am attempting to use Apache Shiro with Spring and MongoDB. I am using Spring Data Repositories which are autowired. I have created my own custom realm for Shiro which uses a Spring Data repository to talk to Mongo:
public class PlatformRealm extends AuthorizingRealm {
#Autowired(required = true)
protected UserRepository userRepository = null;
#Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
...
}
}
The problem I'm seeing is the userRepository isn't being autowired. I get the following line in my console output referring to the PlatformRealm:
INFO org.springframework.web.context.support.XmlWebApplicationContext - Bean 'platformRealm' of type [class com.resonance.platform.core.security.PlatformRealm] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
This is because of the Apache Shiro ShiroFilterFactoryBean. What is happening is this bean and all of its dependencies are being loaded up immediately when the container is started. It doesn't wait for my persistence beans to be initialized prior to resolving dependencies. This causes the repository reference to be null.
The following bean configurations are loaded via the contextConfigLocation parameter:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/web-platform-persistence.xml,
/WEB-INF/web-platform-services.xml
</param-value>
</context-param>
Services bean configuration:
<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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<bean id="userSession"
class="com.resonance.platform.web.core.services.ShiroUserSessionService" />
<!-- Shiro (Security) -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login" />
<property name="successUrl" value="/" />
<!-- The 'filters' property is not necessary since any declared javax.servlet.Filter
bean -->
<!-- defined will be automatically acquired and available via its beanName
in chain -->
<!-- definitions, but you can perform instance overrides or name aliases
here if you like: -->
<!-- <property name="filters"> <util:map> <entry key="anAlias" value-ref="someFilter"/>
</util:map> </property> -->
<property name="filterChainDefinitions">
<value>
# some example chain definitions:
/admin/** = passThruFilter, roles[admin]
/** = passThruFilter
</value>
</property>
</bean>
<bean id="passThruFilter"
class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter" />
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- Single realm app. If you have multiple realms, use the 'realms' property
instead. -->
<property name="realm" ref="platformRealm" />
<!-- By default the servlet container sessions will be used. Uncomment
this line to use shiro's native sessions (see the JavaDoc for more): -->
<!-- <property name="sessionMode" value="native"/> -->
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor" />
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
<!-- Define the Shiro Realm implementation you want to use to connect to
your back-end -->
<!-- security datasource: -->
<bean id="platformRealm" class="com.resonance.platform.core.security.PlatformRealm" />
Persistence bean config:
<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:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<mongo:mongo id="mongo" />
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo" />
<constructor-arg value="platform" />
<property name="writeConcern">
<util:constant static-field="com.mongodb.WriteConcern.SAFE" ></util:constant>
</property>
</bean>
<mongo:repositories base-package="com.resonance.platform.core.data.repositories" />
User Repository:
package com.resonance.platform.core.data.repositories;
import org.bson.types.ObjectId;
import org.springframework.data.repository.CrudRepository;
import com.resonance.platform.core.entities.User;
/**
* A repository used to manage User entities.
* #author Kyle
*/
public interface UserRepository extends CrudRepository<User, ObjectId> {
/**
* Gets a user by the specified login.
* #param login
* #return
*/
User getByLogin(String login);
}
My question is, how can I get the userRepository dependency to resolved properly? I understand that the ShiroFilterFactoryBean has to be initialized before the other dependencies and whatnot, but there must be a way to get the userRepository dependency to be resolved.
EDIT: Added User Repository code.
I am running into the same problem described here.
I am noticing two spring factories.
from the dispacher-servlet.xml which loads #Service #Repository classes due to component-scan defined at an base package level so I can #Autowire Service class into Controller.
from application context doesn't seem to #Autowire classes marked as #Service because they are not loaded.
If I understand you right you should be able to create a subclass of ShiroFilterFactoryBean which implements org.springframework.beans.factory.InitializingBean. In InitializingBean.afterPropertiesSet() you would then add some code that gets the UserRepository and sets it to that field. Not the most elegant solution, but this looks like an exceptional case.
I've had this problem too. It has something to do with the order of bean initialization in the Spring container. The workaround is not to autowire the repository but have your realm implement ApplicationContextAware and get the needed beans straight from the context. It's not elegant, but it'll work.
I am not too sure if this is helpful, but you may check this question from me for an alternative solution.
But, the core issue probably still stays open.
Concrete problem explanation taken from ShiroFilterFactoryBean-and-a-spring-data-mongodb-realm:
The problem is that spring-data-mongodb requires a spring
ApplicationEventMulticaster to have been initialised before it can be
used.
ShiroFilterFactoryBean is a beanPostProcessor, and as such, during
initialisation, spring attempts to configure its realms(and hence my
realm and spring data mongo based userDao). it fails because
ApplicationEventMulticaster has not yet been created.
After I've tried several suggested ways to solve this problem, like the InitializingBean, ApplicationContextAware or BeanPostProcessor interfaces (each resulting in a premature invocation, hence before initializing my necessary service/repository stuff), I came up with the following solution:
Let spring create your shiro context without any automatic bean resolution to your services/repositories.
Let spring create your service/repository context, including mongodb
Create a simple class which will take care of your shiro-service coupling and configure it accordingly in your spring config. This class will be invoked after your shiro and service context has been successful set up.
To (1), sth. like this:
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="filterChainDefinitions">
<value>
<!-- Your definitions -->
</value>
</property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"
p:realm-ref="myShiroRealm" />
<bean id="myShiroRealm" class="com.acme.MyShiroRealm"
<!--no bean refs here-->
/>
To (2), sth. like this:
<bean id="myService" class="com.acme.MyService"
c:myRepository-ref="myRepository" />
...
<!-- Ask Spring Data to scan our repositories -->
<mongo:repositories base-package="com.acme.repository.impl.mongodb" />
To (3):
public class ShiroRealmServiceBridge {
public static void postInject( MyShiroServerRealm realm, MyService service ) {
realm.setService( service );
}
}
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass"><value>com.acme.ShiroRealmServiceBridge</value></property>
<property name="targetMethod"><value>postInject</value></property>
<property name="arguments">
<list>
<ref bean="myShiroRealm" />
<ref bean="myService" />
</list>
</property>
Advantages:
It works xD
No additional burden/dependencies on your shiro stuff
Complete spring configuration and setup, resulting in a consistent state after initialization
Disadvantage:
One time overhead setup
May result in an inconsistent state, which will complain at runtime rather than at startup, if you forget or bump the glue-configuration
The ShiroFilterFactoryBean implements the BeanPostProcessor and, since it has dependencies on the security manager w/ its own dependencies on data stores, data access objects, etc. it can cause a whole slew of Bean X of type Y is not eligible for getting processed by all BeanPostProcessors messages.
The worst part is that it seems to be just a way to see the Filter implementations that Spring is instantiating in order to track and possibly inject properties into AuthorizationFilters.
Frankly I don't need that headache just for filter tracking, so I created a custom version that did not include the BeanPostProcessor. I'm now forced to manually wire in Filter implementations to the beans "filters" property, but at least I don't have to deal with that error and the questionable status of my security manager and related beans.
I am trying to use transactions with MyBatis and Spring and was wondering if there is a best practice on how to achieve this? Any hints or thoughts are appreciated.
My application wil be running in a tomcat container against a MySQL database.
You want to take a look at the #Transactional annotation docs
In terms of best practices it is a mixture of database transactions and spring. Look at where you need to roll back your data, do you need JTA, etc.
Example class
#Transactional
public class DefaultFooService implements FooService {
Foo getFoo(String fooName);
}
Example xml
<!-- this is the service object that we want to make transactional -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- enable the configuration of transactional behavior based on annotations --> <tx:annotation-driven transaction-manager="txManager"/>
<!-- a PlatformTransactionManager is still required -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- (this dependency is defined somewhere else) -->
<property name="dataSource" ref="dataSource"/>
</bean>