【问题标题】:List all exposed/available endpoints of RestEasy service?列出 RestEasy 服务的所有公开/可用端点?
【发布时间】:2013-11-16 16:55:02
【问题描述】:

是否可以以简单的方式列出 RestEasy 服务的所有公开/可用端点?

【问题讨论】:

    标签: jboss resteasy


    【解决方案1】:

    编辑:

    有关“更清洁”的示例,请参阅此要点: https://gist.github.com/wonderb0lt/10731371


    是的,这是可能的。也许你想知道怎么做? :)

    这里有一个“快速-n-脏”的例子:

    import org.jboss.resteasy.annotations.providers.jaxb.Formatted;
    import org.jboss.resteasy.annotations.providers.jaxb.Wrapped;
    import org.jboss.resteasy.core.Dispatcher;
    import org.jboss.resteasy.core.ResourceInvoker;
    import org.jboss.resteasy.core.ResourceMethod;
    import org.jboss.resteasy.core.ResourceMethodRegistry;
    import org.jboss.resteasy.mock.MockDispatcherFactory;
    import org.jboss.resteasy.mock.MockHttpRequest;
    import org.jboss.resteasy.mock.MockHttpResponse;
    import org.junit.Test;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.POST;
    import javax.ws.rs.Path;
    import javax.ws.rs.core.Context;
    import javax.ws.rs.core.MediaType;
    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.bind.annotation.XmlValue;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    public class PrintAllResourcesTest {
    
        @Test
        public void name_StateUnderTest_ExpectedBehavior() throws Exception {
            Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
    
            dispatcher.getRegistry().addSingletonResource(new MetaService());
            dispatcher.getRegistry().addSingletonResource(new Service());
    
            MockHttpResponse response = new MockHttpResponse();
            MockHttpRequest request = MockHttpRequest.get("/meta")
                    .accept(MediaType.APPLICATION_XML);
    
    
            dispatcher.invoke(request, response);
    
             /*<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
             <resources>
                <resource method="GET">/service/</resource>
                <resource method="POST">/service/</resource>
             </resources>*/
            String result = response.getContentAsString();
        }
    
        @XmlRootElement(name = "resource")
        public static final class JaxRsResource {
            @XmlAttribute String method;
            @XmlValue String uri;
    
            public JaxRsResource() {}
    
            public JaxRsResource(String method, String uri) {
                this.method = method;
                this.uri = uri;
            }
    
            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (o == null || getClass() != o.getClass()) return false;
    
                JaxRsResource that = (JaxRsResource) o;
    
                if (method != null ? !method.equals(that.method) : that.method != null) return false;
                if (uri != null ? !uri.equals(that.uri) : that.uri != null) return false;
    
                return true;
            }
    
            @Override
            public int hashCode() {
                int result = method != null ? method.hashCode() : 0;
                result = 31 * result + (uri != null ? uri.hashCode() : 0);
                return result;
            }
        }
    
        @Path("/service")
        public static final class Service {
    
            @GET
            @Path("/")
            public String getStuff(){
                return "";
            }
    
    
            @POST
            @Path("/")
            public String postStuff(){
                return "";
            }
        }
    
    
        @Path("/meta")
        public static final class MetaService {
            @Context Dispatcher dispatcher;
    
            @GET
            @Path("/")
            @Wrapped(element = "resources")
            @Formatted
            public Set<JaxRsResource> getAllResources(){
                Set<JaxRsResource> resources = new HashSet<JaxRsResource>();
    
                ResourceMethodRegistry registry = (ResourceMethodRegistry) dispatcher.getRegistry();
    
                for (Map.Entry<String, List<ResourceInvoker>> entry : registry.getRoot().getBounded().entrySet()) {
                    for (ResourceInvoker invoker : entry.getValue()) {
                        ResourceMethod method = (ResourceMethod) invoker;
    
                        if(method.getMethod().getDeclaringClass() == getClass()){
                            continue;
                        }
    
                        for (String verb : method.getHttpMethods()) {
                            String uri = entry.getKey();
                            resources.add(new JaxRsResource(verb, uri));
                        }
                    }
                }
    
                return resources;
            }
    
        }
    }
    

    【讨论】:

    • 谢谢...找不到东西...帮了我很多忙。
    • 嗨,很抱歉发布这么旧的答案!我发现您的回答很有帮助,并根据您的代码发布了一个不那么“quick-n-dirty”的方法,并希望与全世界分享:gist.github.com/wonderb0lt/10731371
    【解决方案2】:

    我不得不调整“更干净”的示例,这在开始时非常出色。我正在使用 RestEasy 3.07 并且还希望拥有每个方法的 Path 注释值。我希望这个修改可以对其他人有所帮助。

    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<MethodDescription> 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<ResourceDescription> fromBoundResourceInvokers(
                Set<Map.Entry<String, List<ResourceInvoker>>> bound)
        {
            Map<String, ResourceDescription> descriptions = Maps.newHashMap();
    
            for (Map.Entry<String, List<ResourceInvoker>> 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<ResourceDescription> 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<ResourceDescription> descriptions = ResourceDescription.fromBoundResourceInvokers(registry.getBounded()
                .entrySet());
    
        sb.append("<h1>").append("REST interface overview").append("</h1>");
    
        for (ResourceDescription resource : descriptions)
        {
            sb.append("<h2>").append(resource.basePath).append("</h2>");
            sb.append("<ul>");
    
            for (MethodDescription method : resource.calls)
            {
                sb.append("<li> ").append(method.method).append(" ");
                sb.append("<strong>").append(method.fullPath).append("</strong>");
    
                sb.append("<ul>");
    
                if (method.consumes != null)
                {
                    sb.append("<li>").append("Consumes: ").append(method.consumes).append("</li>");
                }
    
                if (method.produces != null)
                {
                    sb.append("<li>").append("Produces: ").append(method.produces).append("</li>");
                }
    
                sb.append("</ul>");
            }
    
            sb.append("</ul>");
        }
    
        return Response.ok(sb.toString()).build();
    
    }
    
    }
    

    (另一方面,也许有一些可用的东西,或者我可以开始工作,为 ServiceStack 做得很好的资源列表和描述建模:http://mono.servicestack.net/Content/Images/MetadataIndex.png

    【讨论】:

      【解决方案3】:

      如果有人还在寻找 在您的应用上点击“/resteasy/registry”

      提供所有已注册端点、关联类/方法等的 XML 输出

      仅供参考,resteasy-jaxb-provider 提供此功能

      【讨论】:

        【解决方案4】:

        有一个 RestEasy 插件“stats”,它暴露了.../resteasy/registry

        需要在web.xml注册:

        <context-param>
            <param-name>resteasy.resources</param-name>
            <param-value>org.jboss.resteasy.plugins.stats.RegistryStatsResource</param-value>
        </context-param>
        

        示例响应:

        <registry>
            <resource uriTemplate="/resource">
                <delete class="org.jboss.resteasy.test.providers.jaxb.resource.StatsResource" method="delete"
                        invocations="0"/>
                <head class="org.jboss.resteasy.test.providers.jaxb.resource.StatsResource" method="head" invocations="0"/>
            </resource>
            <resource uriTemplate="/locator">
                <locator class="org.jboss.resteasy.test.providers.jaxb.resource.StatsResource" method="getLocator"/>
            </resource>
            <resource uriTemplate="/resteasy/registry">
                <get class="org.jboss.resteasy.plugins.stats.RegistryStatsResource" method="get" invocations="2">
                    <produces>application/xml</produces>
                    <produces>application/json</produces>
                </get>
            </resource>
            <resource uriTemplate="/entry/{foo:.*}">
                <post class="org.jboss.resteasy.test.providers.jaxb.resource.StatsResource" method="post" invocations="0">
                    <produces>text/xml</produces>
                    <consumes>application/json</consumes>
                </post>
                <put class="org.jboss.resteasy.test.providers.jaxb.resource.StatsResource" method="put" invocations="0">
                    <produces>text/xml</produces>
                    <consumes>application/json</consumes>
                </put>
            </resource>
        </registry>
        

        Maven 依赖:

        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-jaxb-provider</artifactId>
            <version>3.0.8.Final</version>
        </dependency>
        

        参见例如。 EAP docsthis EAP 7 Jira

        【讨论】:

        【解决方案5】:

        即使是老帖子,我也在这里给出答案。

        这是 JBoss 附带的 RestEasy 的实现。您可以使用它,也可以自己编写。 该实现返回一个具有数组属性的对象,您可以在其中找到每个 RestEasy 资源的 uriTemplate 字符串。

        您需要遍历所有条目并获取所需的信息:

        RegistryData.entries.get(index).uriTemplate

        org.jboss.resteasy.plugins.stats.RegistryStatsResource.get方法的实现:

        public RegistryData get() throws JAXBException {
            ResourceMethodRegistry registry = (ResourceMethodRegistry)ResteasyProviderFactory.getContextData(Registry.class);
            RegistryData data = new RegistryData();
            Iterator i$ = registry.getRoot().getBounded().keySet().iterator();
        
            label85:
            while(i$.hasNext()) {
                String key = (String)i$.next();
                List<ResourceInvoker> invokers = (List)registry.getRoot().getBounded().get(key);
                RegistryEntry entry = new RegistryEntry();
                data.getEntries().add(entry);
                entry.setUriTemplate(key);
                Iterator i$ = invokers.iterator();
        
                while(true) {
                    while(true) {
                        if (!i$.hasNext()) {
                            continue label85;
                        }
        
                        ResourceInvoker invoker = (ResourceInvoker)i$.next();
                        if (invoker instanceof ResourceMethod) {
                            ResourceMethod rm = (ResourceMethod)invoker;
        
                            Object method;
                            for(Iterator i$ = rm.getHttpMethods().iterator(); i$.hasNext(); entry.getMethods().add(method)) {
                                String httpMethod = (String)i$.next();
                                method = null;
                                if (httpMethod.equals("GET")) {
                                    method = new GetResourceMethod();
                                } else if (httpMethod.equals("PUT")) {
                                    method = new PutResourceMethod();
                                } else if (httpMethod.equals("DELETE")) {
                                    method = new DeleteResourceMethod();
                                } else if (httpMethod.equals("POST")) {
                                    method = new PostResourceMethod();
                                } else if (httpMethod.equals("OPTIONS")) {
                                    method = new OptionsResourceMethod();
                                } else if (httpMethod.equals("TRACE")) {
                                    method = new TraceResourceMethod();
                                } else if (httpMethod.equals("HEAD")) {
                                    method = new HeadResourceMethod();
                                }
        
                                ((ResourceMethodEntry)method).setClazz(rm.getResourceClass().getName());
                                ((ResourceMethodEntry)method).setMethod(rm.getMethod().getName());
                                AtomicLong stat = (AtomicLong)rm.getStats().get(httpMethod);
                                if (stat != null) {
                                    ((ResourceMethodEntry)method).setInvocations(stat.longValue());
                                } else {
                                    ((ResourceMethodEntry)method).setInvocations(0L);
                                }
        
                                MediaType[] arr$;
                                int len$;
                                int i$;
                                MediaType mediaType;
                                if (rm.getProduces() != null) {
                                    arr$ = rm.getProduces();
                                    len$ = arr$.length;
        
                                    for(i$ = 0; i$ < len$; ++i$) {
                                        mediaType = arr$[i$];
                                        ((ResourceMethodEntry)method).getProduces().add(mediaType.toString());
                                    }
                                }
        
                                if (rm.getConsumes() != null) {
                                    arr$ = rm.getConsumes();
                                    len$ = arr$.length;
        
                                    for(i$ = 0; i$ < len$; ++i$) {
                                        mediaType = arr$[i$];
                                        ((ResourceMethodEntry)method).getConsumes().add(mediaType.toString());
                                    }
                                }
                            }
                        } else {
                            ResourceLocator rl = (ResourceLocator)invoker;
                            SubresourceLocator locator = new SubresourceLocator();
                            locator.setClazz(rl.getMethod().getDeclaringClass().getName());
                            locator.setMethod(rl.getMethod().getName());
                            entry.setLocator(locator);
                        }
                    }
                }
            }
        
            return data;
        }
        

        另请参阅:WildFly management - list/detect REST endpoints deployed in WildFly

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-03-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多