deusprogrammer
deusprogrammer

Reputation: 105

Instantiate EJB Via Factory

So I have a service I am hooking by instantiating it through a factory that creates a proxy so it can process some annotations I have on the service. So my question is this...is there a way with JavaEE to have my dependency injection instantiate the instances of said service through the factory instead of however EJB's are normally instantiated by the server.

And otherwise...is there another way I could direct the Servlet or EJB container to process annotations for me? Like a bolt in of sorts that could have the code for handling the reflective analysis of the annotated class/method/fields?

I am sorry if this question is hard to understand, I'm having a hard time figuring out how to ask it. Here is an example of a factory one might use to instantiate a service (through a proxy).

package com.trinary.test.service;

import java.lang.reflect.Proxy;

import com.trinary.security.owasp.proxy.OWASPMethodValidatorProxy;

public class TestServiceFactory {
    Class<?>[] interfaces = {TestService.class};

    public TestService createESignService() throws IllegalArgumentException, InstantiationException, IllegalAccessException {
        return (TestService)Proxy.newProxyInstance(
                this.getClass().getClassLoader(), 
                interfaces,
                new OWASPMethodValidatorProxy<TestService>(TestServiceImpl.class));
    }
}

I would love it if in a servlet I might do something like this:

package com.trinary.test.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.trinary.test.service.TestService;

public class TestServlet extends HttpServlet {
    private static final long serialVersionUID = -1778574173539761350L;

    @EJB protected TestService testService;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("PATH: " + req.getPathInfo());
        // ...

        resp.setContentType("text/html");
        resp.getWriter().append("<html><h1>TESTY TEST!</h1></html>");
    }
}

In the above you can see how I might be injecting test service into my servlet. But I would like the EJB container to instantiate new instances of TestService using the factory instead of however the container usually does it. Is there a way to do this?

Upvotes: 0

Views: 822

Answers (2)

deusprogrammer
deusprogrammer

Reputation: 105

I just discovered how to solve my issue. First as a commenter pointed out, I went with CDI instead of EJB (I need to understand what the difference between the two is and if most Application servers support it).

Secondly I used the @Produces annotation on the method in my factory like so:

import java.lang.reflect.Proxy;
import javax.ejb.Stateless;
import javax.enterprise.inject.Default;
import javax.enterprise.inject.Produces;

import com.trinary.security.owasp.proxy.OWASPMethodValidatorProxy;

@Local
public class TestServiceFactory {
    Class<?>[] interfaces = {TestService.class};

    @Produces
    @Default
    public TestService createESignService() throws IllegalArgumentException, InstantiationException, IllegalAccessException {
        return (TestService)Proxy.newProxyInstance(
                this.getClass().getClassLoader(), 
                interfaces,
                new OWASPMethodValidatorProxy<TestService>(TestServiceImpl.class));
    }
}

And then in my servlet I can now do this:

import java.io.IOException;

import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.trinary.test.service.TestService;

public class TestServlet extends HttpServlet {
    private static final long serialVersionUID = -1778574173539761350L;

    @Inject TestService testService;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("PATH: " + req.getPathInfo());

        testService.method(...);

        // ...

        resp.setContentType("text/html");
        resp.getWriter().append("<html><h1>TESTY TEST!</h1></html>");
    }
}

However if you were to try to use this with the service TestService marked up as a managed bean, you would get an exception because it would be ambiguous which way you want to instantiate it unless you want to use a @Qualifer annotation. I elected not to. I just want everywhere this gets injected to use the factory to instantiate.

Upvotes: 0

Brett Kail
Brett Kail

Reputation: 33956

There's no way to directly intercept @EJB at the injection point, but you could intercept the method call on the actual bean using an EJB interceptor. If you can switch to CDI @Inject in the client, then you could use a CDI interceptor. At that point, you could use a CDI producer method to have more control over the object injected into the servlet.

Upvotes: 1

Related Questions