-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Adds support for @JsonKey
annotation
#2905
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -173,6 +173,17 @@ public boolean isNonStaticInnerClass() { | |
/********************************************************** | ||
*/ | ||
|
||
/** | ||
* Method for locating accessor (readable field, or "getter" method) | ||
* that has | ||
* {@link com.fasterxml.jackson.annotation.JsonKey} annotation, | ||
* if any. If multiple ones are found, | ||
* an error is reported by throwing {@link IllegalArgumentException} | ||
* | ||
* @since TODO | ||
*/ | ||
public abstract AnnotatedMember findJsonKeyAccessor(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know that some additions have been left as |
||
|
||
/** | ||
* Method for locating accessor (readable field, or "getter" method) | ||
* that has | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -106,6 +106,11 @@ public class POJOPropertiesCollector | |
|
||
protected LinkedList<AnnotatedMember> _anySetterField; | ||
|
||
/** | ||
* Method(s) annotated with 'JsonKey' annotation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Method(s) and/or Field(s)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I copied the comment here from |
||
*/ | ||
protected LinkedList<AnnotatedMember> _jsonKeyAccessors; | ||
|
||
/** | ||
* Method(s) marked with 'JsonValue' annotation | ||
*<p> | ||
|
@@ -187,6 +192,23 @@ public Map<Object, AnnotatedMember> getInjectables() { | |
return _injectables; | ||
} | ||
|
||
public AnnotatedMember getJsonKeyAccessor() { | ||
if (!_collected) { | ||
collectAll(); | ||
} | ||
// If @JsonKey defined, must have a single one | ||
if (_jsonKeyAccessors != null) { | ||
if (_jsonKeyAccessors.size() > 1) { | ||
reportProblem("Multiple 'as-value' properties defined (%s vs %s)", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as-key accessors |
||
_jsonKeyAccessors.get(0), | ||
_jsonKeyAccessors.get(1)); | ||
} | ||
// otherwise we won't greatly care | ||
return _jsonKeyAccessors.get(0); | ||
} | ||
return null; | ||
} | ||
|
||
/** | ||
* @since 2.9 | ||
*/ | ||
|
@@ -384,6 +406,13 @@ protected void _addFields(Map<String, POJOPropertyBuilder> props) | |
final boolean transientAsIgnoral = _config.isEnabled(MapperFeature.PROPAGATE_TRANSIENT_MARKER); | ||
|
||
for (AnnotatedField f : _classDef.fields()) { | ||
// @JsonKey? | ||
if (Boolean.TRUE.equals(ai.hasAsKey(f))) { | ||
if (_jsonKeyAccessors == null) { | ||
_jsonKeyAccessors = new LinkedList<>(); | ||
} | ||
_jsonKeyAccessors.add(f); | ||
} | ||
// @JsonValue? | ||
if (Boolean.TRUE.equals(ai.hasAsValue(f))) { | ||
if (_jsonValueAccessors == null) { | ||
|
@@ -596,6 +625,14 @@ protected void _addGetterMethod(Map<String, POJOPropertyBuilder> props, | |
_anyGetters.add(m); | ||
return; | ||
} | ||
// @JsonKey? | ||
if (Boolean.TRUE.equals(ai.hasAsKey(m))) { | ||
if (_jsonKeyAccessors == null) { | ||
_jsonKeyAccessors = new LinkedList<>(); | ||
} | ||
_jsonKeyAccessors.add(m); | ||
return; | ||
} | ||
// @JsonValue? | ||
if (Boolean.TRUE.equals(ai.hasAsValue(m))) { | ||
if (_jsonValueAccessors == null) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package com.fasterxml.jackson.databind.jsontype; | ||
|
||
import java.util.Collections; | ||
import java.util.Map; | ||
|
||
import com.fasterxml.jackson.annotation.JsonKey; | ||
import com.fasterxml.jackson.annotation.JsonValue; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import org.junit.Assert; | ||
import org.junit.Ignore; | ||
import org.junit.Test; | ||
|
||
public class MapSerializingTest { | ||
class Inner { | ||
@JsonKey | ||
String key; | ||
|
||
@JsonValue | ||
String value; | ||
|
||
Inner(String key, String value) { | ||
this.key = key; | ||
this.value = value; | ||
} | ||
|
||
public String toString() { | ||
return "Inner(" + this.key + "," + this.value + ")"; | ||
} | ||
|
||
} | ||
|
||
class Outer { | ||
@JsonKey | ||
@JsonValue | ||
Inner inner; | ||
|
||
Outer(Inner inner) { | ||
this.inner = inner; | ||
} | ||
|
||
} | ||
|
||
class NoKeyOuter { | ||
@JsonValue | ||
Inner inner; | ||
|
||
NoKeyOuter(Inner inner) { | ||
this.inner = inner; | ||
} | ||
} | ||
|
||
@Test | ||
public void testClassAsKey() throws Exception { | ||
ObjectMapper mapper = new ObjectMapper(); | ||
Outer outer = new Outer(new Inner("innerKey", "innerValue")); | ||
Map<Outer, String> map = Collections.singletonMap(outer, "value"); | ||
String actual = mapper.writeValueAsString(map); | ||
Assert.assertEquals("{\"innerKey\":\"value\"}", actual); | ||
} | ||
|
||
@Test | ||
public void testClassAsValue() throws Exception { | ||
ObjectMapper mapper = new ObjectMapper(); | ||
Map<String, Outer> mapA = Collections.singletonMap("key", new Outer(new Inner("innerKey", "innerValue"))); | ||
String actual = mapper.writeValueAsString(mapA); | ||
Assert.assertEquals("{\"key\":\"innerValue\"}", actual); | ||
} | ||
|
||
@Test | ||
public void testNoKeyOuter() throws Exception { | ||
ObjectMapper mapper = new ObjectMapper(); | ||
Map<String, NoKeyOuter> mapA = Collections.singletonMap("key", new NoKeyOuter(new Inner("innerKey", "innerValue"))); | ||
String actual = mapper.writeValueAsString(mapA); | ||
Assert.assertEquals("{\"key\":\"innerValue\"}", actual); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is what the code does right now; this I'm not sure if this is appropriate. |
||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One suggestion: could you take
MapperConfig<?>
as the first parameter? While it is not currently needed, it is something I have had to retrofit for a few methods (see f.exfindCreatorAnnotation()
), and in 3.0 every method will be changed to take it. So adding it now reduces conversion work slightly.