How To Get Resource Method Information With ResourceInfo In Jakarta REST

Jakarta EE

Oftentimes in a Jakarta REST application, you may need to access some metadata about a given resource method matched by the Jakarta REST runtime, outside of a resource class. This could be so as to dynamically alter the client’s request based on some custom business requirement, or for informative purposes. For example, in a Jakarta REST component like an exception mapper, you might want to get the currently matched resource method and get its HTTP method. 

The Jakarta REST API has the ResourceInfo interface for just such a situation. This interface is a container managed component that you can inject into other Jakarta REST components with the jakarta.ws.rs.core.Context annotation. The interface has two methods, getResourceMethod and getResourceClass that return a java.lang.reflect.Method and Class<?>, respectively. 

With the getResourceMethod, you can get metadata about the currently matched resource method. It’s important to note that the methods on the ResourceInfo object can return null if they are invoked in a situation where the Jakarta REST runtime has not yet matched a given request to a resource method.

The code snippet below shows the use of the ResourceInfo in an exception mapper to get the matched HTTP method.

@Provider
public class ValidationExceptionMapper implements ExceptionMapper<ValidationException> {
    @Context
    UriInfo uriInfo;

    @Context
    ResourceInfo resourceInfo;

    @Override
    public Response toResponse(final ValidationException exception) {
        var httpMethods = List.of(POST.class, GET.class, PUT.class, DELETE.class, PATCH.class, OPTIONS.class, HEAD.class);

        Annotation[] declaredAnnotations = resourceInfo.getResourceMethod().getDeclaredAnnotations();

        String httpMethod = Arrays.stream(declaredAnnotations)
                .filter(d -> httpMethods.contains(d.annotationType())).findFirst()
                .map(a -> a.annotationType().getSimpleName()).orElse("");

        final var jsonObject = Json.createObjectBuilder()
                .add("host", uriInfo.getAbsolutePath().getHost())
                .add("resource", uriInfo.getAbsolutePath().getPath())
                .add("resourceMethod", httpMethod)
                .add("title", "Validation Errors");

        final var jsonArray = Json.createArrayBuilder();

        JsonObjectBuilder errorObject = Json.createObjectBuilder()
                .add("message", "A validation exception occurred")
                .add("reason", exception.getLocalizedMessage());
        jsonArray.add(errorObject);
        JsonObject errorJsonEntity = jsonObject.add("errors", jsonArray.build()).build();

        return Response.status(Response.Status.BAD_REQUEST).entity(errorJsonEntity).build();
    }
}

The ConstraintViolationExceptionMapper injects both the ResourceInfo and UriInfo components with the @Context annotation. The toResponse method gets the matched resource method, then gets an array of declared annotations with the getDeclaredAnnotations method. This array is then streamed and filtered for an annotation that matches one of any in the pre-declared list of annotations in the httpMethods list. Using this construct, rather than, for instance relying on the index of the methods in the array makes our code portable across vendors. It also ensures it works the same for future releases of the specification. 

The rest of the method creates JSON objects to return meaningful messages to the client. A typical call to a resource method in the application that triggers a ConstraintViolationException will resource in a JSON message such as shown below.

{
  "host": "localhost",
  "resource": "/jee-mongo/api/employee/HR-05",
  "resourceMethod": "POST",
  "title": "Validation Errors",
  "errors": [
    {
      "message": "A validation exception occurred",
      "reason": "No department found for department code HR-05"
    }
  ]
}

Notice the resourceMethod element. This is what we got from using the ResourceInfo object. Of course there are different scenarios where you will need to know the HTTP method, as stated above. But in all cases, the ResourceInfo is your go to object for getting such information. A small caveat, with the release of Jakarta EE 10, is that the @Context annotation will be deprecated and eventually removed in favor of the more ubiquitous Jakarta CDI @Inject. This is part of the long term goal of aligning the platform and making the CDI the core “glue” that binds all the various parts together. But until then, you can use the @Context annotation to get an instance of the ResourceInfo component in your Jakarta REST artefacts. 

Found this useful?

Try some of our Jakarta EE guides:

Comments (2)

Post a comment

Your email address will not be published. Required fields are marked *

Payara needs the contact information you provide to us to contact you about our products and services. You may unsubscribe from these communications at any time. For information on how to unsubscribe, as well as our privacy practices and commitment to protecting your privacy, please review our Legal & Privacy Policy.

  1. Markus Karg

    Beware of assumptions like “HTTP method type is always first”. There is no guarantee about that, as this is undocumented behavior and might not be the case if future or on different vendor’s JREs. In production code, typically you would no use out-of-band knowledge like this, but treat instead check if a known / expected annotation type is found on the method. For example, if you like to introduce a logging level as an annotation, you would ask for the *existence* of “@DebugLevel” instead of assuming it to be there in a particular index position.

    1. Luqman Luqman

      Hi. Yes thanks for the pointer. I looked into the spec but didn’t find it explicitly stated. Like you mentioned, it might result in unexpected behaviour even on the same runtime across different versions. I’ll amend the text accordingly. Thanks.

Related Posts

Payara promotional graphic showing transition from Spring to Jakarta EE, including technology logos, a code icon and arrows leading from Spring to Jakarta EE. 6 minutes
Jakarta EE

From Spring Boot To Jakarta EE 11: How Payara Starter Eases The Transition

If you’ve been living in the Spring ecosystem, you’re used to fast project setup. Spring Initializr gives you a […]

Graphic promoting the Jakarta EE Agentic AI Project by Payara Community. The design shows a laptop screen with a central icon of a person wearing headphones and using a laptop, surrounded by sparkles. The background features blue ocean-themed elements with coral and small fish. Logos for Jakarta EE and Payara Community appear at the top. 3 minutes
Community

Announcing the Jakarta Agentic AI Project

Exploring the Future of AI with the Jakarta EE Community At Payara, we’re passionate about pushing the boundaries of […]

Image promoting a Payara blog with an illustration of a document with checkmarks and a magnifying glass. 5 minutes
Jakarta EE

Why Jakarta EE Standards Make Legacy App Modernization Simple

Legacy Java applications built on enterprise standards don’t have to be roadblocks to modernization. When applications follow established specifications […]