Skip to content

Commit c0c0137

Browse files
authored
Add simple Quarkus demo application (#59)
Added Quarkus demo application that uses MapStruct
1 parent e0503d6 commit c0c0137

11 files changed

Lines changed: 534 additions & 0 deletions

File tree

mapstruct-quarkus/README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# MapStruct + Quarkus
2+
3+
This example demonstrates how easy it is to use MapStruct in a [Quarkus](https://quarkus.io) application.
4+
5+
The example was basically built with the following steps:
6+
7+
1. Create a new Quarkus application
8+
9+
```
10+
mvn io.quarkus:quarkus-maven-plugin:0.15.0:create \
11+
-DprojectGroupId=org.mapstruct.examples.quarkus \
12+
-DprojectArtifactId=mapstruct-examples-quarkus \
13+
-DclassName="org.mapstruct.example.quarkus.PersonResource" \
14+
-Dpath="/person" \
15+
-Dextensions="resteasy-jsonb"
16+
```
17+
18+
2. Add the `mapstruct-processor` as a regular `provided` scoped dependency and *not* as described in the
19+
[reference guide](http://mapstruct.org/documentation/dev/reference/html/#_apache_maven)
20+
21+
```xml
22+
<dependency>
23+
<groupId>org.mapstruct</groupId>
24+
<artifactId>mapstruct-processor</artifactId>
25+
<version>${org.mapstruct.version}</version>
26+
<scope>provided</scope>
27+
</dependency>
28+
```
29+
30+
3. Set CDI as the default component-model (see [reference guide](http://mapstruct.org/documentation/dev/reference/html/#configuration-options))
31+
4. Define a mapper and inject it with `@Inject` in the service
32+
33+
That's it!
34+
35+
### Native images
36+
37+
As MapStruct is not using reflection within the mappers native images are supported as long as CDI is used to retrieve the mappers.
38+
Just try to package your Quarkus application in a native image and feel the speed!
39+
40+
```
41+
mvn package -Dnative
42+
```
43+
44+
In case you prefer to use `Mappers.getMapper(...)` be aware that this is not automatically supported by native images. Internally the `getMapper` method uses reflection to
45+
retrieve the mapper implementation.
46+
This is the only place where MapStruct uses reflection and thus it causes issues with native images.
47+
48+
There are some workarounds by defining additional metadata used during native image creation by GraalVM. For example you can create a `Feature` as described
49+
[here](https://github.com/oracle/graal/blob/master/substratevm/REFLECTION.md) and register all you mapper implementations and their constructor(s).
50+
51+
For example if you just have a `FoobarMapper` the feature might look like this:
52+
53+
```java
54+
@AutomaticFeature
55+
class MapstructMapperFeature implements Feature {
56+
public void beforeAnalysis(BeforeAnalysisAccess access) {
57+
try {
58+
RuntimeReflection.register(FoobarMapperImpl.class);
59+
RuntimeReflection.register(FoobarMapperImpl.class.getConstructors());
60+
} catch (NoSuchMethodException e) {
61+
throw new RuntimeException(e);
62+
}
63+
}
64+
}
65+
```
66+
67+
_(As `FoobarMapperImpl` is a generated class you first have to generate your mappers before you can define this class, otherwise you will get compiliation issues)_
68+
69+
70+
### One drawback
71+
72+
When using the Quarkus dev mode the mapper will automatically be (re)generated in case you make change to the `@Mapper` annotated class.
73+
Changing a dependent class (like `PersonDto` in this example) will not (re)generate the mapper implementation.
74+
75+
As a workaround you can quit the dev-mode, recompile and start the application once again or you can make a (temporary) change to the `@Mapper` annotated class so that it
76+
will be picked up and a valid implementation will be generated.
77+
78+
*Pay attention*: You have to add the mapstruct-processor as described above and *not* using the `maven-compile-plugin`.

mapstruct-quarkus/pom.xml

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
4+
Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
5+
and/or other contributors as indicated by the @authors tag. See the
6+
copyright.txt file in the distribution for a full listing of all
7+
contributors.
8+
9+
Licensed under the Apache License, Version 2.0 (the "License");
10+
you may not use this file except in compliance with the License.
11+
You may obtain a copy of the License at
12+
13+
http://www.apache.org/licenses/LICENSE-2.0
14+
15+
Unless required by applicable law or agreed to in writing, software
16+
distributed under the License is distributed on an "AS IS" BASIS,
17+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
See the License for the specific language governing permissions and
19+
limitations under the License.
20+
21+
-->
22+
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
23+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
24+
<modelVersion>4.0.0</modelVersion>
25+
<groupId>org.mapstruct.examples.quarkus</groupId>
26+
<artifactId>mapstruct-examples-quarkus</artifactId>
27+
<version>1.0-SNAPSHOT</version>
28+
29+
<properties>
30+
<surefire-plugin.version>2.22.0</surefire-plugin.version>
31+
<quarkus.version>0.15.0</quarkus.version>
32+
<org.mapstruct.version>1.3.0.Final</org.mapstruct.version>
33+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
34+
<maven.compiler.source>1.8</maven.compiler.source>
35+
<maven.compiler.target>1.8</maven.compiler.target>
36+
</properties>
37+
38+
<dependencyManagement>
39+
<dependencies>
40+
<dependency>
41+
<groupId>io.quarkus</groupId>
42+
<artifactId>quarkus-bom</artifactId>
43+
<version>${quarkus.version}</version>
44+
<type>pom</type>
45+
<scope>import</scope>
46+
</dependency>
47+
</dependencies>
48+
</dependencyManagement>
49+
50+
<dependencies>
51+
<dependency>
52+
<groupId>org.mapstruct</groupId>
53+
<artifactId>mapstruct</artifactId>
54+
<version>${org.mapstruct.version}</version>
55+
</dependency>
56+
57+
<dependency>
58+
<groupId>io.quarkus</groupId>
59+
<artifactId>quarkus-resteasy-jsonb</artifactId>
60+
</dependency>
61+
62+
<dependency>
63+
<groupId>io.quarkus</groupId>
64+
<artifactId>quarkus-junit5</artifactId>
65+
<scope>test</scope>
66+
</dependency>
67+
<dependency>
68+
<groupId>io.rest-assured</groupId>
69+
<artifactId>rest-assured</artifactId>
70+
<scope>test</scope>
71+
</dependency>
72+
73+
<dependency>
74+
<groupId>org.mapstruct</groupId>
75+
<artifactId>mapstruct-processor</artifactId>
76+
<version>${org.mapstruct.version}</version>
77+
<scope>provided</scope>
78+
</dependency>
79+
</dependencies>
80+
81+
<build>
82+
<plugins>
83+
<plugin>
84+
<groupId>io.quarkus</groupId>
85+
<artifactId>quarkus-maven-plugin</artifactId>
86+
<version>${quarkus.version}</version>
87+
<executions>
88+
<execution>
89+
<id>quarkus-build</id>
90+
<goals>
91+
<goal>build</goal>
92+
</goals>
93+
</execution>
94+
</executions>
95+
</plugin>
96+
<plugin>
97+
<artifactId>maven-surefire-plugin</artifactId>
98+
<version>${surefire-plugin.version}</version>
99+
<configuration>
100+
<systemProperties>
101+
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
102+
</systemProperties>
103+
</configuration>
104+
</plugin>
105+
</plugins>
106+
</build>
107+
108+
<profiles>
109+
<profile>
110+
<id>native</id>
111+
<activation>
112+
<property>
113+
<name>native</name>
114+
</property>
115+
</activation>
116+
<build>
117+
<plugins>
118+
<plugin>
119+
<groupId>io.quarkus</groupId>
120+
<artifactId>quarkus-maven-plugin</artifactId>
121+
<version>${quarkus.version}</version>
122+
<executions>
123+
<execution>
124+
<goals>
125+
<goal>native-image</goal>
126+
</goals>
127+
<configuration>
128+
<enableHttpUrlHandler>true</enableHttpUrlHandler>
129+
</configuration>
130+
</execution>
131+
</executions>
132+
</plugin>
133+
<plugin>
134+
<artifactId>maven-failsafe-plugin</artifactId>
135+
<version>${surefire-plugin.version}</version>
136+
<executions>
137+
<execution>
138+
<goals>
139+
<goal>integration-test</goal>
140+
<goal>verify</goal>
141+
</goals>
142+
<configuration>
143+
<systemProperties>
144+
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
145+
</systemProperties>
146+
</configuration>
147+
</execution>
148+
</executions>
149+
</plugin>
150+
</plugins>
151+
</build>
152+
</profile>
153+
154+
<!-- there is an issue with JDK12 and Quarkus, see https://github.com/quarkusio/quarkus/issues/1534 -->
155+
<!-- so we will skip the quarkus plugin and tests for now in case jdk >= 12 -->
156+
<profile>
157+
<id>java12+</id>
158+
<activation>
159+
<jdk>[12,)</jdk>
160+
</activation>
161+
<properties>
162+
<maven.test.skip>true</maven.test.skip>
163+
</properties>
164+
<build>
165+
<plugins>
166+
<plugin>
167+
<groupId>io.quarkus</groupId>
168+
<artifactId>quarkus-maven-plugin</artifactId>
169+
<version>${quarkus.version}</version>
170+
<executions>
171+
<execution>
172+
<id>quarkus-build</id>
173+
<phase>none</phase> <!-- invalid phase to disable this execution -->
174+
</execution>
175+
</executions>
176+
</plugin>
177+
</plugins>
178+
</build>
179+
</profile>
180+
</profiles>
181+
</project>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
3+
* and/or other contributors as indicated by the @authors tag. See the
4+
* copyright.txt file in the distribution for a full listing of all
5+
* contributors.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
package org.mapstruct.example.quarkus;
20+
21+
import javax.inject.Inject;
22+
import javax.ws.rs.GET;
23+
import javax.ws.rs.Path;
24+
import javax.ws.rs.Produces;
25+
import javax.ws.rs.core.MediaType;
26+
27+
import org.mapstruct.example.quarkus.mapper.PersonMapper;
28+
import org.mapstruct.example.quarkus.dto.PersonDto;
29+
import org.mapstruct.example.quarkus.service.PersonService;
30+
31+
@Path("/person")
32+
public class PersonResource {
33+
34+
@Inject
35+
PersonService personService;
36+
37+
@Inject
38+
PersonMapper personMapper;
39+
40+
@GET
41+
@Produces(MediaType.APPLICATION_JSON)
42+
public PersonDto loadPerson() {
43+
return personMapper.toResource( personService.loadPerson() );
44+
}
45+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
3+
* and/or other contributors as indicated by the @authors tag. See the
4+
* copyright.txt file in the distribution for a full listing of all
5+
* contributors.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
package org.mapstruct.example.quarkus.dto;
20+
21+
public class PersonDto {
22+
private String firstname;
23+
private String surname;
24+
25+
public String getFirstname() {
26+
return firstname;
27+
}
28+
29+
public void setFirstname(String firstname) {
30+
this.firstname = firstname;
31+
}
32+
33+
public String getSurname() {
34+
return surname;
35+
}
36+
37+
public void setSurname(String surname) {
38+
this.surname = surname;
39+
}
40+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/)
3+
* and/or other contributors as indicated by the @authors tag. See the
4+
* copyright.txt file in the distribution for a full listing of all
5+
* contributors.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
package org.mapstruct.example.quarkus.mapper;
20+
21+
import org.mapstruct.Mapper;
22+
import org.mapstruct.Mapping;
23+
import org.mapstruct.example.quarkus.dto.PersonDto;
24+
import org.mapstruct.example.quarkus.service.Person;
25+
26+
@Mapper(config = QuarkusMappingConfig.class)
27+
public interface PersonMapper {
28+
@Mapping(target = "surname", source = "lastname")
29+
PersonDto toResource(Person person);
30+
}

0 commit comments

Comments
 (0)