MapEntryFormatTest.java
package com.fasterxml.jackson.databind.format;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.*;
public class MapEntryFormatTest extends DatabindTestUtil
{
static class BeanWithMapEntry {
// would work with any other shape than OBJECT, or without annotation:
@JsonFormat(shape=JsonFormat.Shape.NATURAL)
public Map.Entry<String,String> entry;
protected BeanWithMapEntry() { }
public BeanWithMapEntry(String key, String value) {
Map<String,String> map = new LinkedHashMap<>();
map.put(key, value);
entry = map.entrySet().iterator().next();
}
}
@JsonFormat(shape=JsonFormat.Shape.OBJECT)
@JsonPropertyOrder({ "key", "value" })
static class MapEntryAsObject implements Map.Entry<String,String> {
protected String key, value;
protected MapEntryAsObject() { }
public MapEntryAsObject(String k, String v) {
key = k;
value = v;
}
@Override
public String getKey() {
return key;
}
@Override
public String getValue() {
return value;
}
@Override
public String setValue(String v) {
value = v;
return v; // wrong, whatever
}
}
static class EntryWithNullWrapper {
@JsonInclude(value=JsonInclude.Include.NON_EMPTY,
content=JsonInclude.Include.NON_NULL)
public Map.Entry<String,String> entry;
public EntryWithNullWrapper(String key, String value) {
HashMap<String,String> map = new HashMap<>();
map.put(key, value);
entry = map.entrySet().iterator().next();
}
}
static class EntryWithDefaultWrapper {
@JsonInclude(value=JsonInclude.Include.NON_EMPTY,
content=JsonInclude.Include.NON_DEFAULT)
public Map.Entry<String,String> entry;
public EntryWithDefaultWrapper(String key, String value) {
HashMap<String,String> map = new HashMap<>();
map.put(key, value);
entry = map.entrySet().iterator().next();
}
}
static class EntryWithNonAbsentWrapper {
@JsonInclude(value=JsonInclude.Include.NON_EMPTY,
content=JsonInclude.Include.NON_ABSENT)
public Map.Entry<String,AtomicReference<String>> entry;
public EntryWithNonAbsentWrapper(String key, String value) {
HashMap<String,AtomicReference<String>> map = new HashMap<>();
map.put(key, new AtomicReference<String>(value));
entry = map.entrySet().iterator().next();
}
}
static class EmptyEntryWrapper {
@JsonInclude(value=JsonInclude.Include.NON_EMPTY,
content=JsonInclude.Include.NON_EMPTY)
public Map.Entry<String,String> entry;
public EmptyEntryWrapper(String key, String value) {
HashMap<String,String> map = new HashMap<>();
map.put(key, value);
entry = map.entrySet().iterator().next();
}
}
/*
/**********************************************************************
/* Test methods, basic
/**********************************************************************
*/
private final ObjectMapper MAPPER = newJsonMapper();
@Test
public void testInclusion() throws Exception
{
assertEquals(a2q("{'entry':{'a':'b'}}"),
MAPPER.writeValueAsString(new EmptyEntryWrapper("a", "b")));
assertEquals(a2q("{'entry':{'a':'b'}}"),
MAPPER.writeValueAsString(new EntryWithDefaultWrapper("a", "b")));
assertEquals(a2q("{'entry':{'a':'b'}}"),
MAPPER.writeValueAsString(new EntryWithNullWrapper("a", "b")));
assertEquals(a2q("{}"),
MAPPER.writeValueAsString(new EmptyEntryWrapper("a", "")));
assertEquals(a2q("{}"),
MAPPER.writeValueAsString(new EntryWithDefaultWrapper("a", "")));
assertEquals(a2q("{'entry':{'a':''}}"),
MAPPER.writeValueAsString(new EntryWithNullWrapper("a", "")));
assertEquals(a2q("{}"),
MAPPER.writeValueAsString(new EntryWithNullWrapper("a", null)));
}
@Test
public void testInclusionWithReference() throws Exception
{
assertEquals(a2q("{'entry':{'a':'b'}}"),
MAPPER.writeValueAsString(new EntryWithNonAbsentWrapper("a", "b")));
// empty String not excluded since reference is not absent, just points to empty
// (so would need 3rd level inclusion definition)
assertEquals(a2q("{'entry':{'a':''}}"),
MAPPER.writeValueAsString(new EntryWithNonAbsentWrapper("a", "")));
assertEquals(a2q("{}"),
MAPPER.writeValueAsString(new EntryWithNonAbsentWrapper("a", null)));
}
/*
/**********************************************************************
/* Test methods, as-Object (Shape)
/**********************************************************************
*/
@Test
public void testAsNaturalRoundtrip() throws Exception
{
BeanWithMapEntry input = new BeanWithMapEntry("foo" ,"bar");
String json = MAPPER.writeValueAsString(input);
assertEquals(a2q("{'entry':{'foo':'bar'}}"), json);
BeanWithMapEntry result = MAPPER.readValue(json, BeanWithMapEntry.class);
assertEquals("foo", result.entry.getKey());
assertEquals("bar", result.entry.getValue());
}
// should work via class annotation
@Test
public void testAsObjectRoundtrip() throws Exception
{
MapEntryAsObject input = new MapEntryAsObject("foo" ,"bar");
String json = MAPPER.writeValueAsString(input);
assertEquals(a2q("{'key':'foo','value':'bar'}"), json);
// 16-Oct-2016, tatu: Happens to work by default because it's NOT basic
// `Map.Entry` but subtype.
MapEntryAsObject result = MAPPER.readValue(json, MapEntryAsObject.class);
assertEquals("foo", result.getKey());
assertEquals("bar", result.getValue());
}
// [databind#1895]
@Test
public void testDefaultShapeOverride() throws Exception
{
ObjectMapper mapper = jsonMapperBuilder()
.withConfigOverride(Map.Entry.class, cfg ->
cfg.setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.OBJECT)))
.build();
Map.Entry<String,String> input = new BeanWithMapEntry("foo", "bar").entry;
assertTrue(mapper.writeValueAsString(input).equals(a2q("{'key':'foo','value':'bar'}"))
|| mapper.writeValueAsString(input).equals(a2q("{'value':'bar','key':'foo'}")));
}
}