0

Im trying to migrate my ejbs to Dao's and here is my implementation : Frameworks : Struts 2, Spring 4.3.7, Hibernate 4.3.10

Web.xml :

<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/classes/appContext.xml</param-value>
    </context-param>
<listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
<filter>
        <filter-name>struts2-prepare</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter</filter-class>
    </filter>
  <filter>
      <filter-name>sitemesh</filter-name>
      <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
  </filter>
  <filter>
      <filter-name>struts2-execute</filter-name>
      <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter</filter-class>
  </filter>
  <listener>
      <listener-class>com.abc.filter.AppContextListener</listener-class>
  </listener>

My Spring configuration : appContext.xml

<!-- data source and sessionFactory -->

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="ABCJNDI" />
</bean>


<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
        <property name="persistenceUnitName" value="abcPersistenceUnit" />
        <property name="dataSource" ref="dataSource" />
</bean>

<context:component-scan base-package="com.abc" />

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<context:annotation-config />
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="employeeService" class="com.abc.daoimpl.EmployeeDAOImpl "></bean>

    <bean id="templateAction" class="com.abc.action.TemplateAction">
        <property name="employeeService" ref="employeeService" />
    </bean>


</beans>

My Action Class :

package com.abc.action

    public class TemplateAction extends ActionSupport implements Preparable {


        @Autowired
        public EmployeeDAO employeeService;
        /**
        *   All other stuff
        **/
    }



package com.abc.action
    public class Login extends TemplateAction{


//      @Autowired
//      public EmployeeDAO employeeService; // tried here also returns null;

        public String login(){

            employeeService.getEmployees(); // employeeService returns null here 

            return SUCCESS;
        }
    }

Listner Class : AppContextListener:

package com.abc.filter
    public class AppContextListener{

        @Autowired
        public EmployeeDAO employeeService;

        public void contextInitialized(ServletContextEvent contextEvent) {
            applicationContext  = new ClassPathXmlApplicationContext("appContext.xml");

            employeeService = applicationContext.getBean(EmployeeDAO.class);

            employeeService.getEmployees();
        }

    }

Employee Class :

package com.abc.dao
    public interface EmployeeDAO  {
        public List<EmployeeEntity> getEmployees();
    }

    package com.abc.daoimpl
    @Repository("employeeService")
    public class EmployeeDAOImpl extends SessionAdapter implements EmployeeDAO{
        public List<EmployeeEntity> getEmployees(){
            Query selectQuery = getEntityManager().createNativeQuery("select * from ...");
        }       
    }



@Entity
    @Table(name="EMPLOYEE_TABLE")
    public class EmployeeEntity{
        /**
         * private fields and getters and setters
        **/
    }


public class SessionAdapter {

    @PersistenceContext(unitName="abcPersistenceUnit")
    private EntityManager entityManager;

    public EntityManager getEntityManager() {
        return entityManager;
    }
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }
}

Problem is that in my action classes both in TemplateAction & in Login I'm getting the autowired property employeeService as null. But in my Listner class AppContextListener if I try to load the appContext.xml manually then its loading the service fine and I am able to access the employeeService and get the result.

Neil Stockton
  • 11,383
  • 3
  • 34
  • 29
Jeff
  • 1
  • 1
  • How do you instantiate those classes? If using null, spring does not manage these insances and hence the fields are not autowired. In this case you may want to set up @Configurable, or get the instances with "prototype" scope using context.getBean(TemplateAction.class) method. – malejpavouk Mar 29 '17 at 20:03
  • Ok I updated my appContext.xml bean definitions and made spring load the beans and injected the service to the Template action. Still I'm getting the employeeService as null. Please find the updated appContext.xml – Jeff Mar 29 '17 at 21:01
  • Looks ok, but still one piece is missing in the question, instantiation of templateAction instances. Or more specifically, how do you inject them into your program. Why I am asking: making sure that there is no duplicate instantiation. (and duplicate instance is probably there, because Spring context never injects nulls, unless "required" is set to false. The context construction would fail in your case. And as it does not, Spring is probably not creating the instance, you are debugging...) – malejpavouk Mar 29 '17 at 21:08
  • I also tried TemplateAction templateAction = new TemplateAction(); in my Login action still I'm getting the service as null. Actually I was under the impression that when I loaded my beans from my AppContextListener manually, then itself the beans get wired to the context since the listener is before the Login action. – Jeff Mar 29 '17 at 21:12
  • creating using new will not work (unless @Configurable support is setted up), Spring will not know about any "manually" instantiated objects. If you want to verify the multiple instances theory, try adding breakpoint/logging to ctor of TemplateAction. You have it configured as a singleton, so you can be sure that there >must< be just a single instance...but my guess is, that you will see that you have multiple... – malejpavouk Mar 29 '17 at 21:19
  • if loaded directly from context using "getBean", the instance is managed and hence should be injected with the dependencies. – malejpavouk Mar 29 '17 at 21:20
  • Tried scope = "singleton" still the service is null. do you mean I need to manually set & get from the context like following : 'Component public class SpringUtils { public static ApplicationContext ctx; Autowired private void setApplicationContext(ApplicationContext applicationContext) { ctx = applicationContext; } } EmployeeDAO employeeService= (EmployeeDAO)SpringUtils.ctx.getBean(EmployeeDAO.class);' ?? – Jeff Mar 29 '17 at 22:29
  • 1
    If you want to use Spring with Struts you have to setup the integration correctly, which you haven't. Spring doesn't own the beans that struts creates, nor does it even know about them. Hence injection will never happen (unless you start using full blown Aspect with compile time weaving and `@Configurable` which I wouldn't suggest). Instead properly setup the Struts and Spring integration. See [the struts documentation](https://struts.apache.org/docs/spring-and-struts-2.html) on how to do that. – M. Deinum Mar 30 '17 at 05:25
  • Also in your listener don't manually load the context again, you are basically loading your application again with that. Instead use the `WebApplicationContextUtils` to get the context loaded by the `ContextLoaderListener` instead. – M. Deinum Mar 30 '17 at 05:28
  • Ok Thanks for the suggession.. I modified the listener now and Instead of using ClassPathXmlApplicationContext I'm using WebApplicationContextUtils to lookup the beans. – Jeff Mar 30 '17 at 19:33
  • I understood that my actions are not mentioned as spring beans. But since I'm migrating my legacy application, I have about a hundreds of classes. According to the documentation mentioned above. Do I need to change the property of all my actions in struts xml in order to mention the same in spring beans. Or is there any other way in the spring context xml to mention the struts xml files. I have more than 100 actions in about 10 struts xml files. – Jeff Mar 30 '17 at 19:33
  • I tried removing autowire and related annotations and did manual xml bean configuration and did exactly how the documentation link suggests. Even then it doesn't work. Moreover there is no solution on the topic marked as the duplicate of... – Jeff Mar 31 '17 at 03:06
  • Now I'm planning to create a singleton class to load the beans from the context manually with suggested WebApplicationContextUtils. @M. Denium thanks for the suggestion. – Jeff Mar 31 '17 at 03:08
  • 1
    Have you actually read the documentation? You should include the plugin, configure the wiring mode to Spring (you don't have to add all your struts actions as spring beans you need to configure struts accordingly). – M. Deinum Mar 31 '17 at 05:49
  • Yes I read the Document thoroughly once again. And I found that I'm missing Struts 2-Spring-plugin.xxx jar. And along with it, I had to upgrade to latest struts and all related jars. And that fixed the issue. Thank you all for the support M.Denium & malejpavouk & @Roman C . Really Appreciate it. And just wanted to know your opinion on the design I've followed here. A TemplateAction with all the services that are wired in it and All other actions extend to the TemplateAction. Since all my services(DaoImpl) are singletons by default. Whats your comment/suggestion. – Jeff Apr 04 '17 at 19:38

0 Answers0