Search code examples
javajbossjax-rsresteasy

JaxRS + RestEasy - How do you create your own @Context injected field?


Question about RestEASY 3.6.2 on JBoss 7.1.0.

I have the following working JaxRS service:

@Path("my-service")
public class MyResource {
  @Context
  HttpServletRequest request;

  @GET
  @Path("get-stuff")
  @Produces(MediaType.APPLICATION_JSON)
  public Response doStuff() {
    MyCustomContext customContext = new MyCustomContext(request);
    // ... use the customContext here.
  }
}

With the way this is currently set up, every rest method requires a MyCustomContext customContext = new MyCustomContext(request);. That is annoying.

Is there some way to inject the MyCustomContext?

@Path("my-service")
public class MyResource {
  @Context
  MyCustomContext context;

  @GET
  @Path("get-stuff")
  @Produces(MediaType.APPLICATION_JSON)
  public Response doStuff() {
    // ... use the customContext here.
  }
}

@Producer // ???
public class MyCustomContext {
  @Context
  HttpServletRequest request;

  public MyCustomContext() {
    // construct with request object.
  }
}

I have found a ton of links hinted towards a way to do this, but I am coming up empty.


Solution

  • I do not know any way of injecting a custom class instance/bean with @Context. I would like to outline alternative approaches that depend on the concrete requirement.

    A) No injection needed at all.

    Make your custom context a class member of your JAX-RS resource class (instead of local variable within each method). Utilize @PostConstruct to instantiate your custom context once the container has created an initialized your resource class instance. The resource class must be a CDI-bean with request scope for this to work.

    @Path("my-service")
    @RequestScoped // CDI-bean with request scope only
    public class MyResource {
    
      @Context
      private HttpServletRequest request;
    
      private MyCustomContext customContext;
    
      @PostConstruct
      public void initialize() {
        this.customContext = new MyCustomContext(this.request); // request is initialized by the container already at this point
      }
    
      @GET
      @Path("get-stuff")
      @Produces(MediaType.APPLICATION_JSON)
      public Response doStuff() {
        // ... use the customContext here.
      }
    }
    

    B) Your custom context requires an HttpServletRequest instance only

    Beside JAX-RS via @Context, CDI also provides a predefined bean for HttpServletRequest via @Inject. You can make your custom context a CDI-bean also and inject that predefined CDI-bean. Afterwards you are able to inject your custom context into your JAX-RS resource (regardless of whether it is an EJB or CDI-bean).

    @Dependent // make your custom context a CDI-bean
    public class MyCustomContext {
    
      @Inject // inject predefined CDI-bean
      private HttpServletRequest request;
    }
    
    @Path("my-service")
    @RequestScoped // either CDI-bean
    //@Stateless // or EJB
    public class MyResource {
    
      @Inject // inject custom context via CDI
      private MyCustomContext customContext;
    
      @GET
      @Path("get-stuff")
      @Produces(MediaType.APPLICATION_JSON)
      public Response doStuff() {
        // ... use the customContext here.
      }
    }
    

    C) Your custom context requires an instance exclusiveley provided via provider specific @Context e.g. Request

    If you inject an instance via @Context into your non JAX-RS custom context CDI-bean it will be null. You need some mechanism to provide the injected instance from your JAX-RS resource. Making CDI responsible for the injection via @Inject on your custom context and adding a producer method via @Produces to your JAX-RS resource will do the job.

    @Dependent // make your custom context a CDI-bean
    public class MyCustomContext {
    
      //@Context // in non JAX-RS context the instance will be null
      @Inject // instead inject the JAX-RS context instance via CDI
      private Request request;
    }
    
    @Path("my-service")
    @RequestScoped // either CDI-bean
    //@Stateless // or EJB
    public class MyResource {
    
      @Context // in JAX-RS context the instance will not be null
      private Request request;
      @Inject
      private MyCustomContext customContext;
    
      @Produces // provide the JAX-RS context instance for injection via CDI
      @RequestScoped
      public Request getContextRequest() {
        return this.request;
      }
    
      @GET
      @Path("get-stuff")
      @Produces(MediaType.APPLICATION_JSON)
      public Response doStuff() {
        // ... use the customContext here.
      }
    }