|
1 | 1 | package com.fasterxml.jackson.databind.records;
|
2 | 2 |
|
| 3 | +import com.fasterxml.jackson.annotation.JsonValue; |
3 | 4 | import com.fasterxml.jackson.databind.BaseMapTest;
|
4 | 5 | import com.fasterxml.jackson.databind.JsonMappingException;
|
5 | 6 | import com.fasterxml.jackson.databind.MapperFeature;
|
@@ -29,6 +30,18 @@ public static RecordWithImplicitFactoryMethods valueOf(String id) {
|
29 | 30 | record RecordWithSingleValueConstructor(int id) {
|
30 | 31 | }
|
31 | 32 |
|
| 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 | + |
32 | 45 | record RecordWithNonCanonicalConstructor(int id, String name, String email) {
|
33 | 46 |
|
34 | 47 | public RecordWithNonCanonicalConstructor(int id, String email) {
|
@@ -119,8 +132,18 @@ public void testDeserializeUsingImplicitFactoryMethod_WithAutoDetectCreatorsDisa
|
119 | 132 | * GOTCHA: For JavaBean, only having single-value constructor results in implicit delegating creator. But for
|
120 | 133 | * Records, the CANONICAL single-value constructor results in properties-based creator.
|
121 | 134 | * <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>. |
124 | 147 | * <p/>
|
125 | 148 | * yihtserns: maybe we can change this to adopt JavaBean's behaviour, but I prefer to not break existing behaviour
|
126 | 149 | * until and unless there's a discussion on this.
|
@@ -190,6 +213,64 @@ public void testDeserializeSingleValueConstructor_WithPropertiesBasedConstructor
|
190 | 213 | assertEquals(new RecordWithSingleValueConstructor(123), value);
|
191 | 214 | }
|
192 | 215 |
|
| 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 | + |
193 | 274 | /*
|
194 | 275 | /**********************************************************************
|
195 | 276 | /* Test methods, implicit properties-based + delegating constructor
|
|
0 commit comments