14

I've been searching everywhere, but can't seem to find a clear answer...

What is the mechanism whereby a server (glassfish for my problem) injects actual objets that are annotated with @Context? More specifically, if I wanted to write a class that did something like:

@Path("/")
public class MyResource {
  @GET
  public String doSomething(@Context MyObject obj) {
    // ...
  }
}

then how would I do it? Where is it that the MyObject is instanciated, who does it, and how?

Edit: I've seen stuff like the following:

Using @Context, @Provider and ContextResolver in JAX-RS

http://jersey.576304.n2.nabble.com/ContextResolver-confusion-td5654154.html

However, this doesn't square with what I've seen, e.g. in the constructor of org.neo4j.server.rest.web.RestfulGraphDatabase, which has the following signature:

public RestfulGraphDatabase(
  @Context UriInfo uriInfo,
  @Context Database database,
  @Context InputFormat input,
  @Context OutputFormat output,
  @Context LeaseManager leaseManager )
Community
  • 1
  • 1
Kricket
  • 4,049
  • 8
  • 33
  • 46

4 Answers4

8

You can write your own injection provider and plug that into Jersey - look at SingletonTypeInjectableProvider and PerRequestTypeInjectableProvider - extend one of these classes (depending on the lifecycle you want for the injectable object) and register your implementation as a provider in your web app.

For example, something like this:

@Provider
public class MyObjectProvider extends SingletonTypeInjectableProvider<Context, MyObject> {
    public MyObjectProvider() {
        // binds MyObject.class to a single MyObject instance
        // i.e. the instance of MyObject created bellow will be injected if you use
        // @Context MyObject myObject
        super(MyObject.class, new MyObject());
    }
}

To include the provider in your web app you have several options:

  1. if your app uses classpath scanning (or package scanning) just make sure the provider is in the right package / on the classpath
  2. or you can simply register it using META-INF/services entry (add META-INF/services/com.sun.jersey.spi.inject.InjectableProvider file having the name of your provider class in it's contents)
Martin Matula
  • 7,969
  • 1
  • 31
  • 35
  • If you're subclassing javax.ws.rs.core.Application, you can register the provider with `this.getSingletons().add(new MyObjectProvider());` in your Application's constructor. – justin May 07 '15 at 17:21
  • The links are broken. – David Berg Sep 30 '15 at 13:55
  • Try these: https://jersey.java.net/nonav/apidocs/1.19/jersey/com/sun/jersey/spi/inject/SingletonTypeInjectableProvider.html https://jersey.java.net/nonav/apidocs/1.19/jersey/com/sun/jersey/spi/inject/PerRequestTypeInjectableProvider.html – elanh Sep 30 '15 at 14:13
  • 1
    The classes were removed from version 2.0+ – elanh Sep 30 '15 at 14:15
3

I think I may be on to something...and if this works, Martin should get partial credit. :)

It appears that the @Provider class must implement the com.sun.jersey.spi.inject.Injectable<T> interface. However, I'm not sure that this is enough to actually have the @Context be injected. What's missing, is that we have to tell the ResourceConfig object of the web app about the @Provider. In the context of what I'm trying to do, and taking hints from neo4j-server, the remaining work boils down to:

  • extending com.sun.jersey.spi.container.servlet.ServletContainer, and overriding the configure method:
@Override
protected void configure(WebConfig wc, ResourceConfig rc, WebApplication wa)
{
  super.configure( wc, rc, wa );
  Set<Object> singletons = rc.getSingletons();
  singletons.add(new MyObjectProvider());
}
  • specifying that this container must be used in the web.xml deployment descriptor:
<servlet>
  <servlet-name>JAX-RS Servlet Container</servlet-name>
  <servlet-class>com.blah.MyServletContainer</servlet-class>
</servlet>
Kricket
  • 4,049
  • 8
  • 33
  • 46
0

I don't think you can use @Context with a user-defined type like MyObject. It is for injecting types that jax-ws already understands. It is mentioned here.

Chapter 5 of the JAX-RS specification presents all the standard JAX-RS Java types that may be used with @Context.

You probably want to use something like @FormParam or @PathParam instead. See section 2.3 of the spec for a description. Here is your answer, copied from that section of the spec:

In general the Java type of the method parameter may:

  1. Be a primitive type;
  2. Have a constructor that accepts a single String argument;
  3. Have a static method named valueOf or fromString that accepts a single String argument (see, for example, Integer.valueOf(String) and java.util.UUID.fromString(String)); or
  4. Be List, Set or SortedSet, where T satisfies 2 or 3 above. The resulting collection is read-only.
Community
  • 1
  • 1
John Watts
  • 8,717
  • 1
  • 31
  • 35
  • Correct. You can only inject the 12 allowable object instances as listed here: https://readlearncode.com/java-ee/what-is-javax-ws-rs-core-context-httpheaders-and-uriinfo/ – Alex Theedom Aug 21 '17 at 10:24
-1

See chapters 5-6 of the JAX-RS spec. That should tell you everything you need to know about it.

Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199