package com.fasterxml.jackson.databind;
import java.io.*;
import java.util.*;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.util.MinimalPrettyPrinter;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
import com.fasterxml.jackson.databind.node.*;
public class ObjectMapperTest extends BaseMapTest
{
static class Bean {
int value = 3;
public void setX(int v) { value = v; }
protected Bean() { }
public Bean(int v) { value = v; }
}
static class EmptyBean { }
@SuppressWarnings("serial")
static class MyAnnotationIntrospector extends JacksonAnnotationIntrospector { }
// for [databind#689]
@SuppressWarnings("serial")
static class FooPrettyPrinter extends MinimalPrettyPrinter {
public FooPrettyPrinter() {
super(" /*foo*/ ");
}
@Override
public void writeArrayValueSeparator(JsonGenerator g) throws IOException
{
g.writeRaw(" , ");
}
}
// for [databind#206]
@SuppressWarnings("serial")
static class NoCopyMapper extends ObjectMapper { }
final ObjectMapper MAPPER = new ObjectMapper();
/*
/**********************************************************
/* Test methods, config
/**********************************************************
*/
public void testFactorFeatures()
{
assertTrue(MAPPER.isEnabled(JsonFactory.Feature.CANONICALIZE_FIELD_NAMES));
}
public void testGeneratorFeatures()
{
// and also for mapper
ObjectMapper mapper = new ObjectMapper();
assertFalse(mapper.isEnabled(JsonGenerator.Feature.ESCAPE_NON_ASCII));
assertTrue(mapper.isEnabled(JsonGenerator.Feature.QUOTE_FIELD_NAMES));
mapper.disable(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM,
JsonGenerator.Feature.QUOTE_FIELD_NAMES);
}
public void testParserFeatures()
{
// and also for mapper
ObjectMapper mapper = new ObjectMapper();
assertTrue(mapper.isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
assertFalse(mapper.isEnabled(JsonParser.Feature.ALLOW_COMMENTS));
mapper.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE,
JsonParser.Feature.STRICT_DUPLICATE_DETECTION);
assertFalse(mapper.isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
}
/*
/**********************************************************
/* Test methods, mapper.copy()
/**********************************************************
*/
// [databind#28]: ObjectMapper.copy()
public void testCopy() throws Exception
{
ObjectMapper m = new ObjectMapper();
assertTrue(m.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
m.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
assertFalse(m.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
InjectableValues inj = new InjectableValues.Std();
m.setInjectableValues(inj);
assertFalse(m.isEnabled(JsonParser.Feature.ALLOW_COMMENTS));
m.enable(JsonParser.Feature.ALLOW_COMMENTS);
assertTrue(m.isEnabled(JsonParser.Feature.ALLOW_COMMENTS));
// // First: verify that handling of features is decoupled:
ObjectMapper m2 = m.copy();
assertFalse(m2.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
m2.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
assertTrue(m2.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
assertSame(inj, m2.getInjectableValues());
// but should NOT change the original
assertFalse(m.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
// nor vice versa:
assertFalse(m.isEnabled(DeserializationFeature.UNWRAP_ROOT_VALUE));
assertFalse(m2.isEnabled(DeserializationFeature.UNWRAP_ROOT_VALUE));
m.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
assertTrue(m.isEnabled(DeserializationFeature.UNWRAP_ROOT_VALUE));
assertFalse(m2.isEnabled(DeserializationFeature.UNWRAP_ROOT_VALUE));
// // Also, underlying JsonFactory instances should be distinct
assertNotSame(m.getFactory(), m2.getFactory());
// [databind#122]: Need to ensure mix-ins are not shared
assertEquals(0, m.getSerializationConfig().mixInCount());
assertEquals(0, m2.getSerializationConfig().mixInCount());
assertEquals(0, m.getDeserializationConfig().mixInCount());
assertEquals(0, m2.getDeserializationConfig().mixInCount());
m.addMixIn(String.class, Integer.class);
assertEquals(1, m.getSerializationConfig().mixInCount());
assertEquals(0, m2.getSerializationConfig().mixInCount());
assertEquals(1, m.getDeserializationConfig().mixInCount());
assertEquals(0, m2.getDeserializationConfig().mixInCount());
// [databind#913]: Ensure JsonFactory Features copied
assertTrue(m2.isEnabled(JsonParser.Feature.ALLOW_COMMENTS));
}
// [databind#1580]
public void testCopyOfConfigOverrides() throws Exception
{
ObjectMapper m = new ObjectMapper();
SerializationConfig config = m.getSerializationConfig();
assertEquals(JsonInclude.Value.empty(), config.getDefaultPropertyInclusion());
assertEquals(JsonSetter.Value.empty(), config.getDefaultSetterInfo());
assertNull(config.getDefaultMergeable());
VisibilityChecker<?> defaultVis = config.getDefaultVisibilityChecker();
assertEquals(VisibilityChecker.Std.class, defaultVis.getClass());
// change
JsonInclude.Value customIncl = JsonInclude.Value.empty().withValueInclusion(JsonInclude.Include.NON_DEFAULT);
m.setDefaultPropertyInclusion(customIncl);
JsonSetter.Value customSetter = JsonSetter.Value.forValueNulls(Nulls.SKIP);
m.setDefaultSetterInfo(customSetter);
m.setDefaultMergeable(Boolean.TRUE);
VisibilityChecker<?> customVis = VisibilityChecker.Std.defaultInstance()
.withFieldVisibility(Visibility.ANY);
m.setVisibility(customVis);
assertSame(customVis, m.getVisibilityChecker());
// and verify that copy retains these settings
ObjectMapper m2 = m.copy();
SerializationConfig config2 = m2.getSerializationConfig();
assertSame(customIncl, config2.getDefaultPropertyInclusion());
assertSame(customSetter, config2.getDefaultSetterInfo());
assertEquals(Boolean.TRUE, config2.getDefaultMergeable());
assertSame(customVis, config2.getDefaultVisibilityChecker());
}
public void testFailedCopy() throws Exception
{
NoCopyMapper src = new NoCopyMapper();
try {
src.copy();
fail("Should not pass");
} catch (IllegalStateException e) {
verifyException(e, "does not override copy()");
}
}
public void testAnnotationIntrospectorCopyin()
{
ObjectMapper m = new ObjectMapper();
m.setAnnotationIntrospector(new MyAnnotationIntrospector());
assertEquals(MyAnnotationIntrospector.class,
m.getDeserializationConfig().getAnnotationIntrospector().getClass());
ObjectMapper m2 = m.copy();
assertEquals(MyAnnotationIntrospector.class,
m2.getDeserializationConfig().getAnnotationIntrospector().getClass());
assertEquals(MyAnnotationIntrospector.class,
m2.getSerializationConfig().getAnnotationIntrospector().getClass());
}
/*
/**********************************************************
/* Test methods, other
/**********************************************************
*/
public void testProps()
{
ObjectMapper m = new ObjectMapper();
// should have default factory
assertNotNull(m.getNodeFactory());
JsonNodeFactory nf = new JsonNodeFactory(true);
m.setNodeFactory(nf);
assertNull(m.getInjectableValues());
assertSame(nf, m.getNodeFactory());
}
// Test to ensure that we can check property ordering defaults...
public void testConfigForPropertySorting() throws Exception
{
ObjectMapper m = new ObjectMapper();
// sort-alphabetically is disabled by default:
assertFalse(m.isEnabled(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY));
SerializationConfig sc = m.getSerializationConfig();
assertFalse(sc.isEnabled(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY));
assertFalse(sc.shouldSortPropertiesAlphabetically());
DeserializationConfig dc = m.getDeserializationConfig();
assertFalse(dc.shouldSortPropertiesAlphabetically());
// but when enabled, should be visible:
m.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);
sc = m.getSerializationConfig();
assertTrue(sc.isEnabled(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY));
assertTrue(sc.shouldSortPropertiesAlphabetically());
dc = m.getDeserializationConfig();
// and not just via SerializationConfig, but also via DeserializationConfig
assertTrue(dc.isEnabled(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY));
assertTrue(dc.shouldSortPropertiesAlphabetically());
}
public void testJsonFactoryLinkage()
{
// first, implicit factory, giving implicit linkage
assertSame(MAPPER, MAPPER.getFactory().getCodec());
// and then explicit factory, which should also be implicitly linked
JsonFactory f = new JsonFactory();
ObjectMapper m = new ObjectMapper(f);
assertSame(f, m.getFactory());
assertSame(m, f.getCodec());
}
public void testProviderConfig() throws Exception
{
ObjectMapper m = new ObjectMapper();
final String JSON = "{ \"x\" : 3 }";
assertEquals(0, m._deserializationContext._cache.cachedDeserializersCount());
// and then should get one constructed for:
Bean bean = m.readValue(JSON, Bean.class);
assertNotNull(bean);
// Since 2.6, serializer for int also cached:
assertEquals(2, m._deserializationContext._cache.cachedDeserializersCount());
m._deserializationContext._cache.flushCachedDeserializers();
assertEquals(0, m._deserializationContext._cache.cachedDeserializersCount());
// 07-Nov-2014, tatu: As per [databind#604] verify that Maps also get cached
m = new ObjectMapper();
List<?> stuff = m.readValue("[ ]", List.class);
assertNotNull(stuff);
// may look odd, but due to "Untyped" deserializer thing, we actually have
// 4 deserializers (int, List<?>, Map<?,?>, Object)
assertEquals(4, m._deserializationContext._cache.cachedDeserializersCount());
}
// For [databind#689]
public void testCustomDefaultPrettyPrinter() throws Exception
{
final ObjectMapper m = new ObjectMapper();
final int[] input = new int[] { 1, 2 };
// without anything else, compact:
assertEquals("[1,2]", m.writeValueAsString(input));
// or with default, get... defaults:
m.enable(SerializationFeature.INDENT_OUTPUT);
assertEquals("[ 1, 2 ]", m.writeValueAsString(input));
assertEquals("[ 1, 2 ]", m.writerWithDefaultPrettyPrinter().writeValueAsString(input));
assertEquals("[ 1, 2 ]", m.writer().withDefaultPrettyPrinter().writeValueAsString(input));
// but then with our custom thingy...
m.setDefaultPrettyPrinter(new FooPrettyPrinter());
assertEquals("[1 , 2]", m.writeValueAsString(input));
assertEquals("[1 , 2]", m.writerWithDefaultPrettyPrinter().writeValueAsString(input));
assertEquals("[1 , 2]", m.writer().withDefaultPrettyPrinter().writeValueAsString(input));
// and yet, can disable too
assertEquals("[1,2]", m.writer().without(SerializationFeature.INDENT_OUTPUT)
.writeValueAsString(input));
}
// For [databind#703], [databind#978]
public void testNonSerializabilityOfObject()
{
ObjectMapper m = new ObjectMapper();
assertFalse(m.canSerialize(Object.class));
// but this used to pass, incorrectly, second time around
assertFalse(m.canSerialize(Object.class));
// [databind#978]: Different answer if empty Beans ARE allowed
m = new ObjectMapper();
m.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
assertTrue(m.canSerialize(Object.class));
assertTrue(MAPPER.writer().without(SerializationFeature.FAIL_ON_EMPTY_BEANS)
.canSerialize(Object.class));
assertFalse(MAPPER.writer().with(SerializationFeature.FAIL_ON_EMPTY_BEANS)
.canSerialize(Object.class));
}
// for [databind#756]
public void testEmptyBeanSerializability()
{
// with default settings, error
assertFalse(MAPPER.writer().with(SerializationFeature.FAIL_ON_EMPTY_BEANS)
.canSerialize(EmptyBean.class));
// but with changes
assertTrue(MAPPER.writer().without(SerializationFeature.FAIL_ON_EMPTY_BEANS)
.canSerialize(EmptyBean.class));
}
// for [databind#898]
public void testSerializerProviderAccess() throws Exception
{
// ensure we have "fresh" instance, just in case
ObjectMapper mapper = new ObjectMapper();
JsonSerializer<?> ser = mapper.getSerializerProviderInstance()
.findValueSerializer(Bean.class);
assertNotNull(ser);
assertEquals(Bean.class, ser.handledType());
}
// for [databind#1074]
public void testCopyOfParserFeatures() throws Exception
{
// ensure we have "fresh" instance to start with
ObjectMapper mapper = new ObjectMapper();
assertFalse(mapper.isEnabled(JsonParser.Feature.ALLOW_COMMENTS));
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
assertTrue(mapper.isEnabled(JsonParser.Feature.ALLOW_COMMENTS));
ObjectMapper copy = mapper.copy();
assertTrue(copy.isEnabled(JsonParser.Feature.ALLOW_COMMENTS));
// also verify there's no back-linkage
copy.configure(JsonParser.Feature.ALLOW_COMMENTS, false);
assertFalse(copy.isEnabled(JsonParser.Feature.ALLOW_COMMENTS));
assertTrue(mapper.isEnabled(JsonParser.Feature.ALLOW_COMMENTS));
}
// since 2.8
public void testDataOutputViaMapper() throws Exception
{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
ObjectNode input = MAPPER.createObjectNode();
input.put("a", 1);
DataOutput data = new DataOutputStream(bytes);
final String exp = "{\"a\":1}";
MAPPER.writeValue(data, input);
assertEquals(exp, bytes.toString("UTF-8"));
// and also via ObjectWriter...
bytes.reset();
data = new DataOutputStream(bytes);
MAPPER.writer().writeValue(data, input);
assertEquals(exp, bytes.toString("UTF-8"));
}
// since 2.8
@SuppressWarnings("unchecked")
public void testDataInputViaMapper() throws Exception
{
byte[] src = "{\"a\":1}".getBytes("UTF-8");
DataInput input = new DataInputStream(new ByteArrayInputStream(src));
Map<String,Object> map = (Map<String,Object>) MAPPER.readValue(input, Map.class);
assertEquals(Integer.valueOf(1), map.get("a"));
input = new DataInputStream(new ByteArrayInputStream(src));
// and via ObjectReader
map = MAPPER.readerFor(Map.class)
.readValue(input);
assertEquals(Integer.valueOf(1), map.get("a"));
input = new DataInputStream(new ByteArrayInputStream(src));
JsonNode n = MAPPER.readerFor(Map.class)
.readTree(input);
assertNotNull(n);
}
}