Getting java.io.NotSerializableException with a spring service when stopping tomcat - spring

i am using spring 3 with JSF 2
and i replaced JSF managed beans with spring beans, by adding on top of bean:
#Component("mybean")
#Scope("session")
and in my bean i am autowiring a spring service (which was declared with the annotation #service)
well, everything works fine with the service, but when i tried to stop tomcat 6, i am getting this exception with my spring service
java.io.NotSerializableException
any ideas why i am getting this exception, and how to solve it.
UPDATE:
after making my service implements serializable, sometimes i am getting following exception:
java.lang.IllegalStateException: Cannot deserialize BeanFactory with id org.springframework.web.context.WebApplicationContext:/spring_faces: no factory registered for this id
at org.springframework.beans.factory.support.DefaultListableBeanFactory$SerializedBeanFactoryReference.readResolve(DefaultListableBeanFactory.java:972)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at java.io.ObjectStreamClass.invokeReadResolve(ObjectStreamClass.java:1061)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1762)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:480)
at org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor.readObject(AbstractBeanFactoryPointcutAdvisor.java:98)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:974)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1849)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1667)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1323)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:480)
at org.springframework.aop.framework.AdvisedSupport.readObject(AdvisedSupport.java:550)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:974)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1849)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at org.apache.catalina.session.StandardSession.readObject(StandardSession.java:1496)
at org.apache.catalina.session.StandardSession.readObjectData(StandardSession.java:998)
at org.apache.catalina.session.StandardManager.doLoad(StandardManager.java:394)
at org.apache.catalina.session.StandardManager.load(StandardManager.java:321)
at org.apache.catalina.session.StandardManager.start(StandardManager.java:648)
at org.apache.catalina.core.ContainerBase.setManager(ContainerBase.java:446)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4631)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
at org.apache.catalina.core.StandardService.start(StandardService.java:525)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
please advise.

Looking at the error, It looks like tomcat is trying to serialize the entire spring context, I think it might be due to the fact that your are implementing Serializable on Service. I was thinking may be you need to do this, I don't know JSF that well but my understanding of scoped beans makes me think, You might need some thing like this
#Component
#Scope(proxyMode=ScopedProxyMode.TARGET_CLASS, value="session")
public class MyBean implements Serializable
{
//no need to implement serializable on service
#Autowired(required=true)
private MyService service;
}

You get this exception because the class does not implement Serializable. Tomcat serializes currently running HttpSession objects including all its attributes to disk whenever it is about to restart/redeploy, so that they are revived after the cycle. Session scoped objects are stored as attributes of the HttpSession, hence they need to implement Serializable to survive the restart/redeploy as well.
If you would like to make them Serializable, then implement it accordingly:
public class YourSpringService implements Serializable {}
Otherwise, just ignore the exception or turn off serializing sessions to disk in Tomcat's config.
Note that the same story also applies to JSF view/session scoped beans.

Well, finally i was able to make it work fine as follows:
1- The Service:
#Service
#Scope("singleton")
public class PersonService{
}
2- The Spring Managed Bean:
#Component("person")
#Scope("session")
public class PersonBean implements Serializable{
#Inject
private PersonService personService;
}
waiting for your feedback.

I had to use readObject() + static ApplicationContext hack to solve the issue:
#Component
#Scope(value = SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class FlashMessages implements Serializable {
#Autowired
transient private SomeBean someBean;
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
// restore someBean field on deserialization
SpringUtils.getContext().getAutowireCapableBeanFactory().autowireBean(this);
}
}
#Component
public class SpringUtils implements ApplicationContextAware {
static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtils.applicationContext = applicationContext;
}
public static ApplicationContext getContext() {
return applicationContext;
}
}

Related

spring security messaging throws NullPointerException internally (Spring context is null!)

this is websocket security config:
#Configuration
public class WSSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer implements ApplicationContextAware {
#Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.nullDestMatcher().denyAll()
.simpSubscribeDestMatchers("/topic/t01", "/topic/t99").authenticated()
.anyMessage().denyAll();
}
}
the context fails to load with this error (trimmed only to the relevant parts):
Caused by: java.lang.NullPointerException: null
at org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer.configureClientInboundChannel(AbstractSecurityWebSocketMessageBrokerConfigurer.java:106) ~[spring-security-config-5.3.3.RELEASE.jar:5.3.3.RELEASE]
at org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration.configureClientInboundChannel(DelegatingWebSocketMessageBrokerConfiguration.java:73) ~[spring-websocket-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.messaging.simp.config.AbstractMessageBrokerConfiguration.getClientInboundChannelRegistration(AbstractMessageBrokerConfiguration.java:153) ~[spring-messaging-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.messaging.simp.config.AbstractMessageBrokerConfiguration.clientInboundChannelExecutor(AbstractMessageBrokerConfiguration.java:144) ~[spring-messaging-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration$$EnhancerBySpringCGLIB$$e1380a16.CGLIB$clientInboundChannelExecutor$35(<generated>) ~[spring-websocket-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration$$EnhancerBySpringCGLIB$$e1380a16$$FastClassBySpringCGLIB$$1a42e7b2.invoke(<generated>) ~[spring-websocket-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration$$EnhancerBySpringCGLIB$$e1380a16.clientInboundChannelExecutor(<generated>) ~[spring-websocket-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_342]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_342]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_342]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_342]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
... 93 common frames omitted
I looked at the culprit class AbstractSecurityWebSocketMessageBrokerConfigurer, the exception was thrown in method configureClientInboundChannel, the context is null. after some debugging I found out that the context was set before this method get called (of course with not null value) by setApplicationContext but the object (proxy) reference was not same when these two method was called (configureClientInboundChannel and setApplicationContext)
#Override
public final void configureClientInboundChannel(ChannelRegistration registration) {
ChannelSecurityInterceptor inboundChannelSecurity = context.getBean(ChannelSecurityInterceptor.class);
.
.
.
}
more information:
spring boot version: 2.3.1.RELEASE
spring security version: 5.3.3.RELEASE

Spring Boot 2.0.0.M4 throws ConverterNotFoundException on Spring Data REST call

I tried to bump my project up to the most recent Spring Boot 2.0.0 milestone (M4 at the moment of this writing) and I keep getting an exception for a missing Converter (ZonedDateTime to java.util.Date) although it's clearly configured - to me at least. Here's the code and stacktrace:
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import java.time.ZonedDateTime;
import java.util.Date;
#Component
public class ZonedDateTimePersistenceConverter implements Converter<ZonedDateTime, Date> {
#Nullable
#Override
public Date convert(ZonedDateTime source) {
return Date.from(java.time.ZonedDateTime.now().toInstant());
}
}
When calling the respective Spring Data REST endpoint I get:
2017-09-17 21:07:53.634 ERROR 1894 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.time.ZonedDateTime] to type [java.util.Date]] with root cause
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.time.ZonedDateTime] to type [java.util.Date]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:321) ~[spring-core-5.0.0.RC4.jar:5.0.0.RC4]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:194) ~[spring-core-5.0.0.RC4.jar:5.0.0.RC4]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:174) ~[spring-core-5.0.0.RC4.jar:5.0.0.RC4]
at org.springframework.data.rest.webmvc.HttpHeadersPreparer.lambda$getLastModifiedInMilliseconds$5(HttpHeadersPreparer.java:123) ~[spring-data-rest-webmvc-3.0.0.RC3.jar:na]
at java.util.Optional.map(Optional.java:215) ~[na:1.8.0_131]
at org.springframework.data.rest.webmvc.HttpHeadersPreparer.getLastModifiedInMilliseconds(HttpHeadersPreparer.java:123) ~[spring-data-rest-webmvc-3.0.0.RC3.jar:na]
at org.springframework.data.rest.webmvc.HttpHeadersPreparer.prepareHeaders(HttpHeadersPreparer.java:83) ~[spring-data-rest-webmvc-3.0.0.RC3.jar:na]
at org.springframework.data.rest.webmvc.ResourceStatus.getStatusAndHeaders(ResourceStatus.java:71) ~[spring-data-rest-webmvc-3.0.0.RC3.jar:na]
at org.springframework.data.rest.webmvc.RepositoryEntityController.lambda$getItemResource$3(RepositoryEntityController.java:337) ~[spring-data-rest-webmvc-3.0.0.RC3.jar:na]
at java.util.Optional.map(Optional.java:215) ~[na:1.8.0_131]
at org.springframework.data.rest.webmvc.RepositoryEntityController.getItemResource(RepositoryEntityController.java:333) ~[spring-data-rest-webmvc-3.0.0.RC3.jar:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) ~[spring-web-5.0.0.RC4.jar:5.0.0.RC4]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-5.0.0.RC4.jar:5.0.0.RC4]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.0.RC4.jar:5.0.0.RC4]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:869) ~[spring-webmvc-5.0.0.RC4.jar:5.0.0.RC4]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:775) ~[spring-webmvc-5.0.0.RC4.jar:5.0.0.RC4]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.0.RC4.jar:5.0.0.RC4]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:981) ~[spring-webmvc-5.0.0.RC4.jar:5.0.0.RC4]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:915) ~[spring-webmvc-5.0.0.RC4.jar:5.0.0.RC4]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978) ~[spring-webmvc-5.0.0.RC4.jar:5.0.0.RC4]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:870) ~[spring-webmvc-5.0.0.RC4.jar:5.0.0.RC4]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:855) ~[spring-webmvc-5.0.0.RC4.jar:5.0.0.RC4]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.20.jar:8.5.20]
...
I've already done some research like debugging and inspecting the GenericConversionService, DefaultConversionService, manually adding it to the converter registry via WebMvcConfigurerAdapter... to no avail.
Any idea where I should look further or what's going here?
Thanks a lot in advance! :)
Edit 1: Additional information to what I've tried and where it's happening. Adding the converter manually didn't help, like so:
#Component
public class AdditionalConverterConfig extends WebMvcConfigurerAdapter {
#Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new ZonedDateTimePersistenceConverter());
}
}
Funnily, the error occurs when I try to access the URI to one of the entities exposed via a Spring Data REST repository (entity is called "Posting", btw), like so:
#RepositoryRestResource(collectionResourceRel = "postings", path = "postings")
public interface PostingRepository extends PagingAndSortingRepository<Posting, Long> {
}
A GET for /api/postings works just fine, listing the first collection page as expected. GET /api/postings/1 however does not. The only critical ZonedDateTime properties in the entity are from its mapped superclass:
#CreatedDate
protected ZonedDateTime createdAt;
#LastModifiedDate
protected ZonedDateTime modifiedAt;
In the listing they appear just fine - in the detail view... not so much ;)

Spring Boot: javax.persistence.TransactionRequiredException: Executing an update/delete query

I am using Spring Boot and configured my Application like this:
#Configuration
#EnableAutoConfiguration
#EnableTransactionManagement
#ComponentScan
#EntityScan("ch.xy.model")
public class Application {
#Autowired
private ImportDAO importDao;
}
ImportDAO looks like that:
#Repository
public class ImportDAO {
#PersistenceContext
private EntityManager em;
#Transactional
void removeTempoAccounts() {
Query q = em.createQuery("DELETE FROM TempoAccount t WHERE t.manual = false");
q.executeUpdate();
}
}
But when removeTempoAcconts is executed I get:
Exception in thread "main" javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:360)
at com.sun.proxy.$Proxy49.executeUpdate(Unknown Source)
at ch.post.pf.jira.tempocats.pspimport.ImportDAO.removeTempoAccounts(ImportDAO.java:95)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:711)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
at ch.post.pf.jira.tempocats.pspimport.ImportDAO$$EnhancerBySpringCGLIB$$1883cf82.removeTempoAccounts(<generated>)
at ch.post.pf.jira.tempocats.pspimport.PspImport.run(PspImport.java:32)
at ch.post.pf.jira.tempocats.pspimport.Application.main(Application.java:20)
What's wrong with my configuration?
#Transactional
void removeTempoAccounts() {
Method had default visibility. Therefore the proxy mechanism was not active!
After changing to public everthing works as expected!
Try to use the #Transactional annotation from Spring package
like #org.springframework.transaction.annotation.Transactional
Then it should work

Trying to evict second level cache

I am trying to evict the second level cache in my persistence entity manager. Looks like I can use the following function defined in the javax.persistence.Cache interface:
/**
* Clear the cache.
*/
public void evictAll();
And in order to get the Cache object, I can use the following function defined in the javax.persistence.EntityManagerFactory interface:
/**
* Access the cache that is associated with the entity manager
* factory (the "second level cache").
* #return instance of the <code>Cache</code> interface
* #throws IllegalStateException if the entity manager factory
* has been closed
*
* #since Java Persistence 2.0
*/
public Cache getCache();
I wire my EntityManagerFactory as such:
#Repository("persistenceManager")
public class PersistenceManager
{
public EntityManagerFactory emf;
#PersistenceUnit(unitName="snap")
public void setEntityManagerFactory(EntityManagerFactory emf) {
this.emf = emf;
...
}
With the following applicationContext configuration file:
< bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
< property name="persistenceUnitName" value="snap" />
< property name="persistenceUnitManager" ref="pum" />
When I call getCache() on the object, I get the following exception:
Caused by: java.lang.AbstractMethodError:
org.hibernate.ejb.EntityManagerFactoryImpl.getCache()Ljavax/persistence/Cache;
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597) at
org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.invokeProxyMethod(AbstractEntityManagerFactoryBean.java:376)
at
org.springframework.orm.jpa.AbstractEntityManagerFactoryBean$ManagedEntityManagerFactoryInvocationHandler.invoke(AbstractEntityManagerFactoryBean.java:517)
at com.sun.proxy.$Proxy26.getCache(Unknown Source) at
com.rbccm.gelp.server.util.PersistenceManager.getCache(PersistenceManager.java:30)
at
com.rbccm.gelp.server.service.SystemDataServiceImpl.evictAllSecondLevelCacheEntries(SystemDataServiceImpl.java:133)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597) at
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at com.sun.proxy.$Proxy34.evictAllSecondLevelCacheEntries(Unknown
Source) at
com.rbccm.gelp.server.SystemGwtServiceImpl.evictAllSecondLevelCacheEntries(SystemGwtServiceImpl.java:132)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597) at
com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:561)
This indicates to me that getCache (defined in the interface) is not actually implemented in the object that is being wired into EntityManagerFactory. So, I put a breakboint in setEntityManagerFactory(EntityManagerFactory emf) and I noticed the concrete type of the object is in fact: org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
When I browse the source code of this class, I can confirm that getCache() is not implemented here. I believe I am using the correct/compatible versions:
Hibernate 3.6.10
Spring 3.1.1
JPA 2.0
Has anyone come across any similar issues or is able to reproduce this problem? How do I address this? If not, then what is an alternative to evict all cache items from second level cahce?
hibernate has different cache realization. In hibernate property file use property hibernate.cache.provider_class to set concrete cache class.

How to mock SessionFactory or Session by PowerMockito in a project using Spring and Hibernate?

I am working on a project that uses Spring and Hibernate. I have an abstract DAO that contains SessionFactory. I need to mock SessionFactory or Session for my unit test. But I have not been successful so far. Below is the code. Anyone has any idea? Thank you.
Here is my AbstractDAO
public abstract class AbstractDAO {
protected JdbcTemplate jdbcTemplate;
protected SessionFactory sessionFactory;
protected NamedParameterJdbcTemplate namedParameterJdbcTemplate;
...
#Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}}
And here is my ConcreteDAO
public class LoginDAO extends AbstractDAO implements InitializingBean {
...
public User getLoggedinUserByUserid(Long userid){
log.info("in getLoggedinUserByUserid");
User result = null;
Session session = sessionFactory.openSession();
try {
session.beginTransaction();
result = (User) session.get(User.class, userid);
session.getTransaction().rollback();
session.close();
} catch (Exception e) {
log.error(e,e);
session.getTransaction().rollback();
session.close();
}
return result;
}
...}
and here is my test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "LoginDAOTest-context.xml" })
#PrepareForTest({SessionFactory.class, Session.class, Transaction.class})
public class LoginDAOTest2 extends BaseDAO {
private static final Logger log = Logger.getLogger(LoginDAOTest2.class);
#Rule
public PowerMockRule rule = new PowerMockRule();
private LoginDAO loginDAO = new LoginDAO();
private SessionFactory mockedSessionFactory;
private Session mockedSession;
private Transaction mockedTransaction;
#Autowired
public void setSessionFactory(SessionFactory sessionFactoryCore) {
mockedSessionFactory = PowerMockito.mock( sessionFactoryCore.getClass());
mockedSession = PowerMockito.mock(Session.class);
PowerMockito.doReturn(mockedSession).when(mockedSessionFactory).openSession();
PowerMockito.doReturn(mockedTransaction).when(mockedSession).beginTransaction();
loginDAO.setSessionFactory(this.mockedSessionFactory);
}
#Test
public void shouldRollbackInGetLoggedinUserByUseridWhenSessionThrowsException() {
// Given
PowerMockito.doThrow(new Exception()).when(mockedSession).get(User.class, 12L);
// When
loginDAO.getLoggedinUserByUserid(12L);
// Then
verify(mockedTransaction, times(1)).rollback();
}
}
and here is the result of junit.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.aeon.ps.dao.LoginDAOTest2': Injection of autowired dependencies failed; nested exception is java.lang.NoClassDefFoundError: org/mockito/internal/MockitoInvocationHandler
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:374)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.NoClassDefFoundError: org/mockito/internal/MockitoInvocationHandler
at org.powermock.api.mockito.PowerMockito.mock(PowerMockito.java:138)
at com.aeon.ps.dao.LoginDAOTest2.setSessionFactory(LoginDAOTest2.java:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:586)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:284)
... 26 more
Caused by: java.lang.ClassNotFoundException: org.mockito.internal.MockitoInvocationHandler
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 35 more
Why don't do this :
#Before
public void setUp() {
mockedSessionFactory = Mockito.mock(SessionFactory.class);
mockedSession = Mockito.mock(Session.class);
mockedTransaction = Mockito.mock(Transaction.class);
Mockito.when(mockedSessionFactory.openSession()).thenReturn(mockedSession);
Mockito.when(mockedSession.beginTransaction()).thenReturn(mockedTransaction);
loginDAO.setSessionFactory(this.mockedSessionFactory);
}
instead of :
#Autowired
public void setSessionFactory(SessionFactory sessionFactoryCore) {
mockedSessionFactory = PowerMockito.mock( sessionFactoryCore.getClass());
mockedSession = PowerMockito.mock(Session.class);
PowerMockito.doReturn(mockedSession).when(mockedSessionFactory).openSession();
PowerMockito.doReturn(mockedTransaction).when(mockedSession).beginTransaction();
loginDAO.setSessionFactory(this.mockedSessionFactory);
}
In addition, it allows you to not use powermock.
Interesting part is here :
Caused by: java.lang.NoClassDefFoundError: org/mockito/internal/MockitoInvocationHandler
at org.powermock.api.mockito.PowerMockito.mock(PowerMockito.java:138)
at com.aeon.ps.dao.LoginDAOTest2.setSessionFactory(LoginDAOTest2.java:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:586)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:284)
... 26 more
It means that powermock is using an internal class that is not available in the mockito distribution your are using.
From that information I gather you are using Mockito 1.9.5-rc1, with some other recent Powermock release. As of now, Johan din't released a newer version of Powermock that take care of the changes that were made in Mockito 1.9.5-rc1.
These refactoring changes in Mockito were made to help the introduction of the MockMaker API, which allows a third party to provide his own mock factory, bytecode engine or else to create mocks.
See the documentation here : http://docs.mockito.googlecode.com/hg/1.9.5-rc1/org/mockito/Mockito.html
So for now, you should use Mockito 1.9.0 if you are using Powermock.

Resources