Skip to content

Commit

Permalink
Fix #3063: resolve seeming @JsonValue conflict (useful with Records) (
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder authored Jan 16, 2023
1 parent d5cdd7b commit 075ec92
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 7 deletions.
4 changes: 4 additions & 0 deletions release-notes/CREDITS-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -1532,3 +1532,7 @@ Moritz Halbritter (mhalbritter@github)
Philippe Marschall (marschall@github)
* Contributed #3699: Allow custom `JsonNode` implementations
(2.14.2)
Gili Tzabari (cowwoc@github)
* Reported #3063: `@JsonValue` fails for Java Record
(2.14.2)
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Project: jackson-databind

#1751: `@JsonTypeInfo` does not work if the Type Id is an Integer value
(reported by @marvin-we)
#3063: `@JsonValue` fails for Java Record
(reported by Gili T)
#3699: Allow custom `JsonNode` implementations
(contributed by Philippe M)
#3711: Enum polymorphism not working correctly with DEDUCTION
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,11 @@ public AnnotatedMember getJsonKeyAccessor() {
// If @JsonKey defined, must have a single one
if (_jsonKeyAccessors != null) {
if (_jsonKeyAccessors.size() > 1) {
reportProblem("Multiple 'as-key' properties defined (%s vs %s)",
_jsonKeyAccessors.get(0),
_jsonKeyAccessors.get(1));
if (!_resolveFieldVsGetter(_jsonKeyAccessors)) {
reportProblem("Multiple 'as-key' properties defined (%s vs %s)",
_jsonKeyAccessors.get(0),
_jsonKeyAccessors.get(1));
}
}
// otherwise we won't greatly care
return _jsonKeyAccessors.get(0);
Expand All @@ -270,11 +272,14 @@ public AnnotatedMember getJsonValueAccessor()
collectAll();
}
// If @JsonValue defined, must have a single one
// 15-Jan-2023, tatu: Except let's try resolving "getter-over-field" case at least
if (_jsonValueAccessors != null) {
if (_jsonValueAccessors.size() > 1) {
reportProblem("Multiple 'as-value' properties defined (%s vs %s)",
_jsonValueAccessors.get(0),
_jsonValueAccessors.get(1));
if (!_resolveFieldVsGetter(_jsonValueAccessors)) {
reportProblem("Multiple 'as-value' properties defined (%s vs %s)",
_jsonValueAccessors.get(0),
_jsonValueAccessors.get(1));
}
}
// otherwise we won't greatly care
return _jsonValueAccessors.get(0);
Expand Down Expand Up @@ -1123,7 +1128,7 @@ protected void _renameWithWrappers(Map<String, POJOPropertyBuilder> props)

/*
/**********************************************************
/* Overridable internal methods, sorting, other stuff
/* Internal methods, sorting
/**********************************************************
*/

Expand Down Expand Up @@ -1244,6 +1249,48 @@ private boolean _anyIndexed(Collection<POJOPropertyBuilder> props) {
return false;
}

/*
/**********************************************************
/* Internal methods, conflict resolution
/**********************************************************
*/

/**
* Method that will be given a {@link List} with 2 or more accessors
* that may be in conflict: it will need to remove lower-priority accessors
* to leave just a single highest-priority accessor to use.
* If this succeeds method returns {@code true}, otherwise {@code false}.
*<p>
* NOTE: method will directly modify given {@code List} directly, regardless
* of whether it ultimately succeeds or not.
*
* @return True if seeming conflict was resolved and there only remains
* single accessor
*/
protected boolean _resolveFieldVsGetter(List<AnnotatedMember> accessors) {
do {
AnnotatedMember acc1 = accessors.get(0);
AnnotatedMember acc2 = accessors.get(1);

if (acc1 instanceof AnnotatedField) {
if (acc2 instanceof AnnotatedMethod) {
// Method has precedence, remove first entry
accessors.remove(0);
continue;
}
} else if (acc1 instanceof AnnotatedMethod) {
// Method has precedence, remove second entry
if (acc2 instanceof AnnotatedField) {
accessors.remove(1);
continue;
}
}
// Not a field/method pair; fail
return false;
} while (accessors.size() > 1);
return true;
}

/*
/**********************************************************
/* Internal methods; helpers
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.fasterxml.jackson.databind.records;

import java.util.Collections;
import java.util.Map;

import com.fasterxml.jackson.annotation.*;

import com.fasterxml.jackson.databind.BaseMapTest;
import com.fasterxml.jackson.databind.ObjectMapper;

public class RecordJsonValue3063Test extends BaseMapTest
{
// [databind#3063]
record GetLocations3063(@JsonValue Map<String, String> nameToLocation)
{
@JsonCreator
public GetLocations3063(Map<String, String> nameToLocation)
{
this.nameToLocation = nameToLocation;
}
}

private final ObjectMapper MAPPER = newJsonMapper();

// [databind#3063]
public void testRecordWithJsonValue3063() throws Exception
{
Map<String, String> locations = Collections.singletonMap("a", "locationA");
String json = MAPPER.writeValueAsString(new GetLocations3063(locations));

assertNotNull(json);
}
}

0 comments on commit 075ec92

Please sign in to comment.