WebSphere Application Server & Liberty

 View Only

Injecting Spring Beans to JAX-RS resource running on Websphere Application Server 9 , JDK 1.8

  • 1.  Injecting Spring Beans to JAX-RS resource running on Websphere Application Server 9 , JDK 1.8

    Posted Thu September 21, 2023 12:47 PM
    Edited by Sibi Vaithara Fri September 22, 2023 09:33 AM

    Hi all

    I have a JAX-RS application running on Websphere Application Server 9.0.5 (Java 1.8). I would like to make use of spring for the backing business classes and hence was attempting to inject Spring (Core – version 5.3.27) beans into the JAX-RS application

    I understand that theIBM JAX-RS  implementation relies on the com.ibm.websphere.jaxrs.server.IBMRestServlet for its initialization. Following post at http://www.javavillage.in/spring-ioc-on-servlets.php ,  I tried  creating a custom servlet extending the IBMRestServlet and adding Spring autowiring to its init method

    package org.my.example;
    
    
    
    
    import org.springframework.beans.factory.annotation.Configurable;
    import org.springframework.web.context.support.SpringBeanAutowiringSupport;
    
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import com.ibm.websphere.jaxrs.server.IBMRestServlet;
    @Configurable
    public class MyHttpServlet extends IBMRestServlet {
    
        @Override
        public void init(ServletConfig config) throws ServletException {
    
            super.init(config);
            SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
    
        }
    
    }

    This required, the IBM Websphere jars ( From "Websphere installation folder/Dev")  to be added to my POM along with spring-web, aspectjweaver, spring-aspects , spring-context-support, spring-context etc as mentioned in link

    <dependency>
                    <groupId>com.ibm.websphere</groupId>
                    <artifactId>j2ee</artifactId>
                    <version>1.0.0</version>
                    <scope>system</scope>
                    <systemPath>C:/IBM/WebSphere/AppServer/dev/JavaEE/j2ee.jar</systemPath>
    </dependency>
    
    
    <dependency>
                    <groupId>com.ibm.websphere.appserver.api</groupId>
                    <artifactId>com.ibm.websphere.appserver.api.jaxrs</artifactId>
                    <version>1.0.80</version>
    </dependency>
    <dependency>
                    <groupId>org.apache.wink</groupId>
                    <artifactId>wink-server</artifactId>
                    <version>1.4</version>
    </dependency>
    <dependency>
                    <groupId>com.ibm.websphere.appserver</groupId>
                    <artifactId>was_public</artifactId>
                    <version>9.0.0</version>
    </dependency>

    Following was added to web.xml

    <listener>
                    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
                    <param-name>contextConfigLocation</param-name>
                    <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    
    
    
    <servlet>
           <servlet-name>JAXRSConfiguration</servlet-name>
           <servlet-class> org.my.example.MyHttpServlet </servlet-class>
           <init-param>
               <param-name>javax.ws.rs.Application</param-name>
               <param-value> org.my.example.RestConfig </param-value>
           </init-param>
           <load-on-startup>1</load-on-startup>

    Note: org.my.example.RestConfig is my class that extends javax.ws.rs.core.Application

    Unfortunately the build fails with following error which I am unable to resolve with any dependencies

    java: cannot access com.ibm.ws.ras.instrument.annotation.InjectedFFDC
    
      class file for com.ibm.ws.ras.instrument.annotation.InjectedFFDC not found

    As an alternate approach, I tried injecting spring to Rest Resource

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.stereotype.Component;
    
    @Component
    
    @Path("/mypath")
    
    public class MyResource {
      
                    @Autowired
                    TestClass testClass;
    
    private static final Logger LOGGER = LoggerFactory.getLogger(MyResource.class);
    
                    @POST
    
                    @Path("/subpath")
    
                    @Consumes(MediaType.APPLICATION_JSON)
    
                    @Produces(MediaType.APPLICATION_JSON)
    
                    public Response getMyResourceList(MyRequest request) {
    
                                    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    
                                    TestClass tClass = applicationContext.getBean(TestClass.class);
    
                                    if(tClass!=null){
    
                                                    LOGGER.debug("TestClass not null");
    
                                    }
    
                                    LOGGER.debug("tClass-------->-"+tClass.testMethod());
    
                                    LOGGER.debug("testClass------>"+testClass.testMethod());
    
                    }

    The Web.xml was modified as below

    <listener>
                    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
                    <param-name>contextConfigLocation</param-name>
                    <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    
    <listener>
                    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
                    <param-name>contextConfigLocation</param-name>
                    <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>

    With servlet still pointing to IBMRestServlet as in original JAX-RS application

    <servlet>
           <servlet-name>JAXRSConfiguration</servlet-name>
           <servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
           <init-param>
               <param-name>javax.ws.rs.Application</param-name>
               <param-value> org.my.example.RestConfig</param-value>
           </init-param>
           <load-on-startup>1</load-on-startup>
       </servlet>

    My Bean looks as follows

    @Component
    public class TestService {
        public String testMethod(){
            return "spring class";
        }
    }

    Here I am successfully able to get the bean instance but since the Application context is created per resource, I do not think it's a good way.

    Request your help and suggestions

    Thanks in Advance

    ------------------------------
    Sibi Vaithara
    ------------------------------