blob: 87d59227bc8a904a006ed3f2a9dccfed118fe6f3 [file] [log] [blame]
package com.fasterxml.jackson.databind.struct;
import java.util.*;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;
/**
* Tests for {@link JsonFormat} and specifically <code>JsonFormat.Feature</code>s.
*/
public class FormatFeaturesTest extends BaseMapTest
{
@JsonPropertyOrder( { "strings", "ints", "bools" })
static class WrapWriteWithArrays
{
@JsonProperty("strings")
@JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED })
public String[] _strings = new String[] {
"a"
};
@JsonFormat(without={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED })
public int[] ints = new int[] {
1
};
public boolean[] bools = new boolean[] { true };
}
@JsonPropertyOrder( { "strings", "ints", "bools", "enums" })
static class WrapWriteWithCollections
{
@JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED })
public List<String> strings = Arrays.asList("a");
@JsonFormat(without={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED })
public Collection<Integer> ints = Arrays.asList(Integer.valueOf(1));
public Set<Boolean> bools = Collections.singleton(true);
@JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED })
public EnumSet<ABC> enums = EnumSet.of(ABC.B);
}
static class StringArrayWrapper {
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
public String[] values;
}
static class StringArrayNotAnnoted {
public String[] values;
protected StringArrayNotAnnoted() { }
public StringArrayNotAnnoted(String ... v) { values = v; }
}
static class IntArrayWrapper {
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
public int[] values;
}
static class LongArrayWrapper {
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
public long[] values;
}
static class StringListWrapper {
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
public List<String> values;
}
static class EnumSetWrapper {
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
public EnumSet<ABC> values;
}
static class RolesInArray {
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
public Role[] roles;
}
static class RolesInList {
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
public List<Role> roles;
}
static class Role {
public String ID;
public String Name;
}
static class CaseInsensitiveRoleWrapper
{
@JsonFormat(with={ JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES })
public Role role;
}
static class SortedKeysMap {
@JsonFormat(with = JsonFormat.Feature.WRITE_SORTED_MAP_ENTRIES)
public Map<String,Integer> values = new LinkedHashMap<>();
protected SortedKeysMap() { }
public SortedKeysMap put(String key, int value) {
values.put(key, value);
return this;
}
}
/*
/**********************************************************
/* Test methods, writing with single-element unwrapping
/**********************************************************
*/
private final ObjectMapper MAPPER = new ObjectMapper();
public void testWithArrayTypes() throws Exception
{
// default: strings unwrapped, ints wrapped
assertEquals(aposToQuotes("{'strings':'a','ints':[1],'bools':[true]}"),
MAPPER.writeValueAsString(new WrapWriteWithArrays()));
// change global default to "yes, unwrap"; changes 'bools' only
assertEquals(aposToQuotes("{'strings':'a','ints':[1],'bools':true}"),
MAPPER.writer().with(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED)
.writeValueAsString(new WrapWriteWithArrays()));
// change global default to "no, don't, unwrap", same as first case
assertEquals(aposToQuotes("{'strings':'a','ints':[1],'bools':[true]}"),
MAPPER.writer().without(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED)
.writeValueAsString(new WrapWriteWithArrays()));
// And then without SerializationFeature but with config override:
ObjectMapper mapper = new ObjectMapper();
mapper.configOverride(String[].class).setFormat(JsonFormat.Value.empty()
.withFeature(JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED));
assertEquals(aposToQuotes("{'values':'a'}"),
mapper.writeValueAsString(new StringArrayNotAnnoted("a")));
}
public void testWithCollectionTypes() throws Exception
{
// default: strings unwrapped, ints wrapped
assertEquals(aposToQuotes("{'strings':'a','ints':[1],'bools':[true],'enums':'B'}"),
MAPPER.writeValueAsString(new WrapWriteWithCollections()));
// change global default to "yes, unwrap"; changes 'bools' only
assertEquals(aposToQuotes("{'strings':'a','ints':[1],'bools':true,'enums':'B'}"),
MAPPER.writer().with(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED)
.writeValueAsString(new WrapWriteWithCollections()));
// change global default to "no, don't, unwrap", same as first case
assertEquals(aposToQuotes("{'strings':'a','ints':[1],'bools':[true],'enums':'B'}"),
MAPPER.writer().without(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED)
.writeValueAsString(new WrapWriteWithCollections()));
}
/*
/**********************************************************
/* Test methods, reading with single-element unwrapping
/**********************************************************
*/
public void testSingleStringArrayRead() throws Exception {
String json = aposToQuotes(
"{ 'values': 'first' }");
StringArrayWrapper result = MAPPER.readValue(json, StringArrayWrapper.class);
assertNotNull(result.values);
assertEquals(1, result.values.length);
assertEquals("first", result.values[0]);
// and then without annotation, but with global override
ObjectMapper mapper = new ObjectMapper();
mapper.configOverride(String[].class).setFormat(JsonFormat.Value.empty()
.withFeature(JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY));
StringArrayNotAnnoted result2 = mapper.readValue(json, StringArrayNotAnnoted.class);
assertNotNull(result2.values);
assertEquals(1, result2.values.length);
assertEquals("first", result2.values[0]);
}
public void testSingleIntArrayRead() throws Exception {
String json = aposToQuotes(
"{ 'values': 123 }");
IntArrayWrapper result = MAPPER.readValue(json, IntArrayWrapper.class);
assertNotNull(result.values);
assertEquals(1, result.values.length);
assertEquals(123, result.values[0]);
}
public void testSingleLongArrayRead() throws Exception {
String json = aposToQuotes(
"{ 'values': -205 }");
LongArrayWrapper result = MAPPER.readValue(json, LongArrayWrapper.class);
assertNotNull(result.values);
assertEquals(1, result.values.length);
assertEquals(-205L, result.values[0]);
}
public void testSingleElementArrayRead() throws Exception {
String json = aposToQuotes(
"{ 'roles': { 'Name': 'User', 'ID': '333' } }");
RolesInArray response = MAPPER.readValue(json, RolesInArray.class);
assertNotNull(response.roles);
assertEquals(1, response.roles.length);
assertEquals("333", response.roles[0].ID);
}
public void testSingleStringListRead() throws Exception {
String json = aposToQuotes(
"{ 'values': 'first' }");
StringListWrapper result = MAPPER.readValue(json, StringListWrapper.class);
assertNotNull(result.values);
assertEquals(1, result.values.size());
assertEquals("first", result.values.get(0));
}
public void testSingleElementListRead() throws Exception {
String json = aposToQuotes(
"{ 'roles': { 'Name': 'User', 'ID': '333' } }");
RolesInList response = MAPPER.readValue(json, RolesInList.class);
assertNotNull(response.roles);
assertEquals(1, response.roles.size());
assertEquals("333", response.roles.get(0).ID);
}
public void testSingleEnumSetRead() throws Exception {
EnumSetWrapper result = MAPPER.readValue(aposToQuotes("{ 'values': 'B' }"),
EnumSetWrapper.class);
assertNotNull(result.values);
assertEquals(1, result.values.size());
assertEquals(ABC.B, result.values.iterator().next());
}
// [databind#1232]: allow per-property case-insensitivity
public void testCaseInsensitive() throws Exception {
CaseInsensitiveRoleWrapper w = MAPPER.readValue
(aposToQuotes("{'role':{'id':'12','name':'Foo'}}"),
CaseInsensitiveRoleWrapper.class);
assertNotNull(w);
assertEquals("12", w.role.ID);
assertEquals("Foo", w.role.Name);
}
// [databind#1232]: allow forcing sorting on Map keys
public void testOrderedMaps() throws Exception {
SortedKeysMap map = new SortedKeysMap()
.put("b", 2)
.put("a", 1);
assertEquals(aposToQuotes("{'values':{'a':1,'b':2}}"),
MAPPER.writeValueAsString(map));
}
}