Skip to content

Commit

Permalink
feat: RequestScope bean implementing JAX-RS ResourceInfo (#348)
Browse files Browse the repository at this point in the history
  • Loading branch information
timyates authored Sep 8, 2023
1 parent 2ed03a8 commit fa2afed
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 0 deletions.
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ groovy = "4.0.13"
spock = "2.3-groovy-4.0"
managed-jaxrs-api = "3.1.0"

micronaut-logging = "1.1.0"
micronaut-security = "4.1.0"
micronaut-serde = "2.2.4"
micronaut-validation = "4.0.2"
Expand Down
1 change: 1 addition & 0 deletions jaxrs-server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ dependencies {
testImplementation(mn.micronaut.http.client)
testImplementation(mnValidation.micronaut.validation)
testImplementation(mnTest.micronaut.test.junit5)
testRuntimeOnly(mnLogging.logback.classic)
testRuntimeOnly(libs.junit.jupiter.engine)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2017-2023 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.jaxrs.runtime.core;

import io.micronaut.core.annotation.Nullable;
import io.micronaut.http.HttpAttributes;
import io.micronaut.http.HttpRequest;
import io.micronaut.runtime.http.scope.RequestAware;
import io.micronaut.runtime.http.scope.RequestScope;
import io.micronaut.web.router.MethodBasedRouteInfo;
import io.micronaut.web.router.RouteInfo;
import io.micronaut.web.router.RouteMatch;
import jakarta.ws.rs.container.ResourceInfo;

import java.lang.reflect.Method;

/**
* A {@link RequestScope} bean implementing the JAX-RS ResourceInfo to access the resource class and resource method matched by the current request.
* Methods in this class MAY return <code>null</code> if a resource class and method have not been matched.
*
* @author Tim Yates
* @since 4.1.0
*/
@RequestScope
public class JaxRsResourceInfo implements RequestAware, ResourceInfo {

private RouteInfo<?> routeInfo;

@Override
public void setRequest(HttpRequest<?> request) {
routeInfo = request.getAttribute(HttpAttributes.ROUTE_MATCH, RouteMatch.class).map(RouteMatch::getRouteInfo).orElse(null);
}

@Nullable
@Override
public Method getResourceMethod() {
if (routeInfo instanceof MethodBasedRouteInfo<?, ?> methodBasedRouteInfo) {
return methodBasedRouteInfo.getTargetMethod().getTargetMethod();
}
return null;
}

@Nullable
@Override
public Class<?> getResourceClass() {
return routeInfo == null ? null : routeInfo.getDeclaringType();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.micronaut.jaxrs.runtime.core

import io.micronaut.context.annotation.Property
import io.micronaut.context.annotation.Requires
import io.micronaut.http.HttpRequest
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import jakarta.inject.Inject
import jakarta.ws.rs.GET
import jakarta.ws.rs.POST
import jakarta.ws.rs.Path
import jakarta.ws.rs.container.ResourceInfo
import spock.lang.Specification

@MicronautTest
@Property(name = "spec.name", value = "ResourceInfoSpec")
class ResourceInfoSpec extends Specification {

@Inject
@Client("/")
HttpClient client

void "resource info is correctly populated"() {
expect:
client.toBlocking().retrieve("/api/info/test", String) == 'io.micronaut.jaxrs.runtime.core.ResourceInfoSpec$ResourceInfoResource:getTest'
client.toBlocking().retrieve(HttpRequest.POST("/api/info/test", "")) == 'io.micronaut.jaxrs.runtime.core.ResourceInfoSpec$ResourceInfoResource:postTest'
}

@Path("/info")
@Requires(property = "spec.name", value = "ResourceInfoSpec")
static class ResourceInfoResource {

private final ResourceInfo resourceInfo

ResourceInfoResource(JaxRsResourceInfo resourceInfo) {
this.resourceInfo = resourceInfo
}

@Path("/test")
@GET
String getTest() {
"${resourceInfo.resourceClass.name}:${resourceInfo.resourceMethod.name}"
}

@Path("/test")
@POST
String postTest() {
"${resourceInfo.resourceClass.name}:${resourceInfo.resourceMethod.name}"
}
}
}
7 changes: 7 additions & 0 deletions src/main/docs/guide/supportedApi.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ You can also use the link:{jaxrsapi}/jakarta/ws/rs/core/Context.html[@Context] a

NOTE: Parameter binding to constructor argument of resource types is not supported at this time.

==== ResourceInfo

link:{jaxrsapi}jakarta/ws/rs/container/ResourceInfo.html[ResourceInfo] is a JAX-RS context which can be injected to check which resource class and method are about to be invoked.
This is supported in the micronaut-jaxrs module via the link:{micronautapi}runtime/http/scope/RequestScope.html[`@RequestScope`] bean link:{api}/io/micronaut/jaxrs/runtime/core/JaxRsResourceInfo.html[`JaxRsResourceInfo`].

See the https://guides.micronaut.io/latest/micronaut-scope-types.html[Scope type guide] for more information on using RequestScope beans.

==== SecurityContext and Micronaut Security

When injecting the link:{jaxrsapi}/jakarta/ws/rs/core/SecurityContext.html[SecurityContext] by default the injected instance is not aware of https://micronaut-projects.github.io/micronaut-security/latest/guide/[Micronaut Security] and methods like `isUserInRole` always return `false`.
Expand Down

0 comments on commit fa2afed

Please sign in to comment.