package com.fasterxml.jackson.databind.convert;
import java.util.LinkedHashMap;
import java.util.Map;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.util.StdConverter;
/**
* Tests for various conversions, especially ones using
* {@link ObjectMapper#convertValue(Object, Class)}.
*/
public class TestBeanConversions
extends com.fasterxml.jackson.databind.BaseMapTest
{
static class PointZ {
public int x, y;
public int z = -13;
public PointZ() { }
public PointZ(int a, int b, int c)
{
x = a;
y = b;
z = c;
}
}
static class PointStrings {
public final String x, y;
public PointStrings(String x, String y) {
this.x = x;
this.y = y;
}
}
public static class BooleanBean {
public boolean boolProp;
}
static class WrapperBean {
public BooleanBean x;
}
static class ObjectWrapper
{
private Object data;
public ObjectWrapper() { }
public ObjectWrapper(Object o) { data = o; }
public Object getData() { return data; }
public void setData(Object data) { this.data = data; }
}
static class Leaf {
public int value;
public Leaf() { }
public Leaf(int v) { value = v; }
}
// [databind#288]
@JsonSerialize(converter = ConvertingBeanConverter.class)
static class ConvertingBean {
public int x, y;
public ConvertingBean(int v1, int v2) {
x = v1;
y = v2;
}
}
public static class DummyBean {
public final int a, b;
public DummyBean(int v1, int v2) {
a = v1 * 2;
b = v2 * 2;
}
}
static class ConvertingBeanConverter extends StdConverter<ConvertingBean, DummyBean>
{
@Override
public DummyBean convert(ConvertingBean cb) {
return new DummyBean(cb.x, cb.y);
}
}
@JsonDeserialize(using = NullBeanDeserializer.class)
static class NullBean {
public static final NullBean NULL_INSTANCE = new NullBean();
}
static class NullBeanDeserializer extends JsonDeserializer<NullBean> {
@Override
public NullBean getNullValue(final DeserializationContext context) {
return NullBean.NULL_INSTANCE;
}
@Override
public NullBean deserialize(final JsonParser parser, final DeserializationContext context) {
throw new UnsupportedOperationException();
}
}
/*
/**********************************************************
/* Test methods
/**********************************************************
*/
private final ObjectMapper MAPPER = new ObjectMapper();
public void testBeanConvert()
{
// should have no problems convert between compatible beans...
PointStrings input = new PointStrings("37", "-9");
PointZ point = MAPPER.convertValue(input, PointZ.class);
assertEquals(37, point.x);
assertEquals(-9, point.y);
// z not included in input, will be whatever default constructor provides
assertEquals(-13, point.z);
}
// For [JACKSON-371]; verify that we know property that caused issue...
// (note: not optimal place for test, but will have to do for now)
public void testErrorReporting() throws Exception
{
//String json = "{\"boolProp\":\"oops\"}";
// First: unknown property
try {
MAPPER.readValue("{\"unknownProp\":true}", BooleanBean.class);
} catch (JsonProcessingException e) {
verifyException(e, "unknownProp");
}
// then bad conversion
try {
MAPPER.readValue("{\"boolProp\":\"foobar\"}", BooleanBean.class);
} catch (JsonMappingException e) {
verifyException(e, "Can not deserialize value of type boolean from String");
}
}
public void testIssue458() throws Exception
{
ObjectWrapper a = new ObjectWrapper("foo");
ObjectWrapper b = new ObjectWrapper(a);
ObjectWrapper b2 = MAPPER.convertValue(b, ObjectWrapper.class);
ObjectWrapper a2 = MAPPER.convertValue(b2.getData(), ObjectWrapper.class);
assertEquals("foo", a2.getData());
}
// should work regardless of wrapping...
public void testWrapping() throws Exception
{
ObjectMapper wrappingMapper = new ObjectMapper();
wrappingMapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
wrappingMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
// conversion is ok, even if it's bogus one
_convertAndVerifyPoint(wrappingMapper);
// also: ok to have mismatched settings, since as per [JACKSON-710], should
// not actually use wrapping internally in these cases
wrappingMapper = new ObjectMapper();
wrappingMapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
wrappingMapper.disable(SerializationFeature.WRAP_ROOT_VALUE);
_convertAndVerifyPoint(wrappingMapper);
wrappingMapper = new ObjectMapper();
wrappingMapper.disable(DeserializationFeature.UNWRAP_ROOT_VALUE);
wrappingMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
_convertAndVerifyPoint(wrappingMapper);
}
// [Issue-11]: simple cast, for POJOs etc
public void testConvertUsingCast() throws Exception
{
String str = new String("foo");
CharSequence seq = str;
String result = MAPPER.convertValue(seq, String.class);
// should just cast...
assertSame(str, result);
}
// [Issue-11]: simple cast, for Tree
public void testNodeConvert() throws Exception
{
ObjectNode src = (ObjectNode) MAPPER.readTree("{}");
TreeNode node = src;
ObjectNode result = MAPPER.treeToValue(node, ObjectNode.class);
// should just cast...
assertSame(src, result);
}
private void _convertAndVerifyPoint(ObjectMapper m)
{
final PointZ input = new PointZ(1, 2, 3);
PointZ output = m.convertValue(input, PointZ.class);
assertEquals(1, output.x);
assertEquals(2, output.y);
assertEquals(3, output.z);
}
/**
* Need to test "shortcuts" introduced by [databind#11]
*/
public void testIssue11() throws Exception
{
// First the expected use case, Node specification
ObjectNode root = MAPPER.createObjectNode();
JsonNode n = root;
ObjectNode ob2 = MAPPER.convertValue(n, ObjectNode.class);
assertSame(root, ob2);
JsonNode n2 = MAPPER.convertValue(n, JsonNode.class);
assertSame(root, n2);
// then some other no-op conversions
String STR = "test";
CharSequence seq = MAPPER.convertValue(STR, CharSequence.class);
assertSame(STR, seq);
// and then something that should NOT use short-cut
Leaf l = new Leaf(13);
Map<?,?> m = MAPPER.convertValue(l, Map.class);
assertNotNull(m);
assertEquals(1, m.size());
assertEquals(Integer.valueOf(13), m.get("value"));
// and reverse too
Leaf l2 = MAPPER.convertValue(m, Leaf.class);
assertEquals(13, l2.value);
// also; ok to use "untyped" (Object):
Object ob = MAPPER.convertValue(l, Object.class);
assertNotNull(ob);
assertEquals(LinkedHashMap.class, ob.getClass());
// And one more: this time with a minor twist
final Object plaino = new Object();
// first, a failed attempt:
try {
m = MAPPER.convertValue(plaino, Map.class);
fail("Conversion should have failed");
} catch (IllegalArgumentException e) {
verifyException(e, "no properties discovered");
}
ObjectMapper mapper = new ObjectMapper();
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
try {
assertEquals("{}", mapper.writeValueAsString(plaino));
} catch (Exception e) {
throw (Exception) e.getCause();
}
// should now work, via serialization/deserialization:
m = mapper.convertValue(plaino, Map.class);
assertNotNull(m);
assertEquals(0, m.size());
}
public void testConversionIssue288() throws Exception
{
String json = MAPPER.writeValueAsString(new ConvertingBean(1, 2));
// must be {"a":2,"b":4}
assertEquals("{\"a\":2,\"b\":4}", json);
}
// Test null conversions from [databind#1433]
public void testConversionIssue1433() throws Exception
{
assertNull(MAPPER.convertValue(null, Object.class));
assertNull(MAPPER.convertValue(null, PointZ.class));
assertSame(NullBean.NULL_INSTANCE,
MAPPER.convertValue(null, NullBean.class));
}
}