Support for records (#499)
Support for records added
Signed-off-by: David Kral <david.k.kral@oracle.com>
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 90e0e46..6f9dc93 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -53,6 +53,6 @@
distribution: 'adopt'
java-version: ${{ matrix.java_version }}
- name: Yasson tests
- run: mvn -U -C -Pstaging test
+ run: mvn -U -C -Pstaging verify
- name: JSONB-API TCK
run: cd yasson-tck && mvn -U -B test
diff --git a/pom.xml b/pom.xml
index 732d89f..2d0057d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -240,6 +240,50 @@
</plugins>
</build>
</profile>
+ <profile>
+ <id>jdk16</id>
+ <activation>
+ <jdk>[16,)</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.8.1</version>
+ <executions>
+ <execution>
+ <id>default-testCompile</id>
+ <configuration>
+ <release>16</release>
+ <compileSourceRoots>
+ <compileSourceRoot>${project.basedir}/src/test/java</compileSourceRoot>
+ <compileSourceRoot>${project.basedir}/src/test/java16</compileSourceRoot>
+ </compileSourceRoots>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <includes>
+ <include>**/RecordTest.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
</profiles>
<build>
@@ -273,6 +317,11 @@
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>3.0.0-M3</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<executions>
@@ -290,7 +339,7 @@
</configuration>
</execution>
<execution>
- <id>multi-release-compile</id>
+ <id>multi-release-compile-9</id>
<goals>
<goal>compile</goal>
</goals>
@@ -303,6 +352,19 @@
</configuration>
</execution>
<execution>
+ <id>multi-release-compile-16</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <release>16</release>
+ <compileSourceRoots>
+ <compileSourceRoot>${project.basedir}/src/main/java16</compileSourceRoot>
+ </compileSourceRoots>
+ <multiReleaseOutput>true</multiReleaseOutput>
+ </configuration>
+ </execution>
+ <execution>
<id>base-compile</id>
<goals>
<goal>compile</goal>
@@ -430,6 +492,7 @@
</executions>
</plugin>
<plugin>
+ <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<executions>
@@ -440,10 +503,12 @@
<goal>test</goal>
</goals>
<configuration>
+<!-- <testFailureIgnore>true</testFailureIgnore>-->
<trimStackTrace>false</trimStackTrace>
<excludes>
- <exclude>**/JavaxNamingExcludedTest.class</exclude>
- <exclude>**/AnnotationIntrospectorWithoutOptionalModulesTest.class</exclude>
+ <exclude>**/JavaxNamingExcludedTest.java</exclude>
+ <exclude>**/AnnotationIntrospectorWithoutOptionalModulesTest.java</exclude>
+ <exclude>**/*Record*</exclude>
</excludes>
<argLine>
<!--Remove when CDI is updated to support modules
diff --git a/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java b/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java
index 97c0010..20359ce 100644
--- a/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java
+++ b/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -148,10 +148,12 @@
* @return JsonbCreator metadata object
*/
public JsonbCreator getCreator(Class<?> clazz) {
- JsonbCreator jsonbCreator = null;
+ JsonbCreator jsonbCreator;
Constructor<?>[] declaredConstructors =
AccessController.doPrivileged((PrivilegedAction<Constructor<?>[]>) clazz::getDeclaredConstructors);
+ jsonbCreator = ClassMultiReleaseExtension.findJsonbCreator(clazz, declaredConstructors, this);
+
for (Constructor<?> constructor : declaredConstructors) {
final jakarta.json.bind.annotation.JsonbCreator annot = findAnnotation(constructor.getDeclaredAnnotations(),
jakarta.json.bind.annotation.JsonbCreator.class);
@@ -180,7 +182,7 @@
return jsonbCreator;
}
- private JsonbCreator createJsonbCreator(Executable executable, JsonbCreator existing, Class<?> clazz) {
+ JsonbCreator createJsonbCreator(Executable executable, JsonbCreator existing, Class<?> clazz) {
if (existing != null) {
throw new JsonbException(Messages.getMessage(MessageKeys.MULTIPLE_JSONB_CREATORS, clazz));
}
diff --git a/src/main/java/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java b/src/main/java/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java
new file mode 100644
index 0000000..9b94193
--- /dev/null
+++ b/src/main/java/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.internal;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import org.eclipse.yasson.internal.model.JsonbCreator;
+
+/**
+ * Search for instance creator from other sources.
+ * Mainly intended to add extensibility for different java versions and new features.
+ */
+class ClassMultiReleaseExtension {
+
+ private ClassMultiReleaseExtension() {
+ throw new IllegalStateException("This class cannot be instantiated");
+ }
+
+ static boolean shouldTransformToPropertyName(Method method) {
+ return true;
+ }
+
+ static boolean isGetAccessorMethod(Method method) {
+ return false;
+ }
+
+ static JsonbCreator findJsonbCreator(Class<?> clazz, Constructor<?>[] declaredConstructors, AnnotationIntrospector introspector) {
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/eclipse/yasson/internal/ClassParser.java b/src/main/java/org/eclipse/yasson/internal/ClassParser.java
index 63ee6e7..1d61b1d 100644
--- a/src/main/java/org/eclipse/yasson/internal/ClassParser.java
+++ b/src/main/java/org/eclipse/yasson/internal/ClassParser.java
@@ -201,7 +201,9 @@
if (!isPropertyMethod(method) || method.isBridge() || isSpecialCaseMethod(clazz, method)) {
continue;
}
- final String propertyName = toPropertyMethod(name);
+ final String propertyName = ClassMultiReleaseExtension.shouldTransformToPropertyName(method)
+ ? toPropertyMethod(name)
+ : name;
registerMethod(propertyName, method, classElement, classProperties);
}
@@ -230,6 +232,9 @@
}
private static boolean isGetter(Method m) {
+ if (ClassMultiReleaseExtension.isGetAccessorMethod(m)) {
+ return true;
+ }
return (m.getName().startsWith(GET_PREFIX) || m.getName().startsWith(IS_PREFIX)) && m.getParameterCount() == 0;
}
@@ -238,7 +243,7 @@
}
private static String toPropertyMethod(String name) {
- return lowerFirstLetter(name.substring(name.startsWith(IS_PREFIX) ? 2 : 3, name.length()));
+ return lowerFirstLetter(name.substring(name.startsWith(IS_PREFIX) ? 2 : 3));
}
private static String lowerFirstLetter(String name) {
diff --git a/src/main/java16/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java b/src/main/java16/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java
new file mode 100644
index 0000000..55adab3
--- /dev/null
+++ b/src/main/java16/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.internal;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Set;
+
+import org.eclipse.yasson.internal.model.JsonbCreator;
+
+/**
+ * Search for instance creator from other sources.
+ * Mainly intended to add extensibility for different java versions and new features.
+ */
+class ClassMultiReleaseExtension {
+
+ private static final Set<String> NOT_VALID_ACCESSOR_METHODS = Set.of("equals", "hashCode", "toString");
+
+ private ClassMultiReleaseExtension() {
+ throw new IllegalStateException("This class cannot be instantiated");
+ }
+
+ static boolean shouldTransformToPropertyName(Method method) {
+ return !method.getDeclaringClass().isRecord();
+ }
+
+ static boolean isGetAccessorMethod(Method method) {
+ if (method.getDeclaringClass().isRecord()) {
+ return !NOT_VALID_ACCESSOR_METHODS.contains(method.getName());
+ }
+ return false;
+ }
+
+ static JsonbCreator findJsonbCreator(Class<?> clazz, Constructor<?>[] declaredConstructors, AnnotationIntrospector introspector) {
+ if (clazz.isRecord()) {
+ return introspector.createJsonbCreator(declaredConstructors[0], null, clazz);
+ }
+ return null;
+ }
+
+}
diff --git a/src/test/java16/org/eclipse/yasson/records/Car.java b/src/test/java16/org/eclipse/yasson/records/Car.java
new file mode 100644
index 0000000..d001315
--- /dev/null
+++ b/src/test/java16/org/eclipse/yasson/records/Car.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.records;
+
+import jakarta.json.bind.annotation.JsonbProperty;
+
+public record Car(@JsonbProperty("typeChanged") String type, @JsonbProperty("colorChanged") String color) {
+}
diff --git a/src/test/java16/org/eclipse/yasson/records/CarWithoutAnnotations.java b/src/test/java16/org/eclipse/yasson/records/CarWithoutAnnotations.java
new file mode 100644
index 0000000..fc1511e
--- /dev/null
+++ b/src/test/java16/org/eclipse/yasson/records/CarWithoutAnnotations.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.records;
+
+public record CarWithoutAnnotations(String type, String color) {
+}
diff --git a/src/test/java16/org/eclipse/yasson/records/RecordTest.java b/src/test/java16/org/eclipse/yasson/records/RecordTest.java
new file mode 100644
index 0000000..0170eac
--- /dev/null
+++ b/src/test/java16/org/eclipse/yasson/records/RecordTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.records;
+
+import org.eclipse.yasson.Jsonbs;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class RecordTest {
+
+ @Test
+ public void testRecordProcessing() {
+ Car car = new Car("skoda", "green");
+ String expected = "{\"colorChanged\":\"green\",\"typeChanged\":\"skoda\"}";
+
+ String json = Jsonbs.defaultJsonb.toJson(car);
+ assertEquals(expected, json);
+ Car deserialized = Jsonbs.defaultJsonb.fromJson(expected, Car.class);
+ assertEquals(car, deserialized);
+ }
+
+ @Test
+ public void testRecordProcessingWithoutJsonbProperties() {
+ CarWithoutAnnotations car = new CarWithoutAnnotations("skoda", "green");
+ String expected = "{\"color\":\"green\",\"type\":\"skoda\"}";
+
+ String json = Jsonbs.defaultJsonb.toJson(car);
+ assertEquals(expected, json);
+ CarWithoutAnnotations deserialized = Jsonbs.defaultJsonb.fromJson(expected, CarWithoutAnnotations.class);
+ assertEquals(car, deserialized);
+ }
+
+}