-
Notifications
You must be signed in to change notification settings - Fork 512
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add simple Quarkus demo application #59
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
175ffbb
Add simple Quarkus demo application
chris922 8eb9f46
Moved component-model from compiler-arg to config
chris922 85a4be9
Cleanup POM
chris922 e861480
Use processor as provided dep, disable tests on jdk >= 12
chris922 ea7b655
Update README.md for Quarkus example
chris922 88e4fbb
Update to Quarkus 0.15.0
chris922 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# MapStruct + Quarkus | ||
|
||
This example demonstrates how easy it is to use MapStruct in a [Quarkus](https://quarkus.io) application. | ||
|
||
The example was basically built with the following steps: | ||
|
||
1. Create a new Quarkus application | ||
|
||
``` | ||
mvn io.quarkus:quarkus-maven-plugin:0.15.0:create \ | ||
-DprojectGroupId=org.mapstruct.examples.quarkus \ | ||
-DprojectArtifactId=mapstruct-examples-quarkus \ | ||
-DclassName="org.mapstruct.example.quarkus.PersonResource" \ | ||
-Dpath="/person" \ | ||
-Dextensions="resteasy-jsonb" | ||
``` | ||
|
||
2. Add the `mapstruct-processor` as a regular `provided` scoped dependency and *not* as described in the | ||
[reference guide](http://mapstruct.org/documentation/dev/reference/html/#_apache_maven) | ||
|
||
```xml | ||
<dependency> | ||
<groupId>org.mapstruct</groupId> | ||
<artifactId>mapstruct-processor</artifactId> | ||
<version>${org.mapstruct.version}</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
``` | ||
|
||
3. Set CDI as the default component-model (see [reference guide](http://mapstruct.org/documentation/dev/reference/html/#configuration-options)) | ||
4. Define a mapper and inject it with `@Inject` in the service | ||
|
||
That's it! | ||
|
||
### Native images | ||
|
||
As MapStruct is not using reflection within the mappers native images are supported as long as CDI is used to retrieve the mappers. | ||
Just try to package your Quarkus application in a native image and feel the speed! | ||
|
||
``` | ||
mvn package -Dnative | ||
``` | ||
|
||
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 | ||
retrieve the mapper implementation. | ||
This is the only place where MapStruct uses reflection and thus it causes issues with native images. | ||
|
||
There are some workarounds by defining additional metadata used during native image creation by GraalVM. For example you can create a `Feature` as described | ||
[here](https://github.com/oracle/graal/blob/master/substratevm/REFLECTION.md) and register all you mapper implementations and their constructor(s). | ||
|
||
For example if you just have a `FoobarMapper` the feature might look like this: | ||
|
||
```java | ||
@AutomaticFeature | ||
class MapstructMapperFeature implements Feature { | ||
public void beforeAnalysis(BeforeAnalysisAccess access) { | ||
try { | ||
RuntimeReflection.register(FoobarMapperImpl.class); | ||
RuntimeReflection.register(FoobarMapperImpl.class.getConstructors()); | ||
} catch (NoSuchMethodException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} | ||
``` | ||
|
||
_(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)_ | ||
|
||
|
||
### One drawback | ||
|
||
When using the Quarkus dev mode the mapper will automatically be (re)generated in case you make change to the `@Mapper` annotated class. | ||
Changing a dependent class (like `PersonDto` in this example) will not (re)generate the mapper implementation. | ||
|
||
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 | ||
will be picked up and a valid implementation will be generated. | ||
|
||
*Pay attention*: You have to add the mapstruct-processor as described above and *not* using the `maven-compile-plugin`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
<?xml version="1.0"?> | ||
<!-- | ||
|
||
Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) | ||
and/or other contributors as indicated by the @authors tag. See the | ||
copyright.txt file in the distribution for a full listing of all | ||
contributors. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
|
||
--> | ||
<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" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<groupId>org.mapstruct.examples.quarkus</groupId> | ||
<artifactId>mapstruct-examples-quarkus</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
|
||
<properties> | ||
<surefire-plugin.version>2.22.0</surefire-plugin.version> | ||
<quarkus.version>0.15.0</quarkus.version> | ||
<org.mapstruct.version>1.3.0.Final</org.mapstruct.version> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
<maven.compiler.source>1.8</maven.compiler.source> | ||
<maven.compiler.target>1.8</maven.compiler.target> | ||
</properties> | ||
|
||
<dependencyManagement> | ||
<dependencies> | ||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-bom</artifactId> | ||
<version>${quarkus.version}</version> | ||
<type>pom</type> | ||
<scope>import</scope> | ||
</dependency> | ||
</dependencies> | ||
</dependencyManagement> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.mapstruct</groupId> | ||
<artifactId>mapstruct</artifactId> | ||
<version>${org.mapstruct.version}</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-resteasy-jsonb</artifactId> | ||
</dependency> | ||
chris922 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-junit5</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
chris922 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<dependency> | ||
<groupId>io.rest-assured</groupId> | ||
<artifactId>rest-assured</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.mapstruct</groupId> | ||
<artifactId>mapstruct-processor</artifactId> | ||
<version>${org.mapstruct.version}</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-maven-plugin</artifactId> | ||
<version>${quarkus.version}</version> | ||
<executions> | ||
<execution> | ||
<id>quarkus-build</id> | ||
<goals> | ||
<goal>build</goal> | ||
</goals> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
<plugin> | ||
<artifactId>maven-surefire-plugin</artifactId> | ||
<version>${surefire-plugin.version}</version> | ||
<configuration> | ||
<systemProperties> | ||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> | ||
</systemProperties> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
<profiles> | ||
<profile> | ||
<id>native</id> | ||
<activation> | ||
<property> | ||
<name>native</name> | ||
</property> | ||
</activation> | ||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-maven-plugin</artifactId> | ||
<version>${quarkus.version}</version> | ||
<executions> | ||
<execution> | ||
<goals> | ||
<goal>native-image</goal> | ||
</goals> | ||
<configuration> | ||
<enableHttpUrlHandler>true</enableHttpUrlHandler> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
<plugin> | ||
<artifactId>maven-failsafe-plugin</artifactId> | ||
<version>${surefire-plugin.version}</version> | ||
<executions> | ||
<execution> | ||
<goals> | ||
<goal>integration-test</goal> | ||
<goal>verify</goal> | ||
</goals> | ||
<configuration> | ||
<systemProperties> | ||
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path> | ||
</systemProperties> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</profile> | ||
|
||
<!-- there is an issue with JDK12 and Quarkus, see https://github.com/quarkusio/quarkus/issues/1534 --> | ||
<!-- so we will skip the quarkus plugin and tests for now in case jdk >= 12 --> | ||
<profile> | ||
<id>java12+</id> | ||
<activation> | ||
<jdk>[12,)</jdk> | ||
</activation> | ||
<properties> | ||
<maven.test.skip>true</maven.test.skip> | ||
</properties> | ||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-maven-plugin</artifactId> | ||
<version>${quarkus.version}</version> | ||
<executions> | ||
<execution> | ||
<id>quarkus-build</id> | ||
<phase>none</phase> <!-- invalid phase to disable this execution --> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</profile> | ||
</profiles> | ||
</project> |
45 changes: 45 additions & 0 deletions
45
mapstruct-quarkus/src/main/java/org/mapstruct/example/quarkus/PersonResource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/** | ||
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) | ||
* and/or other contributors as indicated by the @authors tag. See the | ||
* copyright.txt file in the distribution for a full listing of all | ||
* contributors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.mapstruct.example.quarkus; | ||
|
||
import javax.inject.Inject; | ||
import javax.ws.rs.GET; | ||
import javax.ws.rs.Path; | ||
import javax.ws.rs.Produces; | ||
import javax.ws.rs.core.MediaType; | ||
|
||
import org.mapstruct.example.quarkus.mapper.PersonMapper; | ||
import org.mapstruct.example.quarkus.dto.PersonDto; | ||
import org.mapstruct.example.quarkus.service.PersonService; | ||
|
||
@Path("/person") | ||
public class PersonResource { | ||
|
||
@Inject | ||
PersonService personService; | ||
|
||
@Inject | ||
PersonMapper personMapper; | ||
|
||
@GET | ||
@Produces(MediaType.APPLICATION_JSON) | ||
public PersonDto loadPerson() { | ||
return personMapper.toResource( personService.loadPerson() ); | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
mapstruct-quarkus/src/main/java/org/mapstruct/example/quarkus/dto/PersonDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/** | ||
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) | ||
* and/or other contributors as indicated by the @authors tag. See the | ||
* copyright.txt file in the distribution for a full listing of all | ||
* contributors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.mapstruct.example.quarkus.dto; | ||
|
||
public class PersonDto { | ||
private String firstname; | ||
private String surname; | ||
|
||
public String getFirstname() { | ||
return firstname; | ||
} | ||
|
||
public void setFirstname(String firstname) { | ||
this.firstname = firstname; | ||
} | ||
|
||
public String getSurname() { | ||
return surname; | ||
} | ||
|
||
public void setSurname(String surname) { | ||
this.surname = surname; | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
mapstruct-quarkus/src/main/java/org/mapstruct/example/quarkus/mapper/PersonMapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/** | ||
* Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) | ||
* and/or other contributors as indicated by the @authors tag. See the | ||
* copyright.txt file in the distribution for a full listing of all | ||
* contributors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.mapstruct.example.quarkus.mapper; | ||
|
||
import org.mapstruct.Mapper; | ||
import org.mapstruct.Mapping; | ||
import org.mapstruct.example.quarkus.dto.PersonDto; | ||
import org.mapstruct.example.quarkus.service.Person; | ||
|
||
@Mapper(config = QuarkusMappingConfig.class) | ||
public interface PersonMapper { | ||
@Mapping(target = "surname", source = "lastname") | ||
PersonDto toResource(Person person); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me summon @gsmet on this one; Guillaume, what's the Quarkus way to enable a reflective usage like this with an extension in a generic way? Some background: while MapStruct generally avoids the usage of reflection, there's a single place where it's optionally used when not working with CDI or Spring: obtaining a mapper implementation. The calling code in user apps looks like this:
MapStruct's
getInstance()
method essentially doesreturn Class.forName(passedClass.getName() + ".Impl").newInstance()
;IIUC, we could enable this usage by defining a Quarkus extension in a generic way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I played a bit around with a few ideas I had to find a generic way.. the only idea left that looks promising is to extend our processor to create something like a list of mappers (e. g. just line-by-line in a new file
META-INF/mapstruct.mappers
), access this list in aFeature
and register all these classes.I was working on a PoC for this and it seems to work. Maybe it is also possible to include this
Feature
in the MapStruct library having the graalvm/substratevm dependencies marked asoptional
orprovided
. As this class will not be accessed outside from SubstrateVM it shouldn't make any troubles if it is just available somewhere in the JAR.Another idea I had was to use the
ServiceLoader
as I thought theMETA-INF/services/*
files are maybe already analyzed by the SubstrateVM... but unfortunately this was not the case. Even more worse: When these service files will be used to register the classes for reflection during native-image build it is additionally required to add a property during native-image build to include these service files in the image. Otherwise theServiceLoader
is not able to find them.The other way described on GraalVM pages to enable reflection would be to create a JSON containing all the mappers and add a build property to load this JSON. But I don't like to have the need to modify build parameters, so I prefer the
AutomaticFeature
way.Regarding the Quarkus extension: Writing such an extension would probably the best way to support Quarkus. But maybe we can even find a way to support the GraalVM native-image in general?