| |
| 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()); |
| } |
| } |