-
-
Save dafi/96d4dd6380c3bbc45d3494b1d95312d3 to your computer and use it in GitHub Desktop.
A JAX-RS resource that shows all bound methods in the current context (RestEasy only)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.ResourceMethod; | |
import org.jboss.resteasy.core.ResourceMethodRegistry; | |
import org.jboss.resteasy.util.WeightedMediaType; | |
import org.springframework.stereotype.Service; | |
import com.google.common.collect.Lists; | |
import com.google.common.collect.Maps; | |
import com.sonydadc.wldcs.bo.rest.security.Secure; | |
/** | |
* A resource that displays a list of available | |
* endpoints (which is helpful to see for debugging purposes). | |
* | |
* @author Patrick Stegmann | |
*/ | |
@Service | |
@Path("/") | |
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, ResourceMethod method) { | |
String produces = mostPreferredOrNull(method.getPreferredProduces()); | |
String consumes = mostPreferredOrNull(method.getPreferredConsumes()); | |
for (String verb : method.getHttpMethods()) { | |
calls.add(new MethodDescription(verb, path, produces, consumes)); | |
} | |
} | |
private static String mostPreferredOrNull(List<WeightedMediaType> preferred) { | |
if (preferred.isEmpty()) { | |
return null; | |
} | |
else { | |
return preferred.get(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) { | |
ResourceMethod aMethod = (ResourceMethod) entry.getValue().get(0); | |
String basePath = aMethod.getMethod().getDeclaringClass().getAnnotation(Path.class).value(); | |
if (!descriptions.containsKey(basePath)) { | |
descriptions.put(basePath, new ResourceDescription(basePath)); | |
} | |
for (ResourceInvoker invoker : entry.getValue()) { | |
ResourceMethod method = (ResourceMethod) invoker; | |
descriptions.get(basePath).addMethod(basePath, 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.getRoot().getBounded().entrySet()); | |
} | |
@GET | |
@Path("/") | |
@Produces(MediaType.TEXT_HTML) | |
public Response getAvailableEndpointsHtml(@Context Dispatcher dispatcher) { | |
// Yeah, yeah, HTML per StringBuilder. I can't be bovvered to make a JSP :D | |
StringBuilder sb = new StringBuilder(); | |
ResourceMethodRegistry registry = (ResourceMethodRegistry) dispatcher.getRegistry(); | |
List<ResourceDescription> descriptions = ResourceDescription.fromBoundResourceInvokers(registry.getRoot().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(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment