Skip to content

Commit 0f08eca

Browse files
#1351: Add missing @JsonProperty to setter methods for POJOs (#1355)
* Update templates to support @JsonProperty for setters and add tests for @JsonProperty handling in getters and setters * Replace qualified names with class import for JsonProperty
1 parent d261309 commit 0f08eca

File tree

7 files changed

+372
-0
lines changed

7 files changed

+372
-0
lines changed

client/deployment/src/main/resources/templates/libraries/microprofile/pojo.qute

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public class {m.classname} {#if m.parent}extends {m.parent}{/if}{#if serializabl
8585
/**
8686
* Set {v.name}
8787
**/
88+
@JsonProperty("{v.baseName}")
8889
public void {v.setter}({v.datatypeWithEnum} {v.name}) {
8990
this.{v.name} = {v.name};
9091
}

client/deployment/src/main/resources/templates/libraries/microprofile/pojoQueryParam.qute

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
/**
7575
* Set {v.name}
7676
**/
77+
@com.fasterxml.jackson.annotation.JsonProperty("{v.baseName}")
7778
public void {v.setter}({v.datatypeWithEnum} {v.name}) {
7879
this.{v.name} = {v.name};
7980
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
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" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<parent>
4+
<artifactId>quarkus-openapi-generator-integration-tests</artifactId>
5+
<groupId>io.quarkiverse.openapi.generator</groupId>
6+
<version>3.0.0-SNAPSHOT</version>
7+
</parent>
8+
<modelVersion>4.0.0</modelVersion>
9+
10+
<artifactId>quarkus-openapi-generator-it-jsonproperty-getter-and-setter</artifactId>
11+
<name>Quarkus - OpenAPI Generator - Integration Tests - Client - @JsonProperty for getters and setters</name>
12+
<description>Ensures that @JsonProperty is properly added to getters and setters</description>
13+
14+
<dependencies>
15+
<dependency>
16+
<groupId>io.quarkiverse.openapi.generator</groupId>
17+
<artifactId>quarkus-openapi-generator</artifactId>
18+
</dependency>
19+
<dependency>
20+
<groupId>org.assertj</groupId>
21+
<artifactId>assertj-core</artifactId>
22+
<scope>test</scope>
23+
</dependency>
24+
<dependency>
25+
<groupId>io.quarkus</groupId>
26+
<artifactId>quarkus-junit5</artifactId>
27+
<scope>test</scope>
28+
</dependency>
29+
</dependencies>
30+
<build>
31+
<plugins>
32+
<plugin>
33+
<groupId>io.quarkus</groupId>
34+
<artifactId>quarkus-maven-plugin</artifactId>
35+
<extensions>true</extensions>
36+
<executions>
37+
<execution>
38+
<goals>
39+
<goal>build</goal>
40+
<goal>generate-code</goal>
41+
<goal>generate-code-tests</goal>
42+
</goals>
43+
</execution>
44+
</executions>
45+
</plugin>
46+
</plugins>
47+
</build>
48+
<profiles>
49+
<profile>
50+
<id>native-image</id>
51+
<activation>
52+
<property>
53+
<name>native</name>
54+
</property>
55+
</activation>
56+
<build>
57+
<plugins>
58+
<plugin>
59+
<artifactId>maven-surefire-plugin</artifactId>
60+
<configuration>
61+
<skipTests>${native.surefire.skip}</skipTests>
62+
</configuration>
63+
</plugin>
64+
<plugin>
65+
<artifactId>maven-failsafe-plugin</artifactId>
66+
<executions>
67+
<execution>
68+
<goals>
69+
<goal>integration-test</goal>
70+
<goal>verify</goal>
71+
</goals>
72+
<configuration>
73+
<systemPropertyVariables>
74+
<native.image.path>
75+
${project.build.directory}/${project.build.finalName}-runner
76+
</native.image.path>
77+
<java.util.logging.manager>org.jboss.logmanager.LogManager
78+
</java.util.logging.manager>
79+
<maven.home>${maven.home}</maven.home>
80+
</systemPropertyVariables>
81+
</configuration>
82+
</execution>
83+
</executions>
84+
</plugin>
85+
</plugins>
86+
</build>
87+
<properties>
88+
<quarkus.package.type>native</quarkus.package.type>
89+
</properties>
90+
</profile>
91+
</profiles>
92+
93+
</project>
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
{
2+
"openapi": "3.0.2",
3+
"info": {
4+
"title": "Animals - OpenAPI 3.0",
5+
"version": "1.0.5"
6+
},
7+
"servers": [
8+
{
9+
"url": "/api/v3"
10+
}
11+
],
12+
"tags": [
13+
{
14+
"name": "primate",
15+
"description": "Everything about Primates"
16+
}
17+
],
18+
"paths": {
19+
"/primate/{id}": {
20+
"get": {
21+
"tags": [
22+
"primate"
23+
],
24+
"summary": "Find primate by ID",
25+
"description": "Returns a single primate",
26+
"operationId": "getPrimateById",
27+
"parameters": [
28+
{
29+
"name": "id",
30+
"in": "path",
31+
"description": "ID of primate to return",
32+
"required": true,
33+
"schema": {
34+
"type": "integer",
35+
"format": "int64"
36+
}
37+
}
38+
],
39+
"responses": {
40+
"200": {
41+
"description": "successful operation",
42+
"content": {
43+
"application/json": {
44+
"schema": {
45+
"$ref": "#/components/schemas/Primate"
46+
}
47+
}
48+
}
49+
},
50+
"400": {
51+
"description": "Invalid ID supplied"
52+
},
53+
"404": {
54+
"description": "Primate not found"
55+
}
56+
}
57+
}
58+
}
59+
},
60+
"components": {
61+
"schemas": {
62+
"Animal": {
63+
"type": "object",
64+
"properties": {
65+
"born": {
66+
"type": "string",
67+
"description": "Dated Base extension.",
68+
"format": "date-time"
69+
},
70+
"deceased": {
71+
"type": "string",
72+
"description": "Dated Base extension.",
73+
"format": "date-time"
74+
},
75+
"animal_name": {
76+
"type": "string",
77+
"description": "Animal name"
78+
}
79+
},
80+
"xml": {
81+
"name": "animal"
82+
}
83+
},
84+
"Mammal": {
85+
"type": "object",
86+
"allOf": [ {
87+
"$ref": "#/components/schemas/Animal"
88+
} ],
89+
"properties": {
90+
"gender": {
91+
"type": "string",
92+
"enum": [
93+
"female",
94+
"male"
95+
]
96+
}
97+
},
98+
"xml": {
99+
"name": "mammal"
100+
}
101+
},
102+
"Primate": {
103+
"required": [
104+
"name"
105+
],
106+
"type": "object",
107+
"allOf": [
108+
{
109+
"$ref": "#/components/schemas/Mammal"
110+
}
111+
],
112+
"properties": {
113+
"id": {
114+
"type": "integer",
115+
"format": "int64",
116+
"example": 10
117+
},
118+
"name": {
119+
"type": "string",
120+
"example": "jane doe"
121+
}
122+
},
123+
"xml": {
124+
"name": "primate"
125+
}
126+
}
127+
}
128+
}
129+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
quarkus.openapi-generator.codegen.spec.jsonproperty_openapi_yaml.base-package=org.acme.jsonproperty.gettersetter
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package io.quarkiverse.openapi.generator.it;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.time.format.DateTimeFormatter;
6+
import java.time.format.DateTimeFormatterBuilder;
7+
8+
import jakarta.json.Json;
9+
import jakarta.json.JsonObjectBuilder;
10+
11+
import org.acme.jsonproperty.gettersetter.model.Animal;
12+
import org.acme.jsonproperty.gettersetter.model.Mammal;
13+
import org.acme.jsonproperty.gettersetter.model.Primate;
14+
import org.junit.jupiter.api.BeforeAll;
15+
import org.junit.jupiter.api.Test;
16+
17+
import com.fasterxml.jackson.annotation.JsonProperty;
18+
import com.fasterxml.jackson.databind.ObjectMapper;
19+
20+
import io.quarkus.test.junit.QuarkusTest;
21+
22+
@QuarkusTest
23+
class JsonPropertyGetterSetterTest {
24+
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
25+
26+
@BeforeAll
27+
static void setup() {
28+
OBJECT_MAPPER.findAndRegisterModules();
29+
}
30+
31+
@Test
32+
void verifyGetterSetterWorksOnSnakeCasedFields() {
33+
JsonObjectBuilder jsonObjectBuilder = Json.createObjectBuilder();
34+
jsonObjectBuilder.add("animal_name", "Lion");
35+
36+
Animal animal;
37+
try {
38+
animal = OBJECT_MAPPER.readValue(jsonObjectBuilder.build().toString(), Animal.class);
39+
} catch (Exception e) {
40+
throw new RuntimeException(e);
41+
}
42+
43+
assertEquals(Animal.class, animal.getClass());
44+
assertEquals("Lion", animal.getAnimalName());
45+
}
46+
47+
@Test
48+
void verifyGetterSetterWorksOnNonSnakeCasedFields() {
49+
JsonObjectBuilder jsonObjectBuilder = Json.createObjectBuilder();
50+
// OffsetDateTime field to verify that non-snake-cased fields also work
51+
jsonObjectBuilder.add("born", "2020-01-01T00:00:00Z");
52+
53+
Animal animal;
54+
try {
55+
animal = OBJECT_MAPPER.readValue(jsonObjectBuilder.build().toString(), Animal.class);
56+
} catch (Exception e) {
57+
throw new RuntimeException(e);
58+
}
59+
60+
assertEquals(Animal.class, animal.getClass());
61+
DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendInstant().toFormatter();
62+
assertEquals("2020-01-01T00:00:00Z", animal.getBorn().format(formatter));
63+
}
64+
65+
@Test
66+
void verifyJavaReflectionIndicatesJsonPropertyOnSettersAndGetters() {
67+
try {
68+
var getter = Animal.class.getMethod("getAnimalName");
69+
var setter = Animal.class.getMethod("setAnimalName", String.class);
70+
71+
var getterAnnotation = getter.getAnnotation(JsonProperty.class);
72+
var setterAnnotation = setter.getAnnotation(JsonProperty.class);
73+
74+
assertEquals("animal_name", getterAnnotation.value());
75+
assertEquals("animal_name", setterAnnotation.value());
76+
} catch (NoSuchMethodException e) {
77+
throw new RuntimeException(e);
78+
}
79+
try {
80+
var getter = Primate.class.getMethod("getAnimalName");
81+
var setter = Primate.class.getMethod("setAnimalName", String.class);
82+
83+
var getterAnnotation = getter.getAnnotation(JsonProperty.class);
84+
var setterAnnotation = setter.getAnnotation(JsonProperty.class);
85+
86+
assertEquals("animal_name", getterAnnotation.value());
87+
assertEquals("animal_name", setterAnnotation.value());
88+
} catch (NoSuchMethodException e) {
89+
throw new RuntimeException(e);
90+
}
91+
try {
92+
var getter = Mammal.class.getMethod("getAnimalName");
93+
var setter = Mammal.class.getMethod("setAnimalName", String.class);
94+
95+
var getterAnnotation = getter.getAnnotation(JsonProperty.class);
96+
var setterAnnotation = setter.getAnnotation(JsonProperty.class);
97+
98+
assertEquals("animal_name", getterAnnotation.value());
99+
assertEquals("animal_name", setterAnnotation.value());
100+
} catch (NoSuchMethodException e) {
101+
throw new RuntimeException(e);
102+
}
103+
}
104+
105+
@Test
106+
void verifyJavaReflectionIndicatesJsonPropertyOnSettersAndGettersQueryParam() {
107+
try {
108+
var getter = Animal.AnimalQueryParam.class.getMethod("getAnimalName");
109+
var setter = Animal.AnimalQueryParam.class.getMethod("setAnimalName", String.class);
110+
111+
var getterAnnotation = getter.getAnnotation(JsonProperty.class);
112+
var setterAnnotation = setter.getAnnotation(JsonProperty.class);
113+
114+
assertEquals("animal_name", getterAnnotation.value());
115+
assertEquals("animal_name", setterAnnotation.value());
116+
} catch (NoSuchMethodException e) {
117+
throw new RuntimeException(e);
118+
}
119+
120+
try {
121+
var getter = Mammal.MammalQueryParam.class.getMethod("getAnimalName");
122+
var setter = Mammal.MammalQueryParam.class.getMethod("setAnimalName", String.class);
123+
124+
var getterAnnotation = getter.getAnnotation(JsonProperty.class);
125+
var setterAnnotation = setter.getAnnotation(JsonProperty.class);
126+
127+
assertEquals("animal_name", getterAnnotation.value());
128+
assertEquals("animal_name", setterAnnotation.value());
129+
} catch (NoSuchMethodException e) {
130+
throw new RuntimeException(e);
131+
}
132+
133+
try {
134+
var getter = Primate.PrimateQueryParam.class.getMethod("getAnimalName");
135+
var setter = Primate.PrimateQueryParam.class.getMethod("setAnimalName", String.class);
136+
137+
var getterAnnotation = getter.getAnnotation(JsonProperty.class);
138+
var setterAnnotation = setter.getAnnotation(JsonProperty.class);
139+
140+
assertEquals("animal_name", getterAnnotation.value());
141+
assertEquals("animal_name", setterAnnotation.value());
142+
} catch (NoSuchMethodException e) {
143+
throw new RuntimeException(e);
144+
}
145+
}
146+
}

client/integration-tests/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
<module>serializable-model</module>
5050
<module>equals-hashcode</module>
5151
<module>override-credential-provider</module>
52+
<module>jsonproperty-getter-and-setter</module>
5253
</modules>
5354
<dependencyManagement>
5455
<dependencies>

0 commit comments

Comments
 (0)