Статьи

Джерси: список всех ресурсов, путей, глаголов для создания точки входа / индекса для API

 Последние пару дней я играл с  Джерси, и я хотел создать одну точку входа или индекс, в котором перечислены все мои ресурсы, доступные пути и глаголы, которые они приняли.

Гвидо Симоне  объяснил  изящный способ поиска путей и глаголов для конкретного ресурса,  используя Джерси IntrospectionModeller :

AbstractResource resource = IntrospectionModeller.createResource(JacksonResource.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());
}

Если мы запустим , что против  Д4-минимального «s  JacksonResource  класса мы получаем следующий результат:

Path is /jackson
GET at the path /jackson/{who} return com.g414.j4.minimal.JacksonResource$Greeting
GET at the path /jackson/awesome/{who} return javax.ws.rs.core.Response

Это довольно здорово, но я не хотел вручную перечислять все свои ресурсы, так как я уже сделал это с помощью Guice.

Мне нужен был способ получить их программно, и я частично нашел способ сделать это из  этого поста, который предлагает использовать  Application.getSingletons () .

Я на самом деле в конечном итоге с помощью  Application.getClasses ()  и я в конечном итоге с  ResourceListingResource :

@Path("/")
public class ResourceListingResource
{
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response showAll( @Context Application application,
                             @Context HttpServletRequest request)
    {
        String basePath = request.getRequestURL().toString();
 
        ObjectNode root = JsonNodeFactory.instance.objectNode();
        ArrayNode resources = JsonNodeFactory.instance.arrayNode();
 
        root.put( "resources", resources );
 
        for ( Class<?> aClass : application.getClasses() )
        {
            if ( isAnnotatedResourceClass( aClass ) )
            {
                AbstractResource resource = IntrospectionModeller.createResource( aClass );
                ObjectNode resourceNode = JsonNodeFactory.instance.objectNode();
                String uriPrefix = resource.getPath().getValue();
 
                for ( AbstractSubResourceMethod srm : resource.getSubResourceMethods() )
                {
                    String uri = uriPrefix + "/" + srm.getPath().getValue();
                    addTo( resourceNode, uri, srm, joinUri(basePath, uri) );
                }
 
                for ( AbstractResourceMethod srm : resource.getResourceMethods() )
                {
                    addTo( resourceNode, uriPrefix, srm, joinUri( basePath, uriPrefix ) );
                }
 
                resources.add( resourceNode );
            }
 
        }
 
 
        return Response.ok().entity( root ).build();
    }
 
    private void addTo( ObjectNode resourceNode, String uriPrefix, AbstractResourceMethod srm, String path )
    {
        if ( resourceNode.get( uriPrefix ) == null )
        {
            ObjectNode inner = JsonNodeFactory.instance.objectNode();
            inner.put("path", path);
            inner.put("verbs", JsonNodeFactory.instance.arrayNode());
            resourceNode.put( uriPrefix, inner );
        }
 
        ((ArrayNode) resourceNode.get( uriPrefix ).get("verbs")).add( srm.getHttpMethod() );
    }
 
 
    private boolean isAnnotatedResourceClass( Class rc )
    {
        if ( rc.isAnnotationPresent( Path.class ) )
        {
            return true;
        }
 
        for ( Class i : rc.getInterfaces() )
        {
            if ( i.isAnnotationPresent( Path.class ) )
            {
                return true;
            }
        }
 
        return false;
    }
 
}

Единственное изменение, которое я сделал из решения Гвидо Симона, это то, что я также вызываю  resource.getResourceMethods (), потому что  resource.getSubResourceMethods ()  возвращает только те методы, которые имеют   аннотацию @Path .

Поскольку мы иногда определяем наш путь на уровне класса, а затем определяем различные глаголы, которые оперируют с этим ресурсом, он пропускает некоторые методы.

Если мы запустим команду cURL ( пропущенную через python, чтобы она выглядела хорошо ) против корня, мы получим следующий вывод:

$ curl http://localhost:8080/ -w "\n" 2>/dev/null | python -mjson.tool
 
{
    "resources": [
        {
            "/bench": {
                "path": "http://localhost:8080/bench",
                "verbs": [
                    "GET",
                    "POST",
                    "PUT",
                    "DELETE"
                ]
            }
        },
        {
            "/sample/{who}": {
                "path": "http://localhost:8080/sample/{who}",
                "verbs": [
                    "GET"
                ]
            }
        },
        {
            "/jackson/awesome/{who}": {
                "path": "http://localhost:8080/jackson/awesome/{who}",
                "verbs": [
                    "GET"
                ]
            },
            "/jackson/{who}": {
                "path": "http://localhost:8080/jackson/{who}",
                "verbs": [
                    "GET"
                ]
            }
        },
        {
            "/": {
                "path": "http://localhost:8080/",
                "verbs": [
                    "GET"
                ]
            }
        }
    ]
}