package com.fasterxml.jackson.databind.struct; import java.net.URI; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.annotation.JsonSerialize; public class FormatFeatureUnwrapSingleTest extends BaseMapTest { static class StringArrayNotAnnoted { public String[] values; protected StringArrayNotAnnoted() { } public StringArrayNotAnnoted(String ... v) { values = v; } } @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 }; } static class UnwrapShortArray { @JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED }) public short[] v = { (short) 7 }; } static class UnwrapIntArray { @JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED }) public int[] v = { 3 }; } static class UnwrapLongArray { @JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED }) public long[] v = { 1L }; } static class UnwrapBooleanArray { @JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED }) public boolean[] v = { true }; } static class UnwrapFloatArray { @JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED }) public float[] v = { 0.5f }; } static class UnwrapDoubleArray { @JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED }) public double[] v = { 0.25 }; } static class UnwrapIterable { @JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED }) @JsonSerialize(as=Iterable.class) public Iterable<String> v; public UnwrapIterable() { v = Collections.singletonList("foo"); } public UnwrapIterable(String... values) { v = Arrays.asList(values); } } static class UnwrapCollection { @JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED }) @JsonSerialize(as=Collection.class) public Collection<String> v; public UnwrapCollection() { v = Collections.singletonList("foo"); } public UnwrapCollection(String... values) { v = new LinkedHashSet<String>(Arrays.asList(values)); } } static class UnwrapStringLike { @JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED }) public URI[] v = { URI.create("http://foo") }; } @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); } /* /********************************************************** /* 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())); } public void testUnwrapWithPrimitiveArraysEtc() throws Exception { assertEquals("{\"v\":7}", MAPPER.writeValueAsString(new UnwrapShortArray())); assertEquals("{\"v\":3}", MAPPER.writeValueAsString(new UnwrapIntArray())); assertEquals("{\"v\":1}", MAPPER.writeValueAsString(new UnwrapLongArray())); assertEquals("{\"v\":true}", MAPPER.writeValueAsString(new UnwrapBooleanArray())); assertEquals("{\"v\":0.5}", MAPPER.writeValueAsString(new UnwrapFloatArray())); assertEquals("{\"v\":0.25}", MAPPER.writeValueAsString(new UnwrapDoubleArray())); assertEquals("0.5", MAPPER.writer().with(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED) .writeValueAsString(new double[] { 0.5 })); assertEquals("{\"v\":\"foo\"}", MAPPER.writeValueAsString(new UnwrapIterable())); assertEquals("{\"v\":\"x\"}", MAPPER.writeValueAsString(new UnwrapIterable("x"))); assertEquals("{\"v\":[\"x\",null]}", MAPPER.writeValueAsString(new UnwrapIterable("x", null))); assertEquals("{\"v\":\"foo\"}", MAPPER.writeValueAsString(new UnwrapCollection())); assertEquals("{\"v\":\"x\"}", MAPPER.writeValueAsString(new UnwrapCollection("x"))); assertEquals("{\"v\":[\"x\",null]}", MAPPER.writeValueAsString(new UnwrapCollection("x", null))); assertEquals("{\"v\":\"http://foo\"}", MAPPER.writeValueAsString(new UnwrapStringLike())); } }