1

I have a class

@Path("/foo")
public class Foo {

    public Foo() {
    }

    public Foo(int n) {
    }

    @GET
    @Produces(MediaType.TEXT_HTML)
    @Path("/isAlive")
    public String isAlive() {
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/getConfigFromDB")
    public Response getConfigFromDB(Request) {
    }

Suppose that this is the first call to this web app and the the class has to be constructed for the first time. Can I configure Jersey to choose the second constructor if the path is "http://localhost/foo/isAlive" and the first constructor if the request path is "http://localhost/foo/getConfigFromDB"?

Ori Popowski
  • 10,432
  • 15
  • 57
  • 79

2 Answers2

2

You can manage Resource instantiation yourself overriding Application#getSingletons:

@ApplicationPath("/r")
public class RestApplication extends Application {

    @Override
    public Set<Object> getSingletons() {
        Foo foo = new Foo();
        Bar bar = new Bar(42);
        return new HashSet<Object>(Arrays.asList(foo, bar));
    }

}

But therefore you'll need two classes, each one with the full path:

@Path("/foo/isAlive")
public class Foo {

    public Foo() {}

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public Response isAlive() {
        return Response.ok("foo is alive").build();
    }

}

@Path("/foo/getConfigFromDB")
public class Foo2 {

    private int n;

    public Foo2(int n) {
        this.n = n;
    }

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public Response isAlive() {
        return Response.ok("bar initialized with " + n).build();
    }

}

You could also use a Subresource:

@Path("/foo")
public class Foo {

    public Foo() {}

    @GET
    @Path("/isAlive")
    @Produces(MediaType.TEXT_PLAIN)
    public Response isAlive() {
        return Response.ok("foo is alive").build();
    }

    @Path("/getConfigFromDB")
    @Produces(MediaType.TEXT_PLAIN)
    public Bar getConfigFromDB() {
        return new Bar(4711);
    }

}

public class Bar {

    private int n;

    public Bar(int n) {
        this.n = n;
    }

    @GET
    public Response get() {
        return Response.ok("Bar initialized with " + n).build();
    }

}

But if your problem is about getting authentification-information in the second method as you wrote in a comment I would not use the constructor anyway. See this answer for some other examples.

Community
  • 1
  • 1
lefloh
  • 10,653
  • 3
  • 28
  • 50
1

AFAIK, the Resource instanciation is a responsability of the JAX-RS implementation, and a resource class must have an empty constructor or a constructor with parameters annotated with @Context, @Header, @PathParam, @CookieParam, @MatrixParam, @QueryParam or @PathParam. Also, a new instance of your Resource class will be created for each incoming request.

If your application is deployed on a JavaEE container or includes Spring, you can use the @inject annotation to get access to other services of your application, if that can help you.

Xavier Coulon
  • 1,580
  • 10
  • 15
  • If I integrate Jersey with Spring and let Spring manage class creation, will I be able to achieve the behavior I want? – Ori Popowski Jun 02 '14 at 09:17
  • 1
    I'm not sure about that. May I ask why you need such a second constructor ? As a workaround, can you retrieve that `n` value (passed in the secod constructor) from a service bean injected in the resource with `@Inject` ? – Xavier Coulon Jun 02 '14 at 14:07
  • I don't really need another constructor. It's just an attempt to solve my problem. The problem is that our frontends all inherit an `isAlive()` method, that only returns a `text/html` with a string like `"service is OK"`. The problem is that there is logic inside the constructor that involves remoting and authentication, and in the particular case of the alive check, this messes things up. So I was looking for an elegant solution. What I had in mind was to invoke a different constructor only when the request URI is `.../isAlive` – Ori Popowski Jun 02 '14 at 15:02
  • What about using a ContainerRequestFilter ? Maybe you could check the requested URI in `filter(ContainerRequestContext requestContext)` and call the `ContainerRequestContext#abortWith(Response)` method to avoid calling hitting the resource. You may need to annotated this ContainerRequestFilter `@PreMatching` so that it will be executed upon receiving a client request but before a resource method is matched. (I'm not sure when the resource constructor is actually called) – Xavier Coulon Jun 02 '14 at 15:11