mirror of
https://github.com/jlengrand/helidon.git
synced 2026-03-10 08:21:17 +00:00
Allow user-provided CDI extensions to veto JAX-RS classes (#2429)
* Allow user-provided CDI extensions to veto JAX-RS classes so that they are not included as part of an application during discovery. Changed JaxRsCdiExtension to use a different event to process classes. Updated the bookstore-mp test to verify the veto process and also modernized its tests. Signed-off-by: Santiago Pericasgeertsen <santiago.pericasgeertsen@oracle.com> * Fixed checkstyle issues. Signed-off-by: Santiago Pericasgeertsen <santiago.pericasgeertsen@oracle.com>
This commit is contained in:
committed by
GitHub
parent
2a992422f9
commit
b1ddbe8828
@@ -34,8 +34,7 @@ import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.enterprise.context.Initialized;
|
||||
import javax.enterprise.event.Observes;
|
||||
import javax.enterprise.inject.spi.Extension;
|
||||
import javax.enterprise.inject.spi.ProcessAnnotatedType;
|
||||
import javax.enterprise.inject.spi.WithAnnotations;
|
||||
import javax.enterprise.inject.spi.ProcessManagedBean;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Application;
|
||||
@@ -64,30 +63,34 @@ public class JaxRsCdiExtension implements Extension {
|
||||
private final Set<Class<?>> providers = new HashSet<>();
|
||||
private final AtomicBoolean setInStone = new AtomicBoolean(false);
|
||||
|
||||
private void collectApplications(@Observes ProcessAnnotatedType<? extends Application> applicationType) {
|
||||
applications.add(applicationType.getAnnotatedType().getJavaClass());
|
||||
private void collectApplications(@Observes ProcessManagedBean<? extends Application> processManagedBean) {
|
||||
applications.add(processManagedBean.getAnnotatedBeanClass().getJavaClass());
|
||||
}
|
||||
|
||||
private void collectResourceClasses(@Observes @WithAnnotations(Path.class) ProcessAnnotatedType<?> resourceType) {
|
||||
Class<?> resourceClass = resourceType.getAnnotatedType().getJavaClass();
|
||||
if (resourceClass.isInterface()) {
|
||||
// we are only interested in classes - interface is most likely a REST client API
|
||||
return;
|
||||
private void collectResourceClasses(@Observes ProcessManagedBean<?> processManagedBean) {
|
||||
if (processManagedBean.getAnnotated().isAnnotationPresent(Path.class)) {
|
||||
Class<?> resourceClass = processManagedBean.getAnnotatedBeanClass().getJavaClass();
|
||||
if (resourceClass.isInterface()) {
|
||||
// we are only interested in classes - interface is most likely a REST client API
|
||||
return;
|
||||
}
|
||||
LOGGER.finest(() -> "Discovered resource class " + resourceClass.getName());
|
||||
resources.add(resourceClass);
|
||||
}
|
||||
LOGGER.finest(() -> "Discovered resource class " + resourceClass.getName());
|
||||
resources.add(resourceClass);
|
||||
}
|
||||
|
||||
private void collectProviderClasses(@Observes @WithAnnotations(Provider.class) ProcessAnnotatedType<?> providerType) {
|
||||
Class<?> providerClass = providerType.getAnnotatedType().getJavaClass();
|
||||
if (providerClass.isInterface()) {
|
||||
// we are only interested in classes
|
||||
LOGGER.finest(() -> "Discovered @Provider interface " + providerClass
|
||||
.getName() + ", ignored as we only support classes");
|
||||
return;
|
||||
private void collectProviderClasses(@Observes ProcessManagedBean<?> processManagedBean) {
|
||||
if (processManagedBean.getAnnotated().isAnnotationPresent(Provider.class)) {
|
||||
Class<?> providerClass = processManagedBean.getAnnotatedBeanClass().getJavaClass();
|
||||
if (providerClass.isInterface()) {
|
||||
// we are only interested in classes
|
||||
LOGGER.finest(() -> "Discovered @Provider interface " + providerClass
|
||||
.getName() + ", ignored as we only support classes");
|
||||
return;
|
||||
}
|
||||
LOGGER.finest(() -> "Discovered @Provider class " + providerClass.getName());
|
||||
providers.add(providerClass);
|
||||
}
|
||||
LOGGER.finest(() -> "Discovered @Provider class " + providerClass.getName());
|
||||
providers.add(providerClass);
|
||||
}
|
||||
|
||||
// once application scoped starts, we do not allow modification of applications
|
||||
|
||||
@@ -70,6 +70,11 @@
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.helidon.microprofile.tests</groupId>
|
||||
<artifactId>helidon-microprofile-tests-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.helidon.tests.apps.bookstore.mp;
|
||||
|
||||
import javax.enterprise.event.Observes;
|
||||
import javax.enterprise.inject.spi.Extension;
|
||||
import javax.enterprise.inject.spi.ProcessAnnotatedType;
|
||||
import javax.enterprise.inject.spi.WithAnnotations;
|
||||
import javax.ws.rs.Path;
|
||||
|
||||
/**
|
||||
* A CDI extension to dynamically veto the resource class {@link VetoedResource}.
|
||||
* After this class is vetoed, it shall not be part of the application.
|
||||
*/
|
||||
public class VetoCdiExtension implements Extension {
|
||||
|
||||
private void vetoResourceClass(@Observes @WithAnnotations(Path.class) ProcessAnnotatedType<?> resourceType) {
|
||||
Class<?> resourceClass = resourceType.getAnnotatedType().getJavaClass();
|
||||
if (resourceClass == VetoedResource.class) {
|
||||
resourceType.veto();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,18 +16,24 @@
|
||||
|
||||
package io.helidon.tests.apps.bookstore.mp;
|
||||
|
||||
import java.util.Set;
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.ws.rs.ApplicationPath;
|
||||
import javax.ws.rs.core.Application;
|
||||
/**
|
||||
* This resource class will be dynamically vetoed by {@link VetoCdiExtension} and
|
||||
* should not be part of the application after startup.
|
||||
*/
|
||||
@Path("/vetoed")
|
||||
@RequestScoped
|
||||
public class VetoedResource {
|
||||
|
||||
@ApplicationScoped
|
||||
@ApplicationPath("/")
|
||||
public class BookApplication extends Application {
|
||||
|
||||
@Override
|
||||
public Set<Class<?>> getClasses() {
|
||||
return Set.of(BookResource.class);
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
public Response get() {
|
||||
return Response.ok().build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# http://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.
|
||||
#
|
||||
|
||||
io.helidon.tests.apps.bookstore.mp.VetoCdiExtension
|
||||
@@ -16,50 +16,40 @@
|
||||
|
||||
package io.helidon.tests.apps.bookstore.mp;
|
||||
|
||||
import io.helidon.tests.apps.bookstore.common.Book;
|
||||
|
||||
import javax.enterprise.inject.se.SeContainer;
|
||||
import javax.enterprise.inject.spi.CDI;
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.client.Entity;
|
||||
import javax.ws.rs.client.WebTarget;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.helidon.microprofile.server.Server;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import io.helidon.microprofile.tests.junit5.HelidonTest;
|
||||
import io.helidon.tests.apps.bookstore.common.Book;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
@HelidonTest
|
||||
class BookResourceTest {
|
||||
|
||||
private static Server server;
|
||||
|
||||
private static Client client = ClientBuilder.newClient();
|
||||
|
||||
@BeforeAll
|
||||
public static void startTheServer() {
|
||||
server = Main.startServer();
|
||||
}
|
||||
@Inject
|
||||
private WebTarget webTarget;
|
||||
|
||||
@Test
|
||||
void testBooks() {
|
||||
assertBookStoreSize(0);
|
||||
|
||||
Response res = client.target(getConnectionString("/books"))
|
||||
Response res = webTarget.path("/books")
|
||||
.request()
|
||||
.post(Entity.json(getBookAsJson()));
|
||||
assertEquals(Response.Status.OK.getStatusCode(), res.getStatus());
|
||||
|
||||
assertBookStoreSize(1);
|
||||
|
||||
res = client.target(getConnectionString("/books/123456"))
|
||||
res = webTarget.path("/books/123456")
|
||||
.request()
|
||||
.get();
|
||||
assertEquals(Response.Status.OK.getStatusCode(), res.getStatus());
|
||||
@@ -67,14 +57,14 @@ class BookResourceTest {
|
||||
|
||||
assertBookStoreSize(1);
|
||||
|
||||
res = client.target(getConnectionString("/books/123456"))
|
||||
res = webTarget.path("/books/123456")
|
||||
.request()
|
||||
.put(Entity.json(getBookAsJson()));
|
||||
assertEquals(Response.Status.OK.getStatusCode(), res.getStatus());
|
||||
|
||||
assertBookStoreSize(1);
|
||||
|
||||
res = client.target(getConnectionString("/books/123456"))
|
||||
res = webTarget.path("/books/123456")
|
||||
.request()
|
||||
.delete();
|
||||
assertEquals(Response.Status.OK.getStatusCode(), res.getStatus());
|
||||
@@ -82,16 +72,6 @@ class BookResourceTest {
|
||||
assertBookStoreSize(0);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void destroyClass() {
|
||||
CDI<Object> current = CDI.current();
|
||||
((SeContainer) current).close();
|
||||
}
|
||||
|
||||
private String getConnectionString(String path) {
|
||||
return "http://localhost:" + server.port() + path;
|
||||
}
|
||||
|
||||
private String getBookAsJson() {
|
||||
InputStream is = getClass().getClassLoader().getResourceAsStream("book.json");
|
||||
if (is != null) {
|
||||
@@ -102,8 +82,7 @@ class BookResourceTest {
|
||||
}
|
||||
|
||||
private void assertBookStoreSize(int size) {
|
||||
Book[] jsonArray = client
|
||||
.target(getConnectionString("/books"))
|
||||
Book[] jsonArray = webTarget.path("/books")
|
||||
.request()
|
||||
.get(Book[].class);
|
||||
assertEquals(size, jsonArray.length);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.helidon.tests.apps.bookstore.mp;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.client.WebTarget;
|
||||
import javax.ws.rs.core.Response;
|
||||
import io.helidon.microprofile.tests.junit5.HelidonTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* Test that the resource class {@link VetoedResource} is not part
|
||||
* of the application after it has been vetoed by {@link VetoCdiExtension}.
|
||||
*/
|
||||
@HelidonTest
|
||||
class VetoedResourceTest {
|
||||
|
||||
@Inject
|
||||
private WebTarget webTarget;
|
||||
|
||||
@Test
|
||||
void testVetoed() {
|
||||
Response res = webTarget.path("/vetoed").request().get();
|
||||
assertEquals(Response.Status.NOT_FOUND.getStatusCode(), res.getStatus());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user