Skip to content

Commit 9d3c4f3

Browse files
authored
Record optional parameters (#542)
Record constructor parameters are optional now Signed-off-by: David Kral <[email protected]>
1 parent e7ff427 commit 9d3c4f3

File tree

5 files changed

+94
-3
lines changed

5 files changed

+94
-3
lines changed

src/main/java/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ static boolean shouldTransformToPropertyName(Method method) {
3636
return true;
3737
}
3838

39+
/**
40+
* Whether the class is Record or not.
41+
*
42+
* @param clazz class to check
43+
* @return is record
44+
*/
45+
public static boolean isRecord(Class<?> clazz) {
46+
return false;
47+
}
48+
3949
static boolean isSpecialAccessorMethod(Method method, Map<String, Property> classProperties) {
4050
return false;
4151
}

src/main/java/org/eclipse/yasson/internal/serializer/ObjectDeserializer.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,16 @@
1515
import java.lang.reflect.Constructor;
1616
import java.lang.reflect.Type;
1717
import java.util.ArrayList;
18+
import java.util.Collections;
19+
import java.util.HashMap;
1820
import java.util.LinkedHashMap;
1921
import java.util.List;
2022
import java.util.Map;
23+
import java.util.Optional;
24+
import java.util.OptionalDouble;
25+
import java.util.OptionalInt;
26+
import java.util.OptionalLong;
27+
import java.util.function.Supplier;
2128

2229
import jakarta.json.bind.JsonbException;
2330
import jakarta.json.bind.serializer.JsonbDeserializer;
@@ -42,6 +49,28 @@
4249
*/
4350
class ObjectDeserializer<T> extends AbstractContainerDeserializer<T> {
4451

52+
private static final Map<Class<?>, Supplier<Object>> DEFAULT_CREATOR_VALUES;
53+
private static final Supplier<Object> NULL_PROVIDER = () -> null;
54+
55+
static {
56+
Map<Class<?>, Supplier<Object>> tmpValuesMap = new HashMap<>();
57+
58+
tmpValuesMap.put(byte.class, () -> (byte) 0);
59+
tmpValuesMap.put(short.class, () -> (short) 0);
60+
tmpValuesMap.put(int.class, () -> 0);
61+
tmpValuesMap.put(long.class, () -> 0L);
62+
tmpValuesMap.put(float.class, () -> 0.0F);
63+
tmpValuesMap.put(double.class, () -> 0.0);
64+
tmpValuesMap.put(char.class, () -> '\u0000');
65+
tmpValuesMap.put(boolean.class, () -> false);
66+
tmpValuesMap.put(Optional.class, Optional::empty);
67+
tmpValuesMap.put(OptionalInt.class, OptionalInt::empty);
68+
tmpValuesMap.put(OptionalLong.class, OptionalLong::empty);
69+
tmpValuesMap.put(OptionalDouble.class, OptionalDouble::empty);
70+
71+
DEFAULT_CREATOR_VALUES = Collections.unmodifiableMap(tmpValuesMap);
72+
}
73+
4574
/**
4675
* Last property model cache to avoid lookup by jsonKey on every access.
4776
*/
@@ -123,13 +152,18 @@ public T getInstance(Unmarshaller unmarshaller) {
123152
private T createInstance(Class<T> rawType, JsonbCreator creator) {
124153
final T instance;
125154
final List<Object> paramValues = new ArrayList<>();
155+
boolean isRecord = ClassMultiReleaseExtension.isRecord(rawType);
126156
for (CreatorModel param : creator.getParams()) {
127157
final ValueWrapper valueWrapper = values.get(param.getName());
128158
//required by spec
129-
if (valueWrapper == null) {
159+
if (!isRecord && valueWrapper == null) {
130160
throw new JsonbException(Messages.getMessage(MessageKeys.JSONB_CREATOR_MISSING_PROPERTY, param.getName()));
161+
} else if (valueWrapper == null) {
162+
Class<?> rawParamType = ReflectionUtils.getRawType(param.getType());
163+
paramValues.add(DEFAULT_CREATOR_VALUES.getOrDefault(rawParamType, NULL_PROVIDER).get());
164+
} else {
165+
paramValues.add(valueWrapper.getValue());
131166
}
132-
paramValues.add(valueWrapper.getValue());
133167
}
134168
instance = creator.call(paramValues.toArray(), rawType);
135169
return instance;

src/main/java16/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ private ClassMultiReleaseExtension() {
3535
}
3636

3737
static boolean shouldTransformToPropertyName(Method method) {
38-
return !method.getDeclaringClass().isRecord();
38+
return !isRecord(method.getDeclaringClass());
39+
}
40+
41+
public static boolean isRecord(Class<?> clazz) {
42+
return clazz.isRecord();
3943
}
4044

4145
static boolean isSpecialAccessorMethod(Method method, Map<String, Property> classProperties) {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0,
7+
* or the Eclipse Distribution License v. 1.0 which is available at
8+
* http://www.eclipse.org/org/documents/edl-v10.php.
9+
*
10+
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
11+
*/
12+
13+
package org.eclipse.yasson.records;
14+
15+
import java.util.Optional;
16+
17+
import jakarta.json.bind.annotation.JsonbCreator;
18+
import jakarta.json.bind.annotation.JsonbProperty;
19+
20+
public record CarCreatorOptionalTest(String type, int somePrimitive, String color) {
21+
22+
@JsonbCreator
23+
public CarCreatorOptionalTest(@JsonbProperty("type") Optional<String> type,
24+
@JsonbProperty("somePrimitive") int somePrimitive,
25+
@JsonbProperty("color") String color) {
26+
this(type.orElse("typeDefaultValue"), somePrimitive, color);
27+
}
28+
}

src/test/java16/org/eclipse/yasson/records/RecordTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,19 @@ public void testRecordJsonbCreator() {
9494
assertEquals(car, deserialized);
9595
}
9696

97+
@Test
98+
public void testRecordParameterOptionality() {
99+
CarCreatorOptionalTest car = new CarCreatorOptionalTest("skoda", 123, "red");
100+
String expected = "{\"color\":\"red\",\"somePrimitive\":123,\"type\":\"skoda\"}";
101+
102+
String json = Jsonbs.defaultJsonb.toJson(car);
103+
assertEquals(expected, json);
104+
105+
String toDeserialize = "{}";
106+
String expectedDefaultValues = "{\"color\":null,\"somePrimitive\":0,\"type\":\"typeDefaultValue\"}";
107+
CarCreatorOptionalTest deserialized = Jsonbs.defaultJsonb.fromJson(toDeserialize, CarCreatorOptionalTest.class);
108+
json = Jsonbs.nullableJsonb.toJson(deserialized);
109+
assertEquals(expectedDefaultValues, json);
110+
}
111+
97112
}

0 commit comments

Comments
 (0)