No Session Hibernate in #PostConstruct - spring

MyDao class have the methods to do whole persistence tasks through Hibernate SessionFactory, it works fine.
I inject MyDao in MyService as can see above, but when #PostConstruct init() method is called after injected MyDao (debugging I can see MyDao well injected) get the next Hibernate exception:
org.hibernate.HibernateException: No Session found for current thread
My service implementation.
#Service("myService")
#Transactional(readOnly = true)
public class MyServiceImpl implements MyService {
#Autowired
private MyDao myDao;
private CacheList cacheList;
#PostConstruct
public void init() {
this.cacheList = new CacheList();
this.cacheList.reloadCache(this.myDao.getAllFromServer());
}
...
}
WAY TO SOLVE
As #Yogi recommended above to me, I have used TransactionTemplate to get one valid/active transaction session, in this case I have implemented throught constructor and works fine for me.
#Service("myService")
#Transactional(readOnly = true)
public class MyServiceImpl implements MyService {
#Autowired
private MyDao myDao;
private CacheList cacheList;
#Autowired
public void MyServiceImpl(PlatformTransactionManager transactionManager) {
this.cacheList = (CacheList) new TransactionTemplate(transactionManager).execute(new TransactionCallback(){
#Override
public Object doInTransaction(TransactionStatus transactionStatus) {
CacheList cacheList = new CacheList();
cacheList.reloadCache(MyServiceImpl.this.myDao.getAllFromServer());
return cacheList;
}
});
}
...
}

I don't think there is any transaction allowed on #PostConstruct level so #Transactional won't do much here unless mode is set to aspectj in <tx:annotation-driven mode="aspectj" />.
As per this discussion you can use TransactionTemplate to start manual transaction inside init() to bind session but if you intend to strictly adhere to declarative transaction you need to use ApplicationListener to register event and user ContextRefreshedEvent to initiate transaction.

Make sure you are running under transaction. I can see the transaction annotation but looks like you missed to activate the transaction management using annotation through the use of using <tx:annotation-driven/> tag in spring context.

This happens because MyServiceImpl.init() is called by Spring after MyServiceImpl related bean construction and #Transaction annotation is not used to manage session lifecycle.
A solution might be consider Spring AOP around methods that use the cache instead of #PostConstruct

Related

Use spring Transactional in a Prototype bean

I would like to use spring transaction management capabilities within a prototype bean. I did the following:
I've used javax.inject.Provider to create my prototype bean.
I've annotated the method of the prototyped bean with the #Transactional annotation.
Is this the right way of doing it?
#Service
public class SomeService {
#Autowired
private Provider<SomePrototype> myPrototypeProvider;
public void execute() {
SomePrototype somePrototype = myPrototypeProvider.get();
somePrototype.someMethod();
}
}
#Component
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class SomePrototype {
#Autowired
private SomeSpringBean someSpringBean;
#Autowired
private SomeRepository someRepository;
#Transactional(propagation = Propagation.REQUIRED)
public void someMethod() {
Result result = someSpringBean.doSomething();
someRepository.save(result);
}
}
The initialisation of transaction-scoped bean requires a proxy. Therefore, if we define a transactional bean as prototype, every that bean is requested, a new proxy is created, and that is not efficient.
What is reason behind this requirement (to have transactional prototype bean)

Transactional and Stream in Spring

I try to understand why this code doesn't work
In component:
#PostConstruct
public void runAtStart(){
testStream();
}
#Transactional(readOnly = true)
public void testStream(){
try(Stream<Person> top10ByFirstName = personRepository.findTop10ByFirstName("Tom")){
top10ByFirstName.forEach(System.out::println);
}
}
And repository :
public interface PersonRepository extends JpaRepository<Person, Long> {
Stream<Person> findTop10ByFirstName(String firstName);
}
I get:
org.springframework.dao.InvalidDataAccessApiUsageException: You're trying to execute a streaming query method without a surrounding transaction that keeps the connection open so that the Stream can actually be consumed. Make sure the code consuming the stream uses #Transactional or any other way of declaring a (read-only) transaction.
One key thing about Spring is that many annotated features use proxies to provide the annotation functionality. That is #Transactional, #Cacheable and #Async all rely on Spring detecting those annotations and wrapping those beans in a proxy bean.
That being the case, a proxied method can only be used when invoked on the class and not from within the class. See this about the topic.
Try:
Refactoring and call this #Transactional method from another class in your context, or
By self-autowiring the class into itself and calling the #Transactional method that way.
To demonstrate (1):
public class MyOtherClass {
#Autowired
private MyTestStreamClass myTestStreamClass;
#PostConstruct
public void runAtStart(){
// This will invoke the proxied interceptors for `#Transactional`
myTestStreamClass.testStream();
}
}
To demonstrate (2):
#Component
public class MyTestStreamClass {
#Autowired
private MyTestStreamClass myTestStreamClass;
#PostConstruct
public void runAtStart(){
// This will invoke the proxied interceptors for `#Transactional` since it's self-autowired
myTestStreamClass.testStream();
}
#Transactional(readOnly = true)
public void testStream(){
try(Stream<Person> top10ByFirstName = personRepository.findTop10ByFirstName("Tom")){
top10ByFirstName.forEach(System.out::println);
}
}
}

setting mocked object in case of spring annotation

I'm writing unit test case using Junit, EasyMock and Spring. I'm trying to mock DAO layer call. I've used annotation to inject bean in my application
Service layer class:
public class CustomerService {
#Autowired
private CustomerDao customerDao;
........
public void findCustomerByAccountNumber(String accountNumber){
}
}
Test case for service method:
public class CustomerServiceTest extends AbstractContextConfigLoaderTest{
private CustomerDao mockCustomerDao;
private CustomerService customerService;
private String accountNumber="5247710009575432";
#Before
public void setUp(){
mockCustomerDao= EasyMock.createMock(CustomerDao.class);
customerService= new CustomerService();
}
if i would have used setter injection using Spring bean configuration, i would've set mocked dao object to customerService like below.
customerService.setCustomerDao(mockCustomerDao);
How can i do the same in case of Spring annotation ?
You can use still setup a method
protected void setCustomerDao(CustomerDao customerDao)
and only use it in your JUnit to set the mocked dependencies. The protected access will prevent any class that is not in the same package from using that method.
I suggest enabling spring in your test with something like #RunWith(SpringJUnit4ClassRunner.class) and #ContextConfiguration, in your spring context for the test
make the mock as spring bean.
<bean class="org.easymock.EasyMock" factory-method="createMock">
<constructor-arg value="some.package.CustomerDao" />
</bean>
Now should be wired to the CustomerService, to record the expected behavior you will need to wire the mock in your test class:
#Autowired
private CustomerDao mockCustomerDao;
#Autowired
private CustomerService customerService;
Why not expose this through the constructor and inject it that way? Your production code can use Spring and your test code can just instantiate the object directly.
At the moment you're at the mercy of your DI framework. Break that dependency.

RemoteServiceServlet with spring autowired gives nullpointerexception

I'm using GWT with Spring. I encountered the problem of using an #Autowired bean in a RemoteServiceServlet. For some reason this doesn't work automatically and I need to use #Configurable to get this working. I followed this approach but I still get a NullPointerException for the #Autowired bean:
#Configurable
#Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public class AServiceImpl extends RemoteServiceServlet implements AService {
#Autowired
private IABean aBean;
#Override
public void aMethodFromAService(Args arg[]) {
aBean.aMethodOfABean(); // this gives a NullPointerException
}
}
#Component
public class ABean implements IABean {
...
}
Any guidance in what is going on? Any extra information I need to provide?
http://mitosome.blogspot.be/2011/01/injecting-spring-beans-into-gwt.html
Thanks Alexander for putting me in the right direction
You found a workable solution, but just for the record and we have it working as follows:
public class MyServiceImpl extends RemoteServiceServlet
implements MyService, ServletContextAware
{
#Autowired private transient SomeService someService;
....
}
and
<context:annotation-config/>
<context:component-scan base-package="..."/>
The SomeService is a completely vanilla XML-defined bean. Perhaps that or ...implements ServletContextAware makes a difference.
Cheers,

Dependency Injection into your Singleton

I have a singleton that has a spring injected Dao (simplified below):
public class MyService<T> implements Service<T> {
private final Map<String, T> objects;
private static MyService instance;
MyDao myDao;
public void set MyDao(MyDao myDao) {
this. myDao = myDao;
}
private MyService() {
this.objects = Collections.synchronizedMap(new HashMap<String, T>());
// start a background thread that runs for ever
}
public static synchronized MyService getInstance() {
if(instance == null) {
instance = new MyService();
}
return instance;
}
public void doSomething() {
myDao.persist(objects);
}
}
My spring config will probably look like this:
<bean id="service" class="MyService" factory-method="getInstance"/>
But this will instantiate the MyService during startup.
Is there a programmatic way to do a dependency injection of MyDao into MyService, but not have spring manage the MyService?
Basically I want to be able to do this from my code:
MyService.getInstance().doSomething();
while having spring inject the MyDao for me.
Here is a solution, create a class with a static factory method:
public class MyService {
private static MyService instance;
private MyDao myDao;
public static MyService createInstance(final MyDao myDao) {
instance = new MyService(myDao);
return instance;
}
private MyService(final MyDao myDao) {
this.myDao = myDao;
}
public static synchronized MyService getInstance() {
return instance;
}
public void doSomething() {
// just do it!
myDao.justDoIt();
}
}
and use spring to initilize it:
<bean class="my.path.MyService" factory-method="createInstance" scope="singleton">
<constructor-arg ref="reference.to.myDao" />
</bean>
and now you should be able to do:
MyService.getInstance().doSomething();
without any problems.
If you want a singleton, why not just define that one class in the Spring configs, and it's automatically a singleton (by default).
To avoid initialising at start up, have you looked at Spring lazy initialisation ? Basically you need:
lazy-init="true"
in your bean definition.
As mentioned by others, you should let spring manage your singletons, but if you want to manage them yourself and just let spring inject dependencies, do this:
applicationContext.getAutowireCapableBeanFactory().autowireBean(yourService);
I believe the FactoryBean interface is a good alternative for you. It's a very good choice when you need to execute some initialization logic. For example to start an in memory database or some background processes in separate threads.
You can read more about it in the reference documentation.
An example that demonstrates how I instantiate a database and return a datasource everytime someone wants a bean from the FactoryBean implementation.
#PostConstruct
void init() {
embeddedDatabase = new EmbeddedDatabaseBuilder().addScript(schemaPath)
.addScript(dataPath).setType(embeddedDatabaseType).build();
}
public DataSource getObject() throws Exception {
return embeddedDatabase;
}
This enables loose coupling between the factory logic and the returned object. It's heavily used by the Spring framework internally.
If you want it to be initialized the first time you use it, then set lazy-initialization to true.
Another alternative if you want your code to interact with the Spring container is to create a factory that implements the ApplicationContextAware interface. Then you can do something like this:
myDao = context.getBean(MyDao.class);

Resources