Skip to content

Commit

Permalink
Test case to document behaviour of Record x Single-value Constructor …
Browse files Browse the repository at this point in the history
…x JsonValue annotation, for FasterXML#3180.
  • Loading branch information
yihtserns committed Jan 17, 2023
1 parent 0a4cfc4 commit 9327c3f
Showing 1 changed file with 83 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.fasterxml.jackson.databind.records;

import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.BaseMapTest;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.MapperFeature;
Expand Down Expand Up @@ -29,6 +30,18 @@ public static RecordWithImplicitFactoryMethods valueOf(String id) {
record RecordWithSingleValueConstructor(int id) {
}

record RecordWithSingleValueConstructorWithJsonValue(@JsonValue int id) {
}

record RecordWithSingleValueConstructorWithJsonValueAccessor(int id) {

@JsonValue
@Override
public int id() {
return id;
}
}

record RecordWithNonCanonicalConstructor(int id, String name, String email) {

public RecordWithNonCanonicalConstructor(int id, String email) {
Expand Down Expand Up @@ -119,8 +132,18 @@ public void testDeserializeUsingImplicitFactoryMethod_WithAutoDetectCreatorsDisa
* GOTCHA: For JavaBean, only having single-value constructor results in implicit delegating creator. But for
* Records, the CANONICAL single-value constructor results in properties-based creator.
* <p/>
* Only when there's NON-CANONICAL single-value constructor will there be implicit delegating creator - see
* {@link #testDeserializeUsingImplicitDelegatingConstructor()}.
* It will result in implicit delegating constructor only when:
* <ul>
* <li>
* There's NON-CANONICAL single-value constructor - see
* {@link #testDeserializeUsingImplicitDelegatingConstructor()}, or
* </li>
* <li>
* {@code @JsonValue} annotation is used - see
* {@link #testDeserializeUsingImplicitSingleValueConstructor_WithJsonValue()},
* {@link #testDeserializeUsingImplicitSingleValueConstructor_WithJsonValueAccessor()}
* </li>
* </ul>.
* <p/>
* yihtserns: maybe we can change this to adopt JavaBean's behaviour, but I prefer to not break existing behaviour
* until and unless there's a discussion on this.
Expand Down Expand Up @@ -190,6 +213,64 @@ public void testDeserializeSingleValueConstructor_WithPropertiesBasedConstructor
assertEquals(new RecordWithSingleValueConstructor(123), value);
}

/*
/**********************************************************************
/* Test methods, implicit single-value constructor + @JsonValue
/**********************************************************************
*/

/**
* [databind#3180]
* This test-case is just for documentation purpose:
* Unlike {@link #testDeserializeUsingImplicitSingleValueConstructor()}, annotating {@code @JsonValue}
* to Records header results in a delegating constructor.
*/
public void testDeserializeUsingImplicitSingleValueConstructor_WithJsonValue() throws Exception {
// Can use delegating creator
RecordWithSingleValueConstructorWithJsonValue value = MAPPER.readValue(
"123",
RecordWithSingleValueConstructorWithJsonValue.class);
assertEquals(new RecordWithSingleValueConstructorWithJsonValue(123), value);

try {
// Can no longer use properties-based creator
MAPPER.readValue("{\"id\":123}", RecordWithSingleValueConstructorWithJsonValue.class);

fail("should not pass");
} catch (MismatchedInputException e) {
verifyException(e, "Cannot construct instance");
verifyException(e, "RecordWithSingleValueConstructorWithJsonValue");
verifyException(e, "although at least one Creator exists");
verifyException(e, "cannot deserialize from Object value");
}
}

/**
* [databind#3180]
* This test-case is just for documentation purpose:
* Unlike {@link #testDeserializeUsingImplicitSingleValueConstructor()}, annotating {@code @JsonValue}
* to an accessor results in a delegating creator.
*/
public void testDeserializeUsingImplicitSingleValueConstructor_WithJsonValueAccessor() throws Exception {
// Can use delegating creator
RecordWithSingleValueConstructorWithJsonValueAccessor value = MAPPER.readValue(
"123",
RecordWithSingleValueConstructorWithJsonValueAccessor.class);
assertEquals(new RecordWithSingleValueConstructorWithJsonValueAccessor(123), value);

try {
// Can no longer use properties-based creator
MAPPER.readValue("{\"id\":123}", RecordWithSingleValueConstructorWithJsonValueAccessor.class);

fail("should not pass");
} catch (MismatchedInputException e) {
verifyException(e, "Cannot construct instance");
verifyException(e, "RecordWithSingleValueConstructorWithJsonValueAccessor");
verifyException(e, "although at least one Creator exists");
verifyException(e, "cannot deserialize from Object value");
}
}

/*
/**********************************************************************
/* Test methods, implicit properties-based + delegating constructor
Expand Down

0 comments on commit 9327c3f

Please sign in to comment.