-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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 support for Jackson's JsonPOJOBuilder #3688
Merged
Merged
Changes from all commits
Commits
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
59 changes: 56 additions & 3 deletions
59
...ions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.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 |
---|---|---|
@@ -1,16 +1,69 @@ | ||
package io.quarkus.jackson.deployment; | ||
|
||
import java.util.Collection; | ||
|
||
import javax.inject.Inject; | ||
|
||
import org.jboss.jandex.*; | ||
|
||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; | ||
|
||
import io.quarkus.deployment.annotations.BuildProducer; | ||
import io.quarkus.deployment.annotations.BuildStep; | ||
import io.quarkus.deployment.builditem.CombinedIndexBuildItem; | ||
import io.quarkus.deployment.builditem.substrate.ReflectiveClassBuildItem; | ||
import io.quarkus.deployment.builditem.substrate.ReflectiveHierarchyBuildItem; | ||
|
||
public class JacksonProcessor { | ||
|
||
private static final DotName JSON_DESERIALIZE = DotName.createSimple(JsonDeserialize.class.getName()); | ||
private static final DotName BUILDER_VOID = DotName.createSimple(Void.class.getName()); | ||
|
||
@Inject | ||
BuildProducer<ReflectiveClassBuildItem> reflectiveClass; | ||
|
||
@Inject | ||
BuildProducer<ReflectiveHierarchyBuildItem> reflectiveHierarchyClass; | ||
|
||
@Inject | ||
CombinedIndexBuildItem combinedIndexBuildItem; | ||
|
||
@BuildStep | ||
void register(BuildProducer<ReflectiveClassBuildItem> reflectiveClass) { | ||
reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, | ||
void register() { | ||
addReflectiveClass(true, false, | ||
"com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector", | ||
"com.fasterxml.jackson.databind.ser.std.SqlDateSerializer")); | ||
"com.fasterxml.jackson.databind.ser.std.SqlDateSerializer"); | ||
|
||
IndexView index = combinedIndexBuildItem.getIndex(); | ||
|
||
// TODO: Here we only check for @JsonDeserialize to detect both Model and Builder | ||
// classes to support @JsonPojoBuilder. The @JsonDeserialize annotiona can | ||
// also be used for other scenarios than builder beside adding just the class | ||
// no other scenarios are supported (like when the annotation is place on | ||
// methods). | ||
|
||
Collection<AnnotationInstance> pojoBuilderInstances = index.getAnnotations(JSON_DESERIALIZE); | ||
for (AnnotationInstance pojoBuilderInstance : pojoBuilderInstances) { | ||
if (AnnotationTarget.Kind.CLASS.equals(pojoBuilderInstance.target().kind())) { | ||
addReflectiveHierarchyClass(pojoBuilderInstance.target().asClass().name()); | ||
|
||
AnnotationValue annotationValue = pojoBuilderInstance.value("builder"); | ||
if (null != annotationValue && AnnotationValue.Kind.CLASS.equals(annotationValue.kind())) { | ||
DotName builderClassName = annotationValue.asClass().name(); | ||
if (!BUILDER_VOID.equals(builderClassName)) { | ||
addReflectiveHierarchyClass(builderClassName); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void addReflectiveHierarchyClass(DotName className) { | ||
Type jandexType = Type.create(className, Type.Kind.CLASS); | ||
reflectiveHierarchyClass.produce(new ReflectiveHierarchyBuildItem(jandexType)); | ||
} | ||
|
||
private void addReflectiveClass(boolean methods, boolean fields, String... className) { | ||
reflectiveClass.produce(new ReflectiveClassBuildItem(methods, fields, className)); | ||
} | ||
} |
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,124 @@ | ||
# Quarkus Jackson extension tester | ||
misl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
This project verifies Jackson (de-)serialization support in native mode. | ||
|
||
This project consists of the following modules: | ||
|
||
- model | ||
|
||
This module contains the library with a simple models. This model makes use | ||
of Jackson to support (de-)serialization to JSON. Various forms of models | ||
exists. At the time of writing the following models are present/tested: | ||
- Immutable models using a Builder to construct new instances. | ||
- Simple POJO model being registered for reflection. | ||
|
||
Unit tests are available to prove JVM based JSON (de-)serialization works | ||
properly. | ||
|
||
- service | ||
|
||
This module contains a very simple RESTful resources with only a POST method | ||
to POST new models to this service. A simple unit test is included to verify | ||
correct behaviour for both unit and integration test. | ||
|
||
The following curl command can be used to send POST request to this service: | ||
|
||
``` | ||
curl -X POST -H "Content-Type: application/json" \ | ||
-d '{"version": 2, "id": "123", "value": "val"}' \ | ||
-v localhost:8080/<model-type> | ||
``` | ||
|
||
|
||
## Build | ||
|
||
To build the project, run the following command from the project root directory: | ||
|
||
``` | ||
mvn clean package | ||
``` | ||
|
||
This build should run correctly showing no errors and no test failures. | ||
|
||
For the remainder make the service module your current working directory: | ||
|
||
``` | ||
cd service | ||
``` | ||
|
||
## Package JVM | ||
|
||
Running a JVM based version of the service can either be done with `quarkus:dev` | ||
or by using the JVM based runner. | ||
|
||
- **Using `quarkus:dev`** | ||
``` | ||
mvn quarkus:dev | ||
``` | ||
|
||
- **Using JVM runner** | ||
``` | ||
java -jar target/service-999-SNAPSHOT-runner.jar | ||
``` | ||
|
||
In either case posting new model data like described earlier should result in | ||
a successful `201` response code with the posted message in the body. For example: | ||
|
||
``` | ||
~$ curl -X POST -H "Content-Type: application/json" -d '{"version": 2, "id": "123", "value": "val"}' -v localhost:8080/model | ||
Note: Unnecessary use of -X or --request, POST is already inferred. | ||
* Trying 127.0.0.1... | ||
* TCP_NODELAY set | ||
* Connected to localhost (127.0.0.1) port 8080 (#0) | ||
> POST /model HTTP/1.1 | ||
> Host: localhost:8080 | ||
> User-Agent: curl/7.58.0 | ||
> Accept: */* | ||
> Content-Type: application/json | ||
> Content-Length: 43 | ||
> | ||
* upload completely sent off: 43 out of 43 bytes | ||
< HTTP/1.1 201 Created | ||
< Connection: keep-alive | ||
< Content-Type: application/json | ||
< Content-Length: 38 | ||
< Date: Thu, 22 Aug 2019 13:31:48 GMT | ||
< | ||
* Connection #0 to host localhost left intact | ||
{"version":2,"id":"123","value":"val"} | ||
``` | ||
|
||
## Package Native | ||
|
||
Checking proper behaviour can be achieved in the following 2 ways: | ||
|
||
- **Integration test** | ||
|
||
This scenario requires no additional manual steps besides | ||
executing the following command: | ||
|
||
``` | ||
mvn integration-test verify -Pnative | ||
``` | ||
|
||
The application will be started automatically and test | ||
scenario's will run. The output will indicate whether the | ||
test ran successfully or not. | ||
|
||
In this scenario it is not possible to post new model data | ||
manually. This can be achieved by using the next scenario. | ||
|
||
- **Native runner** | ||
|
||
Running the native version of the service manually like: | ||
|
||
``` | ||
mvn package -Pnative | ||
... | ||
./target/service-999-SNAPSHOT-runner | ||
``` | ||
|
||
Now the application is running new model data can be posted | ||
like described earlier. This should result in a successful | ||
`201` response code with the posted message in the response | ||
body. Just like the JVM example given previously. |
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,108 @@ | ||
<?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/maven-v4_0_0.xsd" | ||
> | ||
|
||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<artifactId>quarkus-integration-test-jackson-parent</artifactId> | ||
<groupId>io.quarkus</groupId> | ||
<version>999-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>quarkus-integration-test-jackson-model</artifactId> | ||
|
||
<name>Quarkus - Integration Tests - Jackson - model</name> | ||
|
||
<properties> | ||
<jackson.version>2.9.9.20190807</jackson.version> | ||
</properties> | ||
|
||
<dependencyManagement> | ||
<dependencies> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson</groupId> | ||
<artifactId>jackson-bom</artifactId> | ||
<version>${jackson.version}</version> | ||
<scope>import</scope> | ||
<type>pom</type> | ||
</dependency> | ||
</dependencies> | ||
</dependencyManagement> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>io.quarkus</groupId> | ||
<artifactId>quarkus-core</artifactId> | ||
</dependency> | ||
|
||
<!-- SLF4J --> | ||
<dependency> | ||
<groupId>org.slf4j</groupId> | ||
<artifactId>slf4j-api</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>com.fasterxml.jackson.core</groupId> | ||
<artifactId>jackson-core</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.core</groupId> | ||
<artifactId>jackson-databind</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.module</groupId> | ||
<artifactId>jackson-module-parameter-names</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.datatype</groupId> | ||
<artifactId>jackson-datatype-jdk8</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.datatype</groupId> | ||
<artifactId>jackson-datatype-jsr310</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.junit.jupiter</groupId> | ||
<artifactId>junit-jupiter-api</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.junit.jupiter</groupId> | ||
<artifactId>junit-jupiter-params</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.junit.jupiter</groupId> | ||
<artifactId>junit-jupiter-engine</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.assertj</groupId> | ||
<artifactId>assertj-core</artifactId> | ||
<version>3.12.2</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-surefire-plugin</artifactId> | ||
<configuration> | ||
<useSystemClassLoader>false</useSystemClassLoader> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
</project> |
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.
There is a typo in
annotationa
. Also the sentence could possible be expressed in a more clear manner, but it's definitely not something to hold up the PR for :)