Affichage des articles dont le libellé est Spring. Afficher tous les articles
Affichage des articles dont le libellé est Spring. Afficher tous les articles

samedi 27 octobre 2012

Liferay : how to fix NoSuchBeanDefinitionException while portlet deploying

I would like to share the fix for mysterious and annoying issue that I've encountered during the development and deploying of a portlet for Liferay 5.2.3.

The error that Liferay server (Tomact) listed in the logs was related to misconfigured Spring beans and the exception was org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'my.service.persistence.SynergieCategoryPersistence.impl' is defined 
The partial stacktrace is belows:

16:36:12,700 ERROR [PortalClassLoaderServletContextListener:92] org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'my.service.SynergieCategoryLocalService.impl': Injection of BeanReference fields failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'my.service.persistence.SynergieCategoryPersistence.impl' is defined
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'fr.smile.synergie.service.SynergieCategoryLocalService.impl': Injection of BeanReference fields failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'my.service.persistence.SynergieCategoryPersistence.impl' is defined
 at com.liferay.portal.spring.annotation.BeanReferenceAnnotationBeanPostProcessor.postProcessAfterInstantiation(BeanReferenceAnnotationBeanPostProcessor.java:67)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:959)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
 at java.security.AccessController.doPrivileged(Native Method)
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
 at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
 at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
 at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:429)
 at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:728)
 at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:380)
 at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:255)
 at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:199)
 at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:45)
 at com.liferay.portal.spring.context.PortletContextLoaderListener.contextInitialized(PortletContextLoaderListener.java:77)
 at com.liferay.portal.kernel.servlet.PortalClassLoaderServletContextListener.portalInit(PortalClassLoaderServletContextListener.java:89)
 at com.liferay.portal.kernel.util.PortalInitableUtil.init(PortalInitableUtil.java:47)
 at com.liferay.portal.kernel.servlet.PortalClassLoaderServletContextListener.contextInitialized(PortalClassLoaderServletContextListener.java:73)
 at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3843)
 at org.apache.catalina.core.StandardContext.start(StandardContext.java:4342)
 at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
 at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
 at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
 at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:926)
 at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:889)
 at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
 at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1217)
 at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:293)
 at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
 at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1337)
 at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1601)
 at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610)
 at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1590)
 at java.lang.Thread.run(Thread.java:680)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'my.service.persistence.SynergieCategoryPersistence.impl' is defined
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:387)
 at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:971)
 at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:246)
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
 at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:880)
 at com.liferay.portal.bean.BeanLocatorImpl.locate(BeanLocatorImpl.java:59)
 at com.liferay.portal.kernel.bean.PortalBeanLocatorUtil.locate(PortalBeanLocatorUtil.java:58)
 at com.liferay.portal.spring.annotation.BeanReferenceElement.getResourceToInject(BeanReferenceElement.java:70)
 at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:180)
 at org.springframework.beans.factory.annotation.InjectionMetadata.injectFields(InjectionMetadata.java:105)
 at com.liferay.portal.spring.annotation.BeanReferenceAnnotationBeanPostProcessor.postProcessAfterInstantiation(BeanReferenceAnnotationBeanPostProcessor.java:64)
 ... 36 more


The portlet classes have been generated by build-service and the same code worked fine during last 2 years. So I was pretty sure that my Spring config is OK and the problem resides in the other part of the system.

After few days spent in debug mode, I have found that while deploying the portlet, the folder WEB-INF/lib was missing the jar file util-java.jar.
Obviously, util-java.jar is needed by Liferay to make some stuff. And apparently, in my case, this jar have not been copied automatically by Liferay hot deployer.

I have copied the missing util-java.jar to WEB-INF/lib and portlet has been deployed without any error.

dimanche 20 mars 2011

Integration tests with JUnit and Spring


Récemment dans le framework Spring j'ai trouvé une classe très utile pour faire des tests d'integration avec la base de données - AbstractTransactionalJUnit4SpringContextTests.
Cette classe contient plusieurs méthodes utilitaires pour tester le code qui interagit avec la BD. Voici la liste des méthodes que j'ai utilisé pour créer les tests d'intégration très élégante - faciles à implémenter et lire:
Je vais décrire la stratégie la plus facile à écrire une classe de test d'intégration est la suivante:
  1. Ecrire une classe de tests qui hérite de AbstractTransactionalJUnit4SpringContextTests
  2. Définir une méthode setUp avec l'annotation @BeforeTest. Cette méthode va utiliser executeSqlScript pour préparer la base de données en y injectant les données qui sont nécessaires pour l'exécution de votre méthode de test. Attention, à ne pas utiliser les ";" à la fin des lignes avec SQL. Les lignes qui se terminent par le ";" seront ignorés par Spring.
  3. La méthode de test qui va faire des "asserts" sur le nombre des lignes insérées dans les différentes tables impactés par les opérations DAOs. Pour faire ces asserts la méthode countRowsInTable est la plus appropriées.
  4. Pour que la base de données reste dans son état initial, il faut supprimer maintenant toutes les données qui ont y été ajoutées par deux étapes précédentes. Pour cela, il suffit de créer une méthode tearDown annotée par @AfterTest, dans cette méthode vous pouvez appeler la méthode généreusement offerte par Spring - deleteFromTables.
Regardez les fonctionnalités complètes de cette classe sur le site officiel de Spring ici.