Skip to content

Commit

Permalink
Merge pull request #10165 from geoand/#10164
Browse files Browse the repository at this point in the history
Warn when a spring-web class is not annotated with @RestController
  • Loading branch information
geoand authored Jun 22, 2020
2 parents b7aa52a + 94d8573 commit 4f809fc
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 0 deletions.
5 changes: 5 additions & 0 deletions extensions/spring-web/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.jboss.jandex.IndexView;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.Type;
import org.jboss.logging.Logger;
import org.jboss.resteasy.core.MediaTypeMap;
import org.jboss.resteasy.plugins.server.servlet.ResteasyContextParameters;
import org.jboss.resteasy.spi.ResteasyDeployment;
Expand Down Expand Up @@ -63,6 +64,8 @@

public class SpringWebProcessor {

private static final Logger LOGGER = Logger.getLogger(SpringWebProcessor.class.getName());

private static final DotName REST_CONTROLLER_ANNOTATION = DotName
.createSimple("org.springframework.web.bind.annotation.RestController");

Expand Down Expand Up @@ -162,6 +165,8 @@ public void process(BeanArchiveIndexBuildItem beanArchiveIndexBuildItem,
BuildProducer<ServletInitParamBuildItem> initParamProducer,
BuildProducer<ResteasyDeploymentCustomizerBuildItem> deploymentCustomizerProducer) {

validateControllers(beanArchiveIndexBuildItem);

final IndexView index = beanArchiveIndexBuildItem.getIndex();
final Collection<AnnotationInstance> annotations = index.getAnnotations(REST_CONTROLLER_ANNOTATION);
if (annotations.isEmpty()) {
Expand Down Expand Up @@ -190,6 +195,35 @@ public void accept(ResteasyDeployment resteasyDeployment) {
reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, false, SpringResourceBuilder.class.getName()));
}

/**
* Make sure the controllers have the proper annotation and warn if not
*/
private void validateControllers(BeanArchiveIndexBuildItem beanArchiveIndexBuildItem) {
Collection<AnnotationInstance> annotations = beanArchiveIndexBuildItem.getIndex().getAnnotations(REQUEST_MAPPING);
Set<DotName> classesWithoutRestController = new HashSet<>();
for (AnnotationInstance annotation : annotations) {
ClassInfo targetClass;
if (annotation.target().kind() == AnnotationTarget.Kind.CLASS) {
targetClass = annotation.target().asClass();
} else if (annotation.target().kind() == AnnotationTarget.Kind.METHOD) {
targetClass = annotation.target().asMethod().declaringClass();
} else {
continue;
}

if (targetClass.classAnnotation(REST_CONTROLLER_ANNOTATION) == null) {
classesWithoutRestController.add(targetClass.name());
}
}

if (!classesWithoutRestController.isEmpty()) {
for (DotName dotName : classesWithoutRestController) {
LOGGER.warn("Class '" + dotName
+ "' uses '@RequestMapping' but was not annotated with '@RestContoller' and will therefore be ignored.");
}
}
}

@BuildStep(onlyIf = IsDevelopment.class)
@Record(STATIC_INIT)
public void registerWithDevModeNotFoundMapper(BeanArchiveIndexBuildItem beanArchiveIndexBuildItem,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package io.quarkus.spring.web.test;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.List;
import java.util.logging.LogRecord;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import io.quarkus.test.ProdBuildResults;
import io.quarkus.test.ProdModeTestResults;
import io.quarkus.test.QuarkusProdModeTest;

public class MissingRestControllerTest {

@RegisterExtension
static final QuarkusProdModeTest config = new QuarkusProdModeTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClasses(NonAnnotatedController.class, ProperController.class))
.setApplicationName("missing-rest-controller")
.setApplicationVersion("0.1-SNAPSHOT")
.setLogRecordPredicate(r -> "io.quarkus.spring.web.deployment.SpringWebProcessor".equals(r.getLoggerName()));

@ProdBuildResults
private ProdModeTestResults prodModeTestResults;

@Test
public void testBuildLogs() {
List<LogRecord> buildLogRecords = prodModeTestResults.getRetainedBuildLogRecords();
assertThat(buildLogRecords).isNotEmpty();
assertThat(buildLogRecords).hasOnlyOneElementSatisfying(r -> {
assertThat(r.getMessage())
.contains("but was not annotated with")
.contains(NonAnnotatedController.class.getName())
.doesNotContain(ProperController.class.getName());
});
}

@RequestMapping("/non")
public static class NonAnnotatedController {

@GetMapping("/hello")
public String greet() {
return "hello";
}
}

@RestController
@RequestMapping("/proper")
public static class ProperController {

@GetMapping("/hello")
public String greet() {
return "hello";
}
}
}

0 comments on commit 4f809fc

Please sign in to comment.