Skip to content

Commit

Permalink
Ensure that @path on an interface with a single impl works as in REST…
Browse files Browse the repository at this point in the history
…Easy Classic

Fixes: #15028
  • Loading branch information
geoand committed Feb 12, 2021
1 parent 6619ec2 commit 059aec4
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

import javax.ws.rs.RuntimeType;
Expand Down Expand Up @@ -73,7 +74,7 @@ void setupClientProxies(ResteasyReactiveClientRecorder recorder,
List<MessageBodyReaderBuildItem> messageBodyReaderBuildItems,
List<MessageBodyWriterBuildItem> messageBodyWriterBuildItems,
BeanArchiveIndexBuildItem beanArchiveIndexBuildItem,
ResourceScanningResultBuildItem resourceScanningResultBuildItem,
Optional<ResourceScanningResultBuildItem> resourceScanningResultBuildItem,
ResteasyReactiveConfig config,
RecorderContext recorderContext,
BuildProducer<GeneratedClassBuildItem> generatedClassBuildItemBuildProducer,
Expand All @@ -85,12 +86,12 @@ void setupClientProxies(ResteasyReactiveClientRecorder recorder,
messageBodyWriterBuildItems, beanContainerBuildItem, applicationResultBuildItem, serialisers,
RuntimeType.CLIENT);

if (resourceScanningResultBuildItem == null
|| resourceScanningResultBuildItem.getResult().getPathInterfaces().isEmpty()) {
if (!resourceScanningResultBuildItem.isPresent()
|| resourceScanningResultBuildItem.get().getResult().getPathInterfaces().isEmpty()) {
recorder.setupClientProxies(new HashMap<>());
return;
}
ResourceScanningResult result = resourceScanningResultBuildItem.getResult();
ResourceScanningResult result = resourceScanningResultBuildItem.get().getResult();

AdditionalReaders additionalReaders = new AdditionalReaders();
AdditionalWriters additionalWriters = new AdditionalWriters();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ public class ResteasyReactiveCommonProcessor {
@BuildStep
void setUpDenyAllJaxRs(CombinedIndexBuildItem index,
JaxRsSecurityConfig config,
ResourceScanningResultBuildItem resteasyDeployment,
Optional<ResourceScanningResultBuildItem> resteasyDeployment,
BuildProducer<AdditionalSecuredClassesBuildIem> additionalSecuredClasses) {
if (config.denyJaxRs) {
if (config.denyJaxRs && resteasyDeployment.isPresent()) {
final List<ClassInfo> classes = new ArrayList<>();

Set<DotName> resourceClasses = resteasyDeployment.getResult().getScannedResourcePaths().keySet();
Set<DotName> resourceClasses = resteasyDeployment.get().getResult().getScannedResourcePaths().keySet();
for (DotName className : resourceClasses) {
ClassInfo classInfo = index.getIndex().getClassByName(className);
if (!SecurityTransformerUtils.hasSecurityAnnotation(classInfo)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package io.quarkus.resteasy.reactive.server.deployment;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.ws.rs.BeanParam;

import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames;
import org.jboss.resteasy.reactive.common.processor.scanning.ResourceScanningResult;
import org.jboss.resteasy.reactive.server.injection.ContextProducers;

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
Expand All @@ -15,6 +21,7 @@
import io.quarkus.arc.processor.DotNames;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.resteasy.reactive.common.deployment.ResourceScanningResultBuildItem;
import io.quarkus.resteasy.reactive.server.runtime.QuarkusContextProducers;
import io.quarkus.resteasy.reactive.spi.DynamicFeatureBuildItem;
import io.quarkus.resteasy.reactive.spi.JaxrsFeatureBuildItem;
Expand Down Expand Up @@ -43,6 +50,38 @@ void beanDefiningAnnotations(BuildProducer<BeanDefiningAnnotationBuildItem> bean
BuiltinScope.SINGLETON.getName()));
}

// when an interface is annotated with @Path and there is only one implementation of it that is not annotated with @Path,
// we need to make this class a bean. See https://github.com/quarkusio/quarkus/issues/15028
@BuildStep
void pathInterfaceImpls(Optional<ResourceScanningResultBuildItem> resourceScanningResultBuildItem,
BuildProducer<AdditionalBeanBuildItem> additionalBeanBuildItemBuildProducer) {
if (!resourceScanningResultBuildItem.isPresent()) {
return;
}
ResourceScanningResult resourceScanningResult = resourceScanningResultBuildItem.get().getResult();
Map<DotName, String> pathInterfaces = resourceScanningResult.getPathInterfaces();
List<String> impls = new ArrayList<>();
for (Map.Entry<DotName, String> i : pathInterfaces.entrySet()) {
List<ClassInfo> candidateBeans = new ArrayList<>(1);
for (ClassInfo clazz : resourceScanningResult.getIndex().getAllKnownImplementors(i.getKey())) {
if (!Modifier.isAbstract(clazz.flags())) {
if ((clazz.enclosingClass() == null || Modifier.isStatic(clazz.flags())) &&
clazz.enclosingMethod() == null) {
candidateBeans.add(clazz);
}
}
}
if (candidateBeans.size() == 1) {
impls.add(candidateBeans.get(0).name().toString());
}
}
if (!impls.isEmpty()) {
additionalBeanBuildItemBuildProducer
.produce(AdditionalBeanBuildItem.builder().setUnremovable().addBeanClasses(impls.toArray(new String[0]))
.build());
}
}

@BuildStep
void additionalBeans(List<DynamicFeatureBuildItem> additionalDynamicFeatures,
List<JaxrsFeatureBuildItem> featureBuildItems,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.quarkus.resteasy.reactive.server.test.simple;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("iface")
public interface InterfaceResource {

@GET
@Produces(MediaType.TEXT_PLAIN)
String hello();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.quarkus.resteasy.reactive.server.test.simple;

import javax.inject.Inject;

public class InterfaceResourceImpl implements InterfaceResource {

@Inject
HelloService helloService;

@Override
public String hello() {
return helloService.sayHello();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public JavaArchive get() {
ParameterWithFromString.class, BeanParamSubClass.class, FieldInjectedSubClassResource.class,
BeanParamSuperClass.class, IllegalClassExceptionMapper.class,
MyParameterProvider.class, MyParameterConverter.class, MyParameter.class,
NewParamsRestResource.class);
NewParamsRestResource.class, InterfaceResource.class, InterfaceResourceImpl.class);
}
});

Expand Down Expand Up @@ -413,4 +413,10 @@ public void bigDecimal() {
RestAssured.get("/simple/bigDecimal/1.0")
.then().statusCode(200).body(Matchers.equalTo("1.0"));
}

@Test
public void testInterfaceResource() {
RestAssured.get("/iface")
.then().statusCode(200).body(Matchers.equalTo("Hello"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import java.util.Set;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
import org.jboss.jandex.MethodInfo;

public final class ResourceScanningResult {

private final IndexView index;
final Map<DotName, ClassInfo> scannedResources;
final Map<DotName, String> scannedResourcePaths;
final Map<DotName, ClassInfo> possibleSubResources;
Expand All @@ -18,10 +20,12 @@ public final class ResourceScanningResult {
final Map<DotName, String> httpAnnotationToMethod;
final List<MethodInfo> classLevelExceptionMappers;

public ResourceScanningResult(Map<DotName, ClassInfo> scannedResources, Map<DotName, String> scannedResourcePaths,
public ResourceScanningResult(IndexView index, Map<DotName, ClassInfo> scannedResources,
Map<DotName, String> scannedResourcePaths,
Map<DotName, ClassInfo> possibleSubResources, Map<DotName, String> pathInterfaces,
Map<DotName, MethodInfo> resourcesThatNeedCustomProducer,
Set<String> beanParams, Map<DotName, String> httpAnnotationToMethod, List<MethodInfo> classLevelExceptionMappers) {
this.index = index;
this.scannedResources = scannedResources;
this.scannedResourcePaths = scannedResourcePaths;
this.possibleSubResources = possibleSubResources;
Expand All @@ -32,6 +36,10 @@ public ResourceScanningResult(Map<DotName, ClassInfo> scannedResources, Map<DotN
this.classLevelExceptionMappers = classLevelExceptionMappers;
}

public IndexView getIndex() {
return index;
}

public Map<DotName, ClassInfo> getScannedResources() {
return scannedResources;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ public static ResourceScanningResult scanResources(
}
httpAnnotationToMethod.put(httpMethodInstance.target().asClass().name(), httpMethodInstance.value().asString());
}
return new ResourceScanningResult(scannedResources,
return new ResourceScanningResult(index, scannedResources,
scannedResourcePaths, possibleSubResources, pathInterfaces, resourcesThatNeedCustomProducer, beanParams,
httpAnnotationToMethod, methodExceptionMappers);
}
Expand Down

0 comments on commit 059aec4

Please sign in to comment.