Skip to content

Commit ae3ca88

Browse files
authored
Test case to document behaviour of Record x Single-value Constructor x JsonValue annotation, for #3180. (#3738)
1 parent 5e715ea commit ae3ca88

File tree

1 file changed

+83
-2
lines changed

1 file changed

+83
-2
lines changed

src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordImplicitCreatorsTest.java

+83-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.fasterxml.jackson.databind.records;
22

3+
import com.fasterxml.jackson.annotation.JsonValue;
34
import com.fasterxml.jackson.databind.BaseMapTest;
45
import com.fasterxml.jackson.databind.JsonMappingException;
56
import com.fasterxml.jackson.databind.MapperFeature;
@@ -29,6 +30,18 @@ public static RecordWithImplicitFactoryMethods valueOf(String id) {
2930
record RecordWithSingleValueConstructor(int id) {
3031
}
3132

33+
record RecordWithSingleValueConstructorWithJsonValue(@JsonValue int id) {
34+
}
35+
36+
record RecordWithSingleValueConstructorWithJsonValueAccessor(int id) {
37+
38+
@JsonValue
39+
@Override
40+
public int id() {
41+
return id;
42+
}
43+
}
44+
3245
record RecordWithNonCanonicalConstructor(int id, String name, String email) {
3346

3447
public RecordWithNonCanonicalConstructor(int id, String email) {
@@ -119,8 +132,18 @@ public void testDeserializeUsingImplicitFactoryMethod_WithAutoDetectCreatorsDisa
119132
* GOTCHA: For JavaBean, only having single-value constructor results in implicit delegating creator. But for
120133
* Records, the CANONICAL single-value constructor results in properties-based creator.
121134
* <p/>
122-
* Only when there's NON-CANONICAL single-value constructor will there be implicit delegating creator - see
123-
* {@link #testDeserializeUsingImplicitDelegatingConstructor()}.
135+
* It will result in implicit delegating constructor only when:
136+
* <ul>
137+
* <li>
138+
* There's NON-CANONICAL single-value constructor - see
139+
* {@link #testDeserializeUsingImplicitDelegatingConstructor()}, or
140+
* </li>
141+
* <li>
142+
* {@code @JsonValue} annotation is used - see
143+
* {@link #testDeserializeUsingImplicitSingleValueConstructor_WithJsonValue()},
144+
* {@link #testDeserializeUsingImplicitSingleValueConstructor_WithJsonValueAccessor()}
145+
* </li>
146+
* </ul>.
124147
* <p/>
125148
* yihtserns: maybe we can change this to adopt JavaBean's behaviour, but I prefer to not break existing behaviour
126149
* until and unless there's a discussion on this.
@@ -190,6 +213,64 @@ public void testDeserializeSingleValueConstructor_WithPropertiesBasedConstructor
190213
assertEquals(new RecordWithSingleValueConstructor(123), value);
191214
}
192215

216+
/*
217+
/**********************************************************************
218+
/* Test methods, implicit single-value constructor + @JsonValue
219+
/**********************************************************************
220+
*/
221+
222+
/**
223+
* [databind#3180]
224+
* This test-case is just for documentation purpose:
225+
* Unlike {@link #testDeserializeUsingImplicitSingleValueConstructor()}, annotating {@code @JsonValue}
226+
* to a Record's header results in a delegating constructor.
227+
*/
228+
public void testDeserializeUsingImplicitSingleValueConstructor_WithJsonValue() throws Exception {
229+
// Can use delegating creator
230+
RecordWithSingleValueConstructorWithJsonValue value = MAPPER.readValue(
231+
"123",
232+
RecordWithSingleValueConstructorWithJsonValue.class);
233+
assertEquals(new RecordWithSingleValueConstructorWithJsonValue(123), value);
234+
235+
try {
236+
// Can no longer use properties-based creator
237+
MAPPER.readValue("{\"id\":123}", RecordWithSingleValueConstructorWithJsonValue.class);
238+
239+
fail("should not pass");
240+
} catch (MismatchedInputException e) {
241+
verifyException(e, "Cannot construct instance");
242+
verifyException(e, "RecordWithSingleValueConstructorWithJsonValue");
243+
verifyException(e, "although at least one Creator exists");
244+
verifyException(e, "cannot deserialize from Object value");
245+
}
246+
}
247+
248+
/**
249+
* [databind#3180]
250+
* This test-case is just for documentation purpose:
251+
* Unlike {@link #testDeserializeUsingImplicitSingleValueConstructor()}, annotating {@code @JsonValue}
252+
* to the accessor results in a delegating creator.
253+
*/
254+
public void testDeserializeUsingImplicitSingleValueConstructor_WithJsonValueAccessor() throws Exception {
255+
// Can use delegating creator
256+
RecordWithSingleValueConstructorWithJsonValueAccessor value = MAPPER.readValue(
257+
"123",
258+
RecordWithSingleValueConstructorWithJsonValueAccessor.class);
259+
assertEquals(new RecordWithSingleValueConstructorWithJsonValueAccessor(123), value);
260+
261+
try {
262+
// Can no longer use properties-based creator
263+
MAPPER.readValue("{\"id\":123}", RecordWithSingleValueConstructorWithJsonValueAccessor.class);
264+
265+
fail("should not pass");
266+
} catch (MismatchedInputException e) {
267+
verifyException(e, "Cannot construct instance");
268+
verifyException(e, "RecordWithSingleValueConstructorWithJsonValueAccessor");
269+
verifyException(e, "although at least one Creator exists");
270+
verifyException(e, "cannot deserialize from Object value");
271+
}
272+
}
273+
193274
/*
194275
/**********************************************************************
195276
/* Test methods, implicit properties-based + delegating constructor

0 commit comments

Comments
 (0)