Skip to content

Commit

Permalink
Decouple quarkus-spring-web from RESTEasy Classic
Browse files Browse the repository at this point in the history
This is prerequisite work for being able to run
Spring Web endpoints on RESTEasy Reactive in addition
to RESTEasy Classic.

The decoupling is achieved by using conditional
dependencies and moving RESTEasy specific code
to a new extension
  • Loading branch information
geoand committed Oct 29, 2021
1 parent b272148 commit 24eda12
Show file tree
Hide file tree
Showing 34 changed files with 693 additions and 338 deletions.
15 changes: 15 additions & 0 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1788,6 +1788,11 @@
<artifactId>quarkus-spring-scheduled-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-web-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-web</artifactId>
Expand All @@ -1798,6 +1803,16 @@
<artifactId>quarkus-spring-web-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-web-resteasy-classic</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-web-resteasy-classic-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-data-jpa</artifactId>
Expand Down
13 changes: 13 additions & 0 deletions devtools/bom-descriptor-json/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2671,6 +2671,19 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-web-resteasy-classic</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-swagger-ui</artifactId>
Expand Down
13 changes: 13 additions & 0 deletions docs/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2632,6 +2632,19 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-web-resteasy-classic-deployment</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-swagger-ui-deployment</artifactId>
Expand Down
42 changes: 42 additions & 0 deletions extensions/spring-web/core/common-runtime/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>quarkus-spring-web-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
</parent>

<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-spring-web-common</artifactId>
<name>Quarkus - Spring Web - Common Runtime</name>

<dependencies>
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_2.1_spec</artifactId>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-web-api</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-webmvc-api</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-core-api</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-context-api</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.quarkus.spring.web.runtime;
package io.quarkus.spring.web.runtime.common;

import static javax.ws.rs.core.HttpHeaders.ACCEPT;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
Expand All @@ -10,13 +10,13 @@
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Variant;

import org.jboss.resteasy.core.request.ServerDrivenNegotiation;

public final class ResponseContentTypeResolver {
public abstract class AbstractResponseContentTypeResolver {

private static final MediaType DEFAULT_MEDIA_TYPE = TEXT_PLAIN_TYPE;

public static MediaType resolve(HttpHeaders httpHeaders, String... supportedMediaTypes) {
protected abstract Variant negotiateBestMatch(List<String> acceptHeaders, List<Variant> variants);

public MediaType resolve(HttpHeaders httpHeaders, String... supportedMediaTypes) {
Objects.requireNonNull(httpHeaders, "HttpHeaders cannot be null");
Objects.requireNonNull(supportedMediaTypes, "Supported media types array cannot be null");

Expand All @@ -33,16 +33,13 @@ public static MediaType resolve(HttpHeaders httpHeaders, String... supportedMedi
return DEFAULT_MEDIA_TYPE;
}

private static Variant getBestVariant(List<String> acceptHeaders, List<Variant> variants) {
private Variant getBestVariant(List<String> acceptHeaders, List<Variant> variants) {
if (acceptHeaders.isEmpty()) {
// done because negotiation.setAcceptHeaders(acceptHeaders) throws a NPE when passed an empty list
return null;
}

ServerDrivenNegotiation negotiation = new ServerDrivenNegotiation();
negotiation.setAcceptHeaders(acceptHeaders);

return negotiation.getBestMatch(variants);
return negotiateBestMatch(acceptHeaders, variants);
}

private static List<Variant> getMediaTypeVariants(String... mediaTypes) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.quarkus.spring.web.runtime;
package io.quarkus.spring.web.runtime.common;

import java.util.List;
import java.util.Map;
Expand All @@ -7,15 +7,16 @@
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;

import org.jboss.resteasy.specimpl.ResponseBuilderImpl;
import org.springframework.http.HttpHeaders;
import org.springframework.web.server.ResponseStatusException;

public class ResponseStatusExceptionMapper implements ExceptionMapper<ResponseStatusException> {
public abstract class AbstractResponseStatusExceptionMapper implements ExceptionMapper<ResponseStatusException> {

protected abstract Response.ResponseBuilder createResponseBuilder(ResponseStatusException exception);

@Override
public Response toResponse(ResponseStatusException exception) {
Response.ResponseBuilder responseBuilder = new ResponseBuilderImpl().status(exception.getStatus().value());
Response.ResponseBuilder responseBuilder = createResponseBuilder(exception);
addHeaders(responseBuilder, exception.getResponseHeaders());
return responseBuilder.entity(exception.getMessage())
.type(MediaType.TEXT_PLAIN).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-spring-web-deployment</artifactId>
<name>Quarkus - Spring - Web - Deployment</name>
<name>Quarkus - Spring Web - Deployment</name>

<dependencies>
<dependency>
Expand All @@ -24,15 +24,17 @@
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson-deployment</artifactId>
<artifactId>quarkus-spring-web-resteasy-classic-deployment</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jaxrs-spi-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-common-spi</artifactId>
<artifactId>quarkus-resteasy-jackson-deployment</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import io.quarkus.gizmo.MethodCreator;
import io.quarkus.gizmo.MethodDescriptor;
import io.quarkus.gizmo.ResultHandle;
import io.quarkus.spring.web.runtime.ResponseContentTypeResolver;
import io.quarkus.spring.web.runtime.ResponseEntityConverter;

class ControllerAdviceAbstractExceptionMapperGenerator extends AbstractExceptionMapperGenerator {
Expand All @@ -53,15 +52,24 @@ class ControllerAdviceAbstractExceptionMapperGenerator extends AbstractException

private FieldDescriptor httpHeadersField;

private final boolean isResteasyClassic;

ControllerAdviceAbstractExceptionMapperGenerator(MethodInfo controllerAdviceMethod, DotName exceptionDotName,
ClassOutput classOutput, TypesUtil typesUtil) {
ClassOutput classOutput, TypesUtil typesUtil, boolean isResteasyClassic) {
super(exceptionDotName, classOutput);

// TODO: remove this restriction
if (!isResteasyClassic) {
throw new IllegalStateException("Currently Spring Web can only work with RESTEasy Classic");
}

this.controllerAdviceMethod = controllerAdviceMethod;
this.typesUtil = typesUtil;

this.returnType = controllerAdviceMethod.returnType();
this.parameterTypes = controllerAdviceMethod.parameters();
this.declaringClassName = controllerAdviceMethod.declaringClass().name().toString();
this.isResteasyClassic = isResteasyClassic;
}

/**
Expand Down Expand Up @@ -187,9 +195,15 @@ private ResultHandle getResponseContentType(MethodCreator methodCreator, List<St
.map(methodCreator::load)
.toArray(ResultHandle[]::new);

return methodCreator.invokeStaticMethod(
MethodDescriptor.ofMethod(ResponseContentTypeResolver.class, "resolve", MediaType.class,
String responseContentTypeResolverClassName = isResteasyClassic
? "io.quarkus.spring.web.runtime.ResteasyClassicResponseContentTypeResolver"
: "io.quarkus.spring.web.runtime.ResteasyReactiveResponseContentTypeResolver"; // doesn't exist yet
ResultHandle contentTypeResolver = methodCreator
.newInstance(MethodDescriptor.ofConstructor(responseContentTypeResolverClassName));
return methodCreator.invokeVirtualMethod(
MethodDescriptor.ofMethod(responseContentTypeResolverClassName, "resolve", MediaType.class,
HttpHeaders.class, String[].class),
contentTypeResolver,
methodCreator.readInstanceField(httpHeadersField, methodCreator.getThis()),
methodCreator.marshalAsArray(String.class, supportedMediaTypes));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
class ResponseStatusOnExceptionGenerator extends AbstractExceptionMapperGenerator {

private final ClassInfo exceptionClassInfo;
private final boolean isResteasyClassic;

ResponseStatusOnExceptionGenerator(ClassInfo exceptionClassInfo, ClassOutput classOutput) {
ResponseStatusOnExceptionGenerator(ClassInfo exceptionClassInfo, ClassOutput classOutput, boolean isResteasyClassic) {
super(exceptionClassInfo.name(), classOutput);
this.exceptionClassInfo = exceptionClassInfo;
this.isResteasyClassic = isResteasyClassic;
}

void generateMethodBody(MethodCreator toResponse) {
Expand Down
Loading

0 comments on commit 24eda12

Please sign in to comment.