9

Does Jersey provide any way to list all of the resources it exposes? That is, given the resource class:

package com.zoo.resource

@Path("/animals")
public class AnimalResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("dog")
    public Dog getDog(){
    ...
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("cat")
    public Cat getCat(){
    ...
    }
}

Does Jersey provide any way for me to get the information:

  • GET at the path /animals/dog returns type Dog
  • GET at the path /animals/cat returns type Cat

(And furthermore, does it provide a way for me to know that AnimalResource is a resource?)

I would like to have this information available to me in a unit test so that I can check that every resource I expose conforms to what an external system expects. I know that there is automagic that exposes the application.wadl, but I don't see that showing me return types and I don't know how to access it from within my tests.

PotataChipz
  • 505
  • 5
  • 11

1 Answers1

9

[update - example is the same but I have reworded my caveats]

It can be done. Try the following:

import com.sun.jersey.api.model.AbstractResource;
import com.sun.jersey.api.model.AbstractSubResourceMethod;
import com.sun.jersey.server.impl.modelapi.annotation.IntrospectionModeller;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

public class AnimalsTest
{
   public static void main(String [] args)
   {
      AbstractResource resource = IntrospectionModeller.createResource(AnimalResource.class);
      System.out.println("Path is " + resource.getPath().getValue());

      String uriPrefix = resource.getPath().getValue();
      for (AbstractSubResourceMethod srm :resource.getSubResourceMethods())
      {
         String uri = uriPrefix + "/" + srm.getPath().getValue();
         System.out.println(srm.getHttpMethod() + " at the path " + uri + " return " + srm.getReturnType().getName());
      }
   }
}

class Dog {}

class Cat {}

@Path("/animals")
class AnimalResource {
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("dog")
    public Dog getDog(){
      return null;
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("cat")
    public Cat getCat(){
       return null;
    }
}

These introspection classes are in jersey-server.

Note that the example above uses some Jersey classes that have "impl" in the package name which suggests that these Jersey classes are not intended for public consumption and may very well have breaking changes in the future. I am just speculating here - I am not a Jersey committer. Just a random user.

Also everything above I figured out by perusing the source code. I have never seen any documentation of an approved way to introspect JAX-RS annotated classes. I agree that an officially supported API to do this kind of thing would be very helpful.

Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
Guido Simone
  • 7,912
  • 2
  • 19
  • 21
  • My zoo resource is just a simplified example, if that's what you meant by "it's pretty obvious that the classes of interest are not intended for public consumption." If you're questioning the need for this in general, I'm sending and receiving JSON objects with another app, and we're attempting to enforce that we agree on the data model. They tell me that at /animals/cat they expect some json format, and I confirm that it matches the POJO returned by the resource with that path. – PotataChipz Nov 21 '12 at 16:34
  • So is there any way to discover all of my resource classes, or do I have to maintain a list of them? – PotataChipz Nov 21 '12 at 16:44
  • 2
    No no no - I was not picking on your zoo. I was trying to warn about the dangers of using internal implementation classes. Sorry for the confusion. Hope my updated answer clears that up. – Guido Simone Nov 21 '12 at 18:24
  • Regarding resource discovery - since Jersey discovers all your annotated classes in the server, it's definitely do-able and is somewhere in the source code. I have not dug into it (yet) because in my project I already maintain a list of the classes of interest and don't really need that capability. – Guido Simone Nov 21 '12 at 18:26
  • Yes that clears things up; I hadn't paid attention to the package names in _your_ example and got confused. Thanks for the help! – PotataChipz Nov 21 '12 at 18:36
  • 5
    Any idea how to do this without the IntrospectionModeller, now that it is no longer a public class? – directedition Aug 21 '14 at 19:21