Skip to content

Commit 75beba2

Browse files
authored
Add support for Quarkus in native mode (#174)
1 parent ea750c7 commit 75beba2

File tree

17 files changed

+426
-47
lines changed

17 files changed

+426
-47
lines changed

belgif-rest-problem-it/belgif-rest-problem-quarkus-it/pom.xml

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<dependency>
1818
<groupId>io.quarkus.platform</groupId>
1919
<artifactId>quarkus-bom</artifactId>
20-
<version>3.18.1</version>
20+
<version>${version.quarkus}</version>
2121
<type>pom</type>
2222
<scope>import</scope>
2323
</dependency>
@@ -56,6 +56,10 @@
5656
<groupId>io.quarkus</groupId>
5757
<artifactId>quarkus-arc</artifactId>
5858
</dependency>
59+
<dependency>
60+
<groupId>io.quarkus</groupId>
61+
<artifactId>quarkus-container-image-docker</artifactId>
62+
</dependency>
5963
<dependency>
6064
<groupId>io.quarkus</groupId>
6165
<artifactId>quarkus-junit5</artifactId>
@@ -73,15 +77,14 @@
7377
<plugin>
7478
<groupId>io.quarkus.platform</groupId>
7579
<artifactId>quarkus-maven-plugin</artifactId>
76-
<version>3.18.1</version>
80+
<version>${version.quarkus}</version>
7781
<extensions>true</extensions>
7882
<executions>
7983
<execution>
8084
<goals>
8185
<goal>build</goal>
8286
<goal>generate-code</goal>
8387
<goal>generate-code-tests</goal>
84-
<goal>native-image-agent</goal>
8588
</goals>
8689
</execution>
8790
</executions>
@@ -107,19 +110,4 @@
107110
</plugins>
108111
</build>
109112

110-
<profiles>
111-
<profile>
112-
<id>native</id>
113-
<activation>
114-
<property>
115-
<name>native</name>
116-
</property>
117-
</activation>
118-
<properties>
119-
<skipITs>false</skipITs>
120-
<quarkus.native.enabled>true</quarkus.native.enabled>
121-
</properties>
122-
</profile>
123-
</profiles>
124-
125113
</project>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FROM quay.io/quarkus/quarkus-micro-image:2.0
2+
WORKDIR /work/
3+
COPY target/*-runner /work/application
4+
RUN chmod 775 /work
5+
EXPOSE 8080
6+
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]

belgif-rest-problem-it/belgif-rest-problem-quarkus-it/src/main/resources/application.properties

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,14 @@ quarkus.http.root-path=/quarkus
22
quarkus.locales=en,fr-BE,nl-BE,de-BE
33
quarkus.rest-client.backend.uri=http://localhost:${quarkus.http.port}/quarkus
44
%test.quarkus.rest-client.backend.uri=http://localhost:${quarkus.http.test-port}/quarkus
5+
quarkus.native.enabled=true
6+
quarkus.container-image.build=true
7+
quarkus.container-image.group=belgif
8+
quarkus.native.container-build=true
9+
quarkus.native.container-runtime=docker
10+
#Fatal error: org.graalvm.compiler.debug.GraalError: org.graalvm.compiler.debug.GraalError:
11+
#com.oracle.svm.hosted.substitute.DeletedElementException: Unsupported method java.lang.Object.wait0(long) is reachable
12+
#To diagnose the issue, you can add the option --report-unsupported-elements-at-runtime.
13+
#The unsupported element is then reported at run time when it is accessed the first time.
14+
quarkus.native.report-errors-at-runtime=true
15+
quarkus.native.resources.includes=com/acme/custom/Messages*.properties
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.github.belgif.rest.problem.quarkus.it;
2+
3+
import java.util.Arrays;
4+
import java.util.stream.Stream;
5+
6+
import org.junit.jupiter.api.Test;
7+
8+
import io.github.belgif.rest.problem.it.AbstractRestProblemIT;
9+
import io.quarkus.test.common.http.TestHTTPEndpoint;
10+
import io.quarkus.test.junit.QuarkusIntegrationTest;
11+
import io.restassured.RestAssured;
12+
import io.restassured.specification.RequestSpecification;
13+
14+
@TestHTTPEndpoint(Frontend.class)
15+
@QuarkusIntegrationTest
16+
class RestProblemQuarkusDockerIT extends AbstractRestProblemIT {
17+
18+
@Override
19+
protected RequestSpecification getSpec() {
20+
return RestAssured.given();
21+
}
22+
23+
@Test
24+
@Override
25+
public void methodNotAllowed() {
26+
getSpec().when().post("/custom").then().assertThat()
27+
.statusCode(405);
28+
}
29+
30+
@Override
31+
protected Stream<String> getClients() {
32+
return Arrays.stream(Client.values()).map(Client::name);
33+
}
34+
}

belgif-rest-problem-java-ee/src/main/java/io/github/belgif/rest/problem/ee/internal/ConstraintViolationUtil.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,22 @@ private static InEnum determineSource(ConstraintViolation<?> violation,
7373
if (propertyPath.getLast().getKind() == ElementKind.PARAMETER) {
7474
if (methodNode != null) {
7575
ParameterNode param = propertyPath.getLast().as(ParameterNode.class);
76-
try {
77-
Method method = violation.getRootBeanClass().getMethod(methodNode.getName(),
78-
methodNode.getParameterTypes().toArray(new Class[0]));
79-
return AnnotationUtil.findParamAnnotation(method, param.getParameterIndex(), ANNOTATIONS)
80-
.map(Annotation::annotationType).map(SOURCE_MAPPING::get)
81-
.orElse(InEnum.BODY);
82-
} catch (NoSuchMethodException e) {
83-
throw new IllegalStateException(
84-
"Method " + methodNode.getName() + " not found on " + violation.getRootBeanClass(), e);
76+
Class<?> clazz = violation.getRootBeanClass();
77+
// Normally Class#getMethod() recursively searches up the class hierarchy,
78+
// but apparantly not on Quarkus native, so we implement the recursion ourselves
79+
while (!Object.class.equals(clazz)) {
80+
try {
81+
Method method = clazz.getMethod(methodNode.getName(),
82+
methodNode.getParameterTypes().toArray(new Class[0]));
83+
return AnnotationUtil.findParamAnnotation(method, param.getParameterIndex(), ANNOTATIONS)
84+
.map(Annotation::annotationType).map(SOURCE_MAPPING::get)
85+
.orElse(InEnum.BODY);
86+
} catch (NoSuchMethodException e) {
87+
clazz = clazz.getSuperclass();
88+
}
8589
}
90+
throw new IllegalStateException(
91+
"Method " + methodNode.getName() + " not found on " + violation.getRootBeanClass());
8692
} else {
8793
return InEnum.QUERY;
8894
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.github.belgif.rest.problem.ee.jaxrs;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
5+
import io.github.belgif.rest.problem.ee.CdiProblemModule;
6+
7+
/**
8+
* ObjectMapper that registers the CdiProblemModule.
9+
*/
10+
public class ProblemObjectMapper extends ObjectMapper {
11+
12+
public static final ProblemObjectMapper INSTANCE = new ProblemObjectMapper();
13+
14+
private ProblemObjectMapper() {
15+
registerModule(new CdiProblemModule());
16+
}
17+
18+
}

belgif-rest-problem-java-ee/src/main/java/io/github/belgif/rest/problem/ee/jaxrs/ProblemObjectMapperContextResolver.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,13 @@
77

88
import com.fasterxml.jackson.databind.ObjectMapper;
99

10-
import io.github.belgif.rest.problem.ee.CdiProblemModule;
11-
1210
@Provider
1311
@Priority(Priorities.USER + 200)
1412
public class ProblemObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
1513

16-
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
17-
.registerModule(new CdiProblemModule());
18-
1914
@Override
2015
public ObjectMapper getContext(Class<?> type) {
21-
return OBJECT_MAPPER;
22-
}
23-
24-
public static ObjectMapper getObjectMapper() {
25-
return OBJECT_MAPPER;
16+
return ProblemObjectMapper.INSTANCE;
2617
}
2718

2819
}

belgif-rest-problem-java-ee/src/main/java/io/github/belgif/rest/problem/ee/jaxrs/client/ProblemClientResponseFilter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import io.github.belgif.rest.problem.DefaultProblem;
1818
import io.github.belgif.rest.problem.api.Problem;
1919
import io.github.belgif.rest.problem.ee.jaxrs.ProblemMediaType;
20-
import io.github.belgif.rest.problem.ee.jaxrs.ProblemObjectMapperContextResolver;
20+
import io.github.belgif.rest.problem.ee.jaxrs.ProblemObjectMapper;
2121

2222
/**
2323
* JAX-RS ClientResponseFilter that converts problem response to a ProblemWrapper exception.
@@ -33,7 +33,7 @@ public class ProblemClientResponseFilter implements ClientResponseFilter {
3333
private final ObjectMapper objectMapper;
3434

3535
public ProblemClientResponseFilter() {
36-
this(ProblemObjectMapperContextResolver.getObjectMapper());
36+
this(ProblemObjectMapper.INSTANCE);
3737
}
3838

3939
public ProblemClientResponseFilter(ObjectMapper objectMapper) {

belgif-rest-problem-java-ee/src/test/java/io/github/belgif/rest/problem/ee/jaxrs/ProblemObjectMapperContextResolverTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ void mapper() {
4242
when(registry.getProblemTypes()).thenReturn(new NamedType[] {});
4343
ObjectMapper mapper = new ProblemObjectMapperContextResolver().getContext(null);
4444
assertThat(mapper.getRegisteredModuleIds()).contains("io.github.belgif.rest.problem.ee.CdiProblemModule");
45-
assertThat(ProblemObjectMapperContextResolver.getObjectMapper()).isSameAs(mapper);
4645
}
4746
}
4847

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>io.github.belgif.rest.problem</groupId>
8+
<artifactId>belgif-rest-problem-parent</artifactId>
9+
<version>${revision}</version>
10+
</parent>
11+
12+
<artifactId>belgif-rest-problem-quarkus-deployment</artifactId>
13+
<packaging>jar</packaging>
14+
15+
<dependencyManagement>
16+
<dependencies>
17+
<dependency>
18+
<groupId>io.quarkus.platform</groupId>
19+
<artifactId>quarkus-bom</artifactId>
20+
<version>${version.quarkus}</version>
21+
<type>pom</type>
22+
<scope>import</scope>
23+
</dependency>
24+
</dependencies>
25+
</dependencyManagement>
26+
27+
<dependencies>
28+
<dependency>
29+
<groupId>io.quarkus</groupId>
30+
<artifactId>quarkus-arc-deployment</artifactId>
31+
</dependency>
32+
<dependency>
33+
<groupId>io.quarkus</groupId>
34+
<artifactId>quarkus-rest-jackson-common-deployment</artifactId>
35+
</dependency>
36+
<dependency>
37+
<groupId>io.github.belgif.rest.problem</groupId>
38+
<artifactId>belgif-rest-problem-quarkus</artifactId>
39+
<version>${project.version}</version>
40+
</dependency>
41+
<dependency>
42+
<groupId>io.github.belgif.rest.problem</groupId>
43+
<artifactId>belgif-rest-problem-java-ee</artifactId>
44+
<classifier>jakarta</classifier>
45+
<version>${project.version}</version>
46+
<scope>provided</scope>
47+
</dependency>
48+
<dependency>
49+
<groupId>jakarta.ws.rs</groupId>
50+
<artifactId>jakarta.ws.rs-api</artifactId>
51+
<scope>provided</scope>
52+
</dependency>
53+
<dependency>
54+
<groupId>org.jboss.resteasy.microprofile</groupId>
55+
<artifactId>microprofile-rest-client</artifactId>
56+
<scope>provided</scope>
57+
</dependency>
58+
<dependency>
59+
<groupId>org.junit.jupiter</groupId>
60+
<artifactId>junit-jupiter</artifactId>
61+
<scope>test</scope>
62+
</dependency>
63+
<dependency>
64+
<groupId>org.assertj</groupId>
65+
<artifactId>assertj-core</artifactId>
66+
<scope>test</scope>
67+
</dependency>
68+
<dependency>
69+
<groupId>org.mockito</groupId>
70+
<artifactId>mockito-junit-jupiter</artifactId>
71+
<scope>test</scope>
72+
</dependency>
73+
</dependencies>
74+
75+
<build>
76+
<plugins>
77+
<plugin>
78+
<artifactId>maven-compiler-plugin</artifactId>
79+
<configuration>
80+
<annotationProcessorPaths>
81+
<path>
82+
<groupId>io.quarkus</groupId>
83+
<artifactId>quarkus-extension-processor</artifactId>
84+
<version>${version.quarkus}</version>
85+
</path>
86+
</annotationProcessorPaths>
87+
</configuration>
88+
</plugin>
89+
</plugins>
90+
</build>
91+
92+
</project>

0 commit comments

Comments
 (0)