List all exposed/available endpoints of RestEasy service?

前端 未结 5 2157
甜味超标
甜味超标 2021-02-12 15:51

Is it possible to list all exposed/available endpoints of RestEasy service in a simple way?

5条回答
  •  逝去的感伤
    2021-02-12 16:26

    I had to adjust the "cleaner" example which was excellent to begin with. I'm using RestEasy 3.07 and wanted to also have each method's Path annotation value. I hope this modification can be of help to others.

    import java.lang.annotation.Annotation;
    import java.lang.reflect.Method;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.Context;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    
    import org.jboss.resteasy.core.Dispatcher;
    import org.jboss.resteasy.core.ResourceInvoker;
    import org.jboss.resteasy.core.ResourceMethodInvoker;
    import org.jboss.resteasy.core.ResourceMethodRegistry;
    import org.springframework.stereotype.Component;
    
    import com.google.common.collect.Lists;
    import com.google.common.collect.Maps;
    
    @Component
    @Path("/overview")
    public class OverviewResource
    {
    private static final class MethodDescription
    {
        private String method;
        private String fullPath;
        private String produces;
        private String consumes;
    
        public MethodDescription(String method, String fullPath, String produces, String consumes)
        {
            super();
            this.method = method;
            this.fullPath = fullPath;
            this.produces = produces;
            this.consumes = consumes;
        }
    
    }
    
    private static final class ResourceDescription
    {
        private String basePath;
        private List calls;
    
        public ResourceDescription(String basePath)
        {
            this.basePath = basePath;
            this.calls = Lists.newArrayList();
        }
    
        public void addMethod(String path, ResourceMethodInvoker method)
        {
            String produces = mostPreferredOrNull(method.getProduces());
            String consumes = mostPreferredOrNull(method.getConsumes());
    
            for (String verb : method.getHttpMethods())
            {
                calls.add(new MethodDescription(verb, path, produces, consumes));
            }
        }
    
        private static String mostPreferredOrNull(MediaType[] mediaTypes)
        {
            if (mediaTypes == null || mediaTypes.length < 1)
            {
                return null;
            }
            else
            {
                return mediaTypes[0].toString();
            }
        }
    
        public static List fromBoundResourceInvokers(
                Set>> bound)
        {
            Map descriptions = Maps.newHashMap();
    
            for (Map.Entry> entry : bound)
            {
                Method aMethod = ((ResourceMethodInvoker) entry.getValue().get(0)).getMethod();
                String basePath = aMethod.getDeclaringClass().getAnnotation(Path.class).value();
    
                if (!descriptions.containsKey(basePath))
                {
                    descriptions.put(basePath, new ResourceDescription(basePath));
                }
    
                for (ResourceInvoker invoker : entry.getValue())
                {
                    ResourceMethodInvoker method = (ResourceMethodInvoker) invoker;
    
                    String subPath = null;
                    for(Annotation annotation : method.getMethodAnnotations())
                    {
                        if(annotation.annotationType().equals(Path.class))
                        {
                            subPath = ((Path) annotation).value();
                            break;
                        }
                    }
    
                    descriptions.get(basePath).addMethod(basePath + subPath, method);
                }
            }
    
            return Lists.newLinkedList(descriptions.values());
        }
    }
    
    @GET
    @Path("/")
    @Produces(MediaType.APPLICATION_JSON)
    public List getAvailableEndpoints(@Context Dispatcher dispatcher)
    {
        ResourceMethodRegistry registry = (ResourceMethodRegistry) dispatcher.getRegistry();
        return ResourceDescription.fromBoundResourceInvokers(registry.getBounded().entrySet());
    }
    
    @GET
    @Path("/")
    @Produces(MediaType.TEXT_HTML)
    public Response getAvailableEndpointsHtml(@Context Dispatcher dispatcher)
    {
    
        StringBuilder sb = new StringBuilder();
        ResourceMethodRegistry registry = (ResourceMethodRegistry) dispatcher.getRegistry();
        List descriptions = ResourceDescription.fromBoundResourceInvokers(registry.getBounded()
                .entrySet());
    
        sb.append("

    ").append("REST interface overview").append("

    "); for (ResourceDescription resource : descriptions) { sb.append("

    ").append(resource.basePath).append("

    "); sb.append("
      "); for (MethodDescription method : resource.calls) { sb.append("
    • ").append(method.method).append(" "); sb.append("").append(method.fullPath).append(""); sb.append("
        "); if (method.consumes != null) { sb.append("
      • ").append("Consumes: ").append(method.consumes).append("
      • "); } if (method.produces != null) { sb.append("
      • ").append("Produces: ").append(method.produces).append("
      • "); } sb.append("
      "); } sb.append("
    "); } return Response.ok(sb.toString()).build(); } }

    (On another note, perhaps there is something available, or I can begin work on, to model the resource listing and description that ServiceStack does so nicely: http://mono.servicestack.net/Content/Images/MetadataIndex.png)

提交回复
热议问题