Record processing backport (#531)
Record processing backport
Signed-off-by: David Kral <david.k.kral@oracle.com>
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
new file mode 100644
index 0000000..6019b64
--- /dev/null
+++ b/.github/workflows/maven.yml
@@ -0,0 +1,56 @@
+#
+# Copyright (c) 2022 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
+#
+
+name: Yasson
+
+on: [push, pull_request]
+
+jobs:
+ build:
+ name: Test on JDK ${{ matrix.java_version }}
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ java_version: [ 11, 17 ]
+
+ steps:
+ - name: Checkout for build
+ uses: actions/checkout@v2.3.4
+ with:
+ fetch-depth: 0
+ - name: Set up compile JDK
+ uses: actions/setup-java@v2
+ with: #Compile java needs to be the highest to ensure proper compilation of the multi-release jar
+ distribution: 'adopt'
+ java-version: 17
+ - name: Maven cache
+ uses: actions/cache@v2
+ env:
+ cache-name: maven-cache
+ with:
+ path:
+ ~/.m2
+ key: build-${{ env.cache-name }}
+ - name: Copyright
+ run: bash etc/copyright.sh
+ - name: Checkstyle
+ run: mvn -B -Pstaging checkstyle:checkstyle
+ - name: Yasson install
+ run: mvn -U -C -Pstaging clean install -DskipTests
+ - name: Set up JDK for tests
+ uses: actions/setup-java@v2
+ with:
+ distribution: 'adopt'
+ java-version: ${{ matrix.java_version }}
+ - name: Yasson tests
+ run: mvn -U -C -Dmaven.javadoc.skip=true -Pstaging verify
diff --git a/pom.xml b/pom.xml
index 385d30e..3baa8a2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2016, 2022 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
@@ -36,6 +36,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jakarta.json.version>1.1.6</jakarta.json.version>
<jakarta.json.bind.version>1.0.2</jakarta.json.bind.version>
+ <jakarta.enterprise.cdi-api.version>2.0.2</jakarta.enterprise.cdi-api.version>
<netbeans.hint.jdkPlatform>JDK_9</netbeans.hint.jdkPlatform>
</properties>
@@ -62,7 +63,7 @@
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
- <version>2.0.2</version>
+ <version>${jakarta.enterprise.cdi-api.version}</version>
<optional>true</optional>
<scope>provided</scope>
</dependency>
@@ -222,6 +223,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>
@@ -255,6 +300,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>
@@ -272,6 +322,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>
@@ -305,6 +368,9 @@
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ <manifestEntries>
+ <Multi-Release>true</Multi-Release>
+ </manifestEntries>
</archive>
</configuration>
</plugin>
@@ -366,7 +432,7 @@
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <version>3.5.0</version>
+ <version>5.1.1</version>
<executions>
<execution>
<id>osgi-bundle</id>
@@ -375,13 +441,14 @@
<goal>manifest</goal>
</goals>
<configuration>
+ <niceManifest>true</niceManifest>
<instructions>
- <_failok>true</_failok>
<Bundle-Name>${project.name}</Bundle-Name>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Bundle-Version>${project.version}</Bundle-Version>
<Export-Package>org.eclipse.yasson;version=${project.version}</Export-Package>
<Private-Package>org.eclipse.yasson.*;version=${project.version}</Private-Package>
+ <Multi-Release>true</Multi-Release>
<Import-Package>
javax.enterprise.context.spi;version=!;resolution:="optional",
javax.enterprise.inject.spi;version=!;resolution:="optional",
@@ -396,6 +463,7 @@
</executions>
</plugin>
<plugin>
+ <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<executions>
@@ -410,12 +478,14 @@
<excludes>
<exclude>**/JavaxNamingExcludedTest.class</exclude>
<exclude>**/AnnotationIntrospectorWithoutOptionalModulesTest.class</exclude>
+ <exclude>**/*Record*</exclude>
</excludes>
<argLine>
<!--Remove when CDI is updated to support modules
(Yasson does read CDI which is on CP, CDI access yasson's classes with reflection)
-->
--add-reads org.eclipse.yasson=ALL-UNNAMED --add-opens org.eclipse.yasson/org.eclipse.yasson.internal.cdi=ALL-UNNAMED
+ --add-opens=java.base/java.lang=ALL-UNNAMED
--add-exports org.eclipse.yasson/org.eclipse.yasson.internal.cdi=java.naming
</argLine>
diff --git a/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java b/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java
index d10b5a1..a0ab13f 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, 2022 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
@@ -175,12 +175,15 @@
}
}
if (jsonbCreator == null) {
- jsonbCreator = constructorPropertiesIntrospector.getCreator(declaredConstructors);
+ jsonbCreator = ClassMultiReleaseExtension.findCreator(clazz, declaredConstructors, this);
+ if (jsonbCreator == null) {
+ jsonbCreator = constructorPropertiesIntrospector.getCreator(declaredConstructors);
+ }
}
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..c7adaa1
--- /dev/null
+++ b/src/main/java/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2022 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.Map;
+import java.util.Optional;
+
+import javax.json.bind.JsonbException;
+
+import org.eclipse.yasson.internal.model.JsonbCreator;
+import org.eclipse.yasson.internal.model.Property;
+
+/**
+ * Search for instance creator from other sources.
+ * Mainly intended to add extensibility for different java versions and new features.
+ */
+public class ClassMultiReleaseExtension {
+
+ private ClassMultiReleaseExtension() {
+ throw new IllegalStateException("This class cannot be instantiated");
+ }
+
+ static boolean shouldTransformToPropertyName(Method method) {
+ return true;
+ }
+
+ static boolean isSpecialAccessorMethod(Method method, Map<String, Property> classProperties) {
+ return false;
+ }
+
+ static JsonbCreator findCreator(Class<?> clazz,
+ Constructor<?>[] declaredConstructors,
+ AnnotationIntrospector introspector) {
+ return null;
+ }
+
+ public static Optional<JsonbException> exceptionToThrow(Class<?> clazz) {
+ return Optional.empty();
+ }
+
+}
diff --git a/src/main/java/org/eclipse/yasson/internal/ClassParser.java b/src/main/java/org/eclipse/yasson/internal/ClassParser.java
index 57c7617..8b0114d 100644
--- a/src/main/java/org/eclipse/yasson/internal/ClassParser.java
+++ b/src/main/java/org/eclipse/yasson/internal/ClassParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2022 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
@@ -192,10 +192,14 @@
for (Method method : declaredMethods) {
String name = method.getName();
//isBridge method filters out methods inherited from interfaces
- if (!isPropertyMethod(method) || method.isBridge() || isSpecialCaseMethod(clazz, method)) {
+ boolean isAccessorMethod = ClassMultiReleaseExtension.isSpecialAccessorMethod(method, classProperties)
+ || isPropertyMethod(method);
+ if (!isAccessorMethod || 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);
}
diff --git a/src/main/java/org/eclipse/yasson/internal/properties/MessageKeys.java b/src/main/java/org/eclipse/yasson/internal/properties/MessageKeys.java
index df49725..ca78328 100644
--- a/src/main/java/org/eclipse/yasson/internal/properties/MessageKeys.java
+++ b/src/main/java/org/eclipse/yasson/internal/properties/MessageKeys.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2022 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
@@ -61,6 +61,10 @@
*/
NO_DEFAULT_CONSTRUCTOR("noDefaultConstructor"),
/**
+ * Class does not have default constructor.
+ */
+ RECORD_MULTIPLE_CONSTRUCTORS("recordMultipleConstructors"),
+ /**
* There has been an error while invoking getter.
*/
INVOKING_GETTER("invokingGetter"),
diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ObjectDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ObjectDeserializer.java
index 8b155c8..38c7ddf 100644
--- a/src/main/java/org/eclipse/yasson/internal/serializer/ObjectDeserializer.java
+++ b/src/main/java/org/eclipse/yasson/internal/serializer/ObjectDeserializer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2022 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
@@ -23,6 +23,7 @@
import javax.json.bind.serializer.JsonbDeserializer;
import javax.json.stream.JsonParser;
+import org.eclipse.yasson.internal.ClassMultiReleaseExtension;
import org.eclipse.yasson.internal.JsonbContext;
import org.eclipse.yasson.internal.JsonbParser;
import org.eclipse.yasson.internal.JsonbRiParser;
@@ -98,7 +99,8 @@
} else {
Constructor<T> defaultConstructor = (Constructor<T>) getClassModel().getDefaultConstructor();
if (defaultConstructor == null) {
- throw new JsonbException(Messages.getMessage(MessageKeys.NO_DEFAULT_CONSTRUCTOR, rawType));
+ throw ClassMultiReleaseExtension.exceptionToThrow(rawType)
+ .orElse(new JsonbException(Messages.getMessage(MessageKeys.NO_DEFAULT_CONSTRUCTOR, rawType)));
}
instance = ReflectionUtils.createNoArgConstructorInstance(defaultConstructor);
}
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..d62e7fb
--- /dev/null
+++ b/src/main/java16/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2022 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.Map;
+import java.util.Optional;
+
+import javax.json.bind.JsonbException;
+
+import org.eclipse.yasson.internal.model.JsonbCreator;
+import org.eclipse.yasson.internal.model.Property;
+import org.eclipse.yasson.internal.properties.MessageKeys;
+import org.eclipse.yasson.internal.properties.Messages;
+
+/**
+ * Search for instance creator from other sources.
+ * Mainly intended to add extensibility for different java versions and new features.
+ */
+public class ClassMultiReleaseExtension {
+
+ private ClassMultiReleaseExtension() {
+ throw new IllegalStateException("This class cannot be instantiated");
+ }
+
+ static boolean shouldTransformToPropertyName(Method method) {
+ return !method.getDeclaringClass().isRecord();
+ }
+
+ static boolean isSpecialAccessorMethod(Method method, Map<String, Property> classProperties) {
+ return method.getDeclaringClass().isRecord()
+ && method.getParameterCount() == 0
+ && !void.class.equals(method.getReturnType())
+ && classProperties.containsKey(method.getName());
+ }
+
+ static JsonbCreator findCreator(Class<?> clazz,
+ Constructor<?>[] declaredConstructors,
+ AnnotationIntrospector introspector) {
+ if (clazz.isRecord()) {
+ if (declaredConstructors.length == 1) {
+ return introspector.createJsonbCreator(declaredConstructors[0], null, clazz);
+ }
+ }
+ return null;
+ }
+
+ public static Optional<JsonbException> exceptionToThrow(Class<?> clazz) {
+ if (clazz.isRecord()) {
+ if (clazz.getDeclaredConstructors().length > 1) {
+ return Optional.of(new JsonbException(Messages.getMessage(MessageKeys.RECORD_MULTIPLE_CONSTRUCTORS, clazz)));
+ }
+ }
+ return Optional.empty();
+ }
+
+}
diff --git a/src/main/resources/yasson-messages.properties b/src/main/resources/yasson-messages.properties
index aeca59a..6629b3f 100644
--- a/src/main/resources/yasson-messages.properties
+++ b/src/main/resources/yasson-messages.properties
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, 2019 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2022 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
@@ -50,6 +50,7 @@
errorParsingDate=Error parsing {1} from value: {0}. Check your @JsonbDateFormat has all time units for {1} type, \
or consider using org.eclipse.yasson.YassonConfig#ZERO_TIME_PARSE_DEFAULTING.
noDefaultConstructor=Cannot create instance of a class: {0}, No default constructor found.
+recordMultipleConstructors=Cannot create instance of a record: {0}, Multiple constructors found.
offsetDateTimeFromMillis=Parsing {0} from epoch millisecond, UTC zone offset will be used.
timeToEpochMillisError=Cannot convert {0} to/from epoch milliseconds.
configPropertyInvalidType=JsonbConfig property [{0}] must be of type [{1}].
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..16a18fe
--- /dev/null
+++ b/src/test/java16/org/eclipse/yasson/records/Car.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2022 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 javax.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/CarWithCreator.java b/src/test/java16/org/eclipse/yasson/records/CarWithCreator.java
new file mode 100644
index 0000000..281fcfb
--- /dev/null
+++ b/src/test/java16/org/eclipse/yasson/records/CarWithCreator.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022 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 javax.json.bind.annotation.JsonbCreator;
+import javax.json.bind.annotation.JsonbProperty;
+
+public record CarWithCreator(String type, String color) {
+
+ @JsonbCreator
+ public static CarWithCreator create(@JsonbProperty("type") String type, @JsonbProperty("color") String color) {
+ return new CarWithCreator(type, color);
+ }
+
+}
diff --git a/src/test/java16/org/eclipse/yasson/records/CarWithExtraMethod.java b/src/test/java16/org/eclipse/yasson/records/CarWithExtraMethod.java
new file mode 100644
index 0000000..685a237
--- /dev/null
+++ b/src/test/java16/org/eclipse/yasson/records/CarWithExtraMethod.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2022 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 CarWithExtraMethod(String type, String color) {
+
+ public String type() {
+ return type;
+ }
+
+}
diff --git a/src/test/java16/org/eclipse/yasson/records/CarWithMultipleConstructors.java b/src/test/java16/org/eclipse/yasson/records/CarWithMultipleConstructors.java
new file mode 100644
index 0000000..39f6ef4
--- /dev/null
+++ b/src/test/java16/org/eclipse/yasson/records/CarWithMultipleConstructors.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2022 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 CarWithMultipleConstructors(String type, String color) {
+
+ public CarWithMultipleConstructors(String type) {
+ this(type, "red");
+ }
+
+}
diff --git a/src/test/java16/org/eclipse/yasson/records/CarWithMultipleConstructorsAndCreator.java b/src/test/java16/org/eclipse/yasson/records/CarWithMultipleConstructorsAndCreator.java
new file mode 100644
index 0000000..42bea50
--- /dev/null
+++ b/src/test/java16/org/eclipse/yasson/records/CarWithMultipleConstructorsAndCreator.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022 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 javax.json.bind.annotation.JsonbCreator;
+import javax.json.bind.annotation.JsonbProperty;
+
+public record CarWithMultipleConstructorsAndCreator(String type, String color) {
+
+ @JsonbCreator
+ public CarWithMultipleConstructorsAndCreator(@JsonbProperty("type") String type) {
+ this(type, "red");
+ }
+
+}
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..4ded5f7
--- /dev/null
+++ b/src/test/java16/org/eclipse/yasson/records/CarWithoutAnnotations.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2022 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..a7c3e97
--- /dev/null
+++ b/src/test/java16/org/eclipse/yasson/records/RecordTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2022 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 javax.json.bind.JsonbException;
+
+import org.eclipse.yasson.Jsonbs;
+import org.eclipse.yasson.internal.properties.MessageKeys;
+import org.eclipse.yasson.internal.properties.Messages;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+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);
+ }
+
+ @Test
+ public void testRecordProcessingWithExtraMethod() {
+ CarWithExtraMethod car = new CarWithExtraMethod("skoda", "green");
+ String expected = "{\"color\":\"green\",\"type\":\"skoda\"}";
+
+ String json = Jsonbs.defaultJsonb.toJson(car);
+ assertEquals(expected, json);
+ CarWithExtraMethod deserialized = Jsonbs.defaultJsonb.fromJson(expected, CarWithExtraMethod.class);
+ assertEquals(car, deserialized);
+ }
+
+ @Test
+ public void testRecordMultipleConstructors() {
+ CarWithMultipleConstructors car = new CarWithMultipleConstructors("skoda");
+ String expected = "{\"color\":\"red\",\"type\":\"skoda\"}";
+
+ String json = Jsonbs.defaultJsonb.toJson(car);
+ assertEquals(expected, json);
+ JsonbException jsonbException = assertThrows(JsonbException.class,
+ () -> Jsonbs.defaultJsonb.fromJson(expected,
+ CarWithMultipleConstructors.class));
+ String expectedMessage = Messages.getMessage(MessageKeys.RECORD_MULTIPLE_CONSTRUCTORS, CarWithMultipleConstructors.class);
+ assertEquals(expectedMessage, jsonbException.getMessage());
+ }
+
+ @Test
+ public void testRecordMultipleConstructorsWithJsonbCreator() {
+ CarWithMultipleConstructorsAndCreator car = new CarWithMultipleConstructorsAndCreator("skoda");
+ String expected = "{\"color\":\"red\",\"type\":\"skoda\"}";
+
+ String json = Jsonbs.defaultJsonb.toJson(car);
+ assertEquals(expected, json);
+ CarWithMultipleConstructorsAndCreator deserialized = Jsonbs.defaultJsonb
+ .fromJson(expected, CarWithMultipleConstructorsAndCreator.class);
+ assertEquals(car, deserialized);
+ }
+
+ @Test
+ public void testRecordJsonbCreator() {
+ CarWithCreator car = new CarWithCreator("skoda", "red");
+ String expected = "{\"color\":\"red\",\"type\":\"skoda\"}";
+
+ String json = Jsonbs.defaultJsonb.toJson(car);
+ assertEquals(expected, json);
+ CarWithCreator deserialized = Jsonbs.defaultJsonb.fromJson(expected, CarWithCreator.class);
+ assertEquals(car, deserialized);
+ }
+
+}