• Inject Spring Bean into Liferay Impl Class

    Posted on May 24, 2015 by Hamidul Islam in Liferay.

    inject-spring-bean-top


    aim

    To inject spring bean into Liferay Impl is quite straight forward. This article will explain how can we inject spring bean into Lifery Service class like LocalServiceImpl or ServiceImpl class. We can develop a portlet using different frameworks like Spring MVC, Prime Faces,Liferay MVC and so on. A portlet with code which are generated by service builder tool has its own spring context. Even a Liferay MVC Portlet with service (i.e., service.xml and generated class) has it own spring context. In this article we will demonstrate how to create our own custom bean and make them available in LocalServiceImpl class. 


    Note:

    This article only explains how to inject spring bean into Liferay Services. This article does not explain practical use of injecting spring bean into Liferay services. However for spring developer this technique will be very useful while developing Liferay portlet using Spring Framework. However we can inject spring bean into Liferay Services even in non spring based portlet.

    Step 1: Create the POJO class 

    Spring beans are nothing but POJO class. Here we will create POJO class

    package com.proliferay.pojo;
    
    import java.io.Serializable;
    
    public class Customer implements Serializable {
    
    	private static final long serialVersionUID = 1L;
    
    	private String firstName;
    	private String middleName;
    	private String lastName;
    	private int age;
    
    	public String getFirstName() {
    		return firstName;
    	}
    
    	public void setFirstName(String firstName) {
    		this.firstName = firstName;
    	}
    
    	public String getMiddleName() {
    		return middleName;
    	}
    
    	public void setMiddleName(String middleName) {
    		this.middleName = middleName;
    	}
    
    	public String getLastName() {
    		return lastName;
    	}
    
    	public void setLastName(String lastName) {
    		this.lastName = lastName;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    }
    

    Step 2: Create ext-spring.xml file and register the above POJO class as spring bean

    In the Step 1 we have created just a POJO class. We have to tell Liferay to use that POJO class as spring bean. This is done by using the file ext-spring.xml file. By default this file is not available.  We need to create this file under /docroot/WEB-INF/src/META-INF directory. After creating the file, add the below content

    <?xml version="1.0"?>
    
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	default-destroy-method="destroy" default-init-method="afterPropertiesSet"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    	<bean id="com.proliferay.pojo.Customer" class="com.proliferay.pojo.Customer" />
    </beans>
    

    Step 3: Tell LocalServiceImpl class to use this spring bean 

    The bean is ready, but we need to use it in our LocalServiceImpl class. To inject the bean into our LocalServiceImpl class we can use @BeanReference annotation. See the below code. 

    package com.proliferay.sbuilder.example.crud.service.impl;
    
    import java.util.List;
    
    import com.liferay.portal.kernel.bean.BeanReference;
    import com.liferay.portal.kernel.exception.SystemException;
    import com.proliferay.pojo.Customer;
    import com.proliferay.sbuilder.example.crud.model.Book;
    import com.proliferay.sbuilder.example.crud.service.base.BookLocalServiceBaseImpl;
    
    /**
     * The implementation of the book local service.
     *
     * <p>
     * All custom service methods should be put in this class. Whenever methods are added, rerun ServiceBuilder to copy their definitions into the {@link com.proliferay.sbuilder.example.crud.service.BookLocalService} interface.
     *
     * <p>
     * This is a local service. Methods of this service will not have security checks based on the propagated JAAS credentials because this service can only be accessed from within the same VM.
     * </p>
     *
     * @author Hamidul Islam
     * @see com.proliferay.sbuilder.example.crud.service.base.BookLocalServiceBaseImpl
     * @see com.proliferay.sbuilder.example.crud.service.BookLocalServiceUtil
     */
    public class BookLocalServiceImpl extends BookLocalServiceBaseImpl {
    	/*
    	 * NOTE FOR DEVELOPERS:
    	 *
    	 * Never reference this interface directly. Always use {@link com.proliferay.sbuilder.example.crud.service.BookLocalServiceUtil} to access the book local service.
    	 */
    
    	public List<Book> getBookByAuthor(String authorName) throws SystemException{
    		System.out.println("Accessing Spring Bean injected into the service::::"+customer.getFirstName());
    		return bookPersistence.findByAuthor(authorName);
    	}
    
    	@BeanReference(type=Customer.class)
    	private Customer customer;
    
    }
    

    Now the customer bean is ready to use in BookLocalServiceImpl class. Any method in the impl class can access the injected bean. 

    Important Note:

    The Customer bean is available in the Spring Context. We can retrieve the bean from the spring context at any time and we can update the bean according to our requirements. Consider that "crud-example-portlet" is the context path of our portlet. Then below is the code to access the customer bean in our portlet class. 

    BeanLocator beanLocator = PortletBeanLocatorUtil.getBeanLocator("crud-example-portlet");
    Customer customer = (Customer) beanLocator.locate("com.proliferay.pojo.Customer");
    

     

    Access-Bean

     

    In the portlet class we can update the bean like customer.setFirstName("John"). Once bean is updated it will be updated in all the places where the bean is used, as the bean is singleton in nature. Thus after updating the bean in portlet class if the Impl class method is invoked then the call customer.getFirstName()  will return John which was set in portlet class. Similarly if we update the bean in LocalServiceImpl class and try to access the bean in portlet class as shown in the above code we will get the updated bean.

    Good to know 

    List out all the beans under a given context(say crud-example-portlet):

    BeanLocator beanLocator = PortletBeanLocatorUtil.getBeanLocator("crud-example-portlet");
    String[] beans = beanLocator.getNames();
    for(String bean : beans){
    	System.out.println("#########bean##########"+bean);
    }
    

    List out all the beans under Portal level:

    BeanLocator beanLocator = PortalBeanLocatorUtil.getBeanLocator();
    String[] beans = beanLocator.getNames();
    for(String bean : beans){
    	System.out.println("#########bean##########"+bean);
    }
    

3 Responses so far.

  1. Csaba Tenkes says:

    For me the casting is not working. When I try to do this based on your example:

    BeanLocator beanLocator = PortletBeanLocatorUtil.getBeanLocator("scp-hook");
    GuiceUtils gUtils= GuiceUtils)beanLocator.locate("com.havilog.baltic.hooks.GuiceUtils");

    Than I got this:
    java.lang.ClassCastException: com.sun.proxy.$Proxy781 cannot be cast to com.havilog.baltic.hooks.GuiceUtils
    at com.havilog.baltic.hooks.service.organization.OrganizationServiceWrapperImpl.(OrganizationServiceWrapperImpl.java:57)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
    at com.liferay.portal.deploy.hot.HookHotDeployListener.initServices(HookHotDeployListener.java:1943)
    at com.liferay.portal.deploy.hot.HookHotDeployListener.doInvokeDeploy(HookHotDeployListener.java:634)
    at com.liferay.portal.deploy.hot.HookHotDeployListener.invokeDeploy(HookHotDeployListener.java:274)
    at com.liferay.portal.deploy.hot.HotDeployImpl.doFireDeployEvent(HotDeployImpl.java:195)
    at com.liferay.portal.deploy.hot.HotDeployImpl.fireDeployEvent(HotDeployImpl.java:97)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.liferay.portal.security.lang.DoPrivilegedHandler.doInvoke(DoPrivilegedHandler.java:88)
    at com.liferay.portal.security.lang.DoPrivilegedHandler.invoke(DoPrivilegedHandler.java:56)
    at com.sun.proxy.$Proxy29.fireDeployEvent(Unknown Source)
    at com.liferay.portal.kernel.deploy.hot.HotDeployUtil.fireDeployEvent(HotDeployUtil.java:27)
    at com.liferay.portal.kernel.servlet.PluginContextListener.fireDeployEvent(PluginContextListener.java:164)
    at com.liferay.portal.kernel.servlet.PluginContextListener.doPortalInit(PluginContextListener.java:154)
    at com.liferay.portal.kernel.util.BasePortalLifecycle.portalInit(BasePortalLifecycle.java:44)
    at com.liferay.portal.kernel.util.PortalLifecycleUtil.register(PortalLifecycleUtil.java:64)
    at com.liferay.portal.kernel.util.PortalLifecycleUtil.register(PortalLifecycleUtil.java:56)
    at com.liferay.portal.kernel.util.BasePortalLifecycle.registerPortalLifecycle(BasePortalLifecycle.java:54)
    at com.liferay.portal.kernel.servlet.PluginContextListener.contextInitialized(PluginContextListener.java:116)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4887)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5381)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633)
    at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1114)
    at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1672)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

  2. Csaba Tenkes says:

    I mean GuiceUtils gUtils= (GuiceUtils)beanLocator.locate("com.havilog.baltic.hooks.GuiceUtils");

  3. Csaba Tenkes says:

    Bean injection also not working when I do something like this:

    @BeanReference(type=GuiceUtils.class)
    protected GuiceUtils guiceUtils;

    my instance is null!

Top
%d bloggers like this: