blob: f7b2f86403e58d3e2a0de310783bd1b69452a7d3 [file] [log] [blame]
package com.fasterxml.jackson.databind.deser.creators;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
public class TestCreators2 extends BaseMapTest
{
static class HashTest
{
final byte[] bytes;
final String type;
@JsonCreator
public HashTest(@JsonProperty("bytes") @JsonDeserialize(using = BytesDeserializer.class) final byte[] bytes,
@JsonProperty("type") final String type)
{
this.bytes = bytes;
this.type = type;
}
}
static class BytesDeserializer extends JsonDeserializer<byte[]>
{
@Override
public byte[] deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
String str = jp.getText();
return str.getBytes("UTF-8");
}
}
static class Primitives
{
protected int x = 3;
protected double d = -0.5;
protected boolean b = true;
@JsonCreator
public Primitives(@JsonProperty("x") int x,
@JsonProperty("d") double d,
@JsonProperty("b") boolean b)
{
this.x = x;
this.d = d;
this.b = b;
}
}
protected static class Test431Container {
protected final List<Item431> items;
@JsonCreator
public Test431Container(@JsonProperty("items") final List<Item431> i) {
items = i;
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
protected static class Item431 {
protected final String id;
@JsonCreator
public Item431(@JsonProperty("id") String id) {
this.id = id;
}
}
// Test class for verifying that creator-call failures are reported as checked exceptions
static class BeanFor438 {
@JsonCreator
public BeanFor438(@JsonProperty("name") String s) {
throw new IllegalArgumentException("I don't like that name!");
}
}
// For [JACKSON-470]: should be appropriately detected, reported error about
static class BrokenCreatorBean
{
protected String bar;
@JsonCreator
public BrokenCreatorBean(@JsonProperty("bar") String bar1, @JsonProperty("bar") String bar2) {
bar = ""+bar1+"/"+bar2;
}
}
// For [JACKSON-541]: should not need @JsonCreator if SerializationFeature.AUTO_DETECT_CREATORS is on.
static class AutoDetectConstructorBean
{
protected final String foo;
protected final String bar;
public AutoDetectConstructorBean(@JsonProperty("bar") String bar,
@JsonProperty("foo") String foo){
this.bar = bar;
this.foo = foo;
}
}
static class BustedCtor {
@JsonCreator
BustedCtor(@JsonProperty("a") String value) {
throw new IllegalArgumentException("foobar");
}
}
static class IgnoredCtor
{
@JsonIgnore
public IgnoredCtor(String arg) {
throw new RuntimeException("Should never use this constructor");
}
public IgnoredCtor() { }
}
abstract static class AbstractBase {
@JsonCreator
public static AbstractBase create(Map<String,Object> props)
{
return new AbstractBaseImpl(props);
}
}
static class AbstractBaseImpl extends AbstractBase
{
protected Map<String,Object> props;
public AbstractBaseImpl(Map<String,Object> props) {
this.props = props;
}
}
static interface Issue700Set extends java.util.Set<Object> { }
static class Issue700Bean
{
protected Issue700Set item;
@JsonCreator
public Issue700Bean(@JsonProperty("item") String item) { }
public String getItem() { return null; }
}
static final class MultiPropCreator1476 {
private final int intField;
private final String stringField;
public MultiPropCreator1476(@JsonProperty("intField") int intField) {
this(intField, "empty");
}
public MultiPropCreator1476(@JsonProperty("stringField") String stringField) {
this(-1, stringField);
}
@JsonCreator
public MultiPropCreator1476(@JsonProperty("intField") int intField,
@JsonProperty("stringField") String stringField) {
this.intField = intField;
this.stringField = stringField;
}
public int getIntField() {
return intField;
}
public String getStringField() {
return stringField;
}
}
/*
/**********************************************************
/* Test methods
/**********************************************************
*/
private final ObjectMapper MAPPER = new ObjectMapper();
public void testExceptionFromConstructor() throws Exception
{
try {
MAPPER.readValue("{}", BustedCtor.class);
fail("Expected exception");
} catch (JsonMappingException e) {
verifyException(e, ": foobar");
// also: should have nested exception
Throwable t = e.getCause();
if (t == null) {
fail("Should have assigned cause for: ("+e.getClass().getSimpleName()+") "+e);
}
assertNotNull(t);
assertEquals(IllegalArgumentException.class, t.getClass());
assertEquals("foobar", t.getMessage());
}
}
public void testSimpleConstructor() throws Exception
{
HashTest test = MAPPER.readValue("{\"type\":\"custom\",\"bytes\":\"abc\" }", HashTest.class);
assertEquals("custom", test.type);
assertEquals("abc", new String(test.bytes, "UTF-8"));
}
// Test for [JACKSON-372]
public void testMissingPrimitives() throws Exception
{
Primitives p = MAPPER.readValue("{}", Primitives.class);
assertFalse(p.b);
assertEquals(0, p.x);
assertEquals(0.0, p.d);
}
public void testJackson431() throws Exception
{
final Test431Container foo = MAPPER.readValue(
"{\"items\":\n"
+"[{\"bar\": 0,\n"
+"\"id\": \"id123\",\n"
+"\"foo\": 1\n"
+"}]}",
Test431Container.class);
assertNotNull(foo);
}
// Catch and re-throw exceptions that Creator methods throw
public void testJackson438() throws Exception
{
Exception e = null;
try {
MAPPER.readValue("{ \"name\":\"foobar\" }", BeanFor438.class);
fail("Should have failed");
} catch (Exception e0) {
e = e0;
}
if (!(e instanceof JsonMappingException)) {
fail("Should have received JsonMappingException, caught "+e.getClass().getName());
}
verifyException(e, "don't like that name");
// Ok: also, let's ensure root cause is directly linked, without other extra wrapping:
Throwable t = e.getCause();
if (t == null) {
fail("Should have assigned cause for: ("+e.getClass().getSimpleName()+") "+e);
}
assertEquals(IllegalArgumentException.class, t.getClass());
verifyException(e, "don't like that name");
}
public void testCreatorWithDupNames() throws Exception
{
try {
MAPPER.readValue("{\"bar\":\"x\"}", BrokenCreatorBean.class);
fail("Should have caught duplicate creator parameters");
} catch (JsonMappingException e) {
verifyException(e, "duplicate creator property \"bar\"");
verifyException(e, "for type `com.fasterxml.jackson.databind.");
verifyException(e, "$BrokenCreatorBean`");
}
}
public void testCreatorMultipleArgumentWithoutAnnotation() throws Exception {
AutoDetectConstructorBean value = MAPPER.readValue("{\"bar\":\"bar\",\"foo\":\"foo\"}",
AutoDetectConstructorBean.class);
assertEquals("bar", value.bar);
assertEquals("foo", value.foo);
}
public void testIgnoredSingleArgCtor() throws Exception
{
try {
MAPPER.readValue(quote("abc"), IgnoredCtor.class);
fail("Should have caught missing constructor problem");
} catch (JsonMappingException e) {
verifyException(e, "no String-argument constructor/factory method");
}
}
public void testAbstractFactory() throws Exception
{
AbstractBase bean = MAPPER.readValue("{\"a\":3}", AbstractBase.class);
assertNotNull(bean);
AbstractBaseImpl impl = (AbstractBaseImpl) bean;
assertEquals(1, impl.props.size());
assertEquals(Integer.valueOf(3), impl.props.get("a"));
}
public void testCreatorProperties() throws Exception
{
Issue700Bean value = MAPPER.readValue("{ \"item\" : \"foo\" }", Issue700Bean.class);
assertNotNull(value);
}
// [databind#1476]
public void testConstructorChoice() throws Exception {
ObjectMapper mapper = new ObjectMapper();
MultiPropCreator1476 pojo = mapper.readValue("{ \"intField\": 1, \"stringField\": \"foo\" }",
MultiPropCreator1476.class);
assertEquals(1, pojo.getIntField());
assertEquals("foo", pojo.getStringField());
}
}