aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatu Saloranta <tsaloranta@gmail.com>2011-12-27 20:48:48 -0800
committerTatu Saloranta <tsaloranta@gmail.com>2011-12-27 20:48:48 -0800
commitf1c5f8f392069401c1daaa6601cc45cbf9f5fd34 (patch)
tree5991d78ad4b07e84b239d4c6f5712e6285f679da
parentffbadea73497dbd251c17172ec7054518e291704 (diff)
downloadjackson-databind-f1c5f8f392069401c1daaa6601cc45cbf9f5fd34.tar.gz
Refactoring to improve grouping of deserializers
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/KeyDeserializers.java2
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/StdDeserializers.java82
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/CalendarDeserializer.java47
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializer.java28
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializers.java157
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java187
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/JacksonDeserializers.java84
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/JavaTypeDeserializer.java37
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/JdkDeserializers.java272
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/NumberDeserializers.java445
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java470
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java10
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/StringDeserializer.java3
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/TimestampDeserializer.java28
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/deser/std/TokenBufferDeserializer.java36
-rw-r--r--src/test/java/com/fasterxml/jackson/databind/deser/TestAnyProperties.java33
-rw-r--r--src/test/java/com/fasterxml/jackson/databind/introspect/TestPOJOPropertiesCollector.java33
17 files changed, 1057 insertions, 897 deletions
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/KeyDeserializers.java b/src/main/java/com/fasterxml/jackson/databind/deser/KeyDeserializers.java
index 141648f7c..5dad1d0c0 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/KeyDeserializers.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/KeyDeserializers.java
@@ -16,8 +16,6 @@ import com.fasterxml.jackson.databind.KeyDeserializer;
* does not support handling of the type. In latter case, further calls can be made
* for other providers; in former case returned key deserializer is used for handling of
* key instances of specified type.
- *
- * @since 1.8
*/
public interface KeyDeserializers
{
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/StdDeserializers.java b/src/main/java/com/fasterxml/jackson/databind/deser/StdDeserializers.java
index 4cca7f76e..07f587ad4 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/StdDeserializers.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/StdDeserializers.java
@@ -3,25 +3,11 @@ package com.fasterxml.jackson.databind.deser;
import java.util.*;
import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.deser.std.AtomicBooleanDeserializer;
-import com.fasterxml.jackson.databind.deser.std.CalendarDeserializer;
-import com.fasterxml.jackson.databind.deser.std.ClassDeserializer;
-import com.fasterxml.jackson.databind.deser.std.DateDeserializer;
-import com.fasterxml.jackson.databind.deser.std.FromStringDeserializer;
-import com.fasterxml.jackson.databind.deser.std.JavaTypeDeserializer;
-import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
-import com.fasterxml.jackson.databind.deser.std.TimestampDeserializer;
-import com.fasterxml.jackson.databind.deser.std.TokenBufferDeserializer;
-import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;
+import com.fasterxml.jackson.databind.deser.std.*;
import com.fasterxml.jackson.databind.type.*;
/**
* Helper class used to contain simple/well-known deserializers for core JDK types.
- *<p>
- * Note: as of Jackson 1.9, we use type-erased class for registering, since
- * some types may come either as type-erased or typed (for example,
- * <code>java.lang.Class</code>).
*/
class StdDeserializers
{
@@ -37,62 +23,19 @@ class StdDeserializers
StdDeserializer<?> strDeser = new StringDeserializer();
add(strDeser, String.class);
add(strDeser, CharSequence.class);
- add(new ClassDeserializer());
- // Then primitive-wrappers (simple):
- add(new StdDeserializer.BooleanDeserializer(Boolean.class, null));
- add(new StdDeserializer.ByteDeserializer(Byte.class, null));
- add(new StdDeserializer.ShortDeserializer(Short.class, null));
- add(new StdDeserializer.CharacterDeserializer(Character.class, null));
- add(new StdDeserializer.IntegerDeserializer(Integer.class, null));
- add(new StdDeserializer.LongDeserializer(Long.class, null));
- add(new StdDeserializer.FloatDeserializer(Float.class, null));
- add(new StdDeserializer.DoubleDeserializer(Double.class, null));
-
- /* And actual primitives: difference is the way nulls are to be
- * handled...
- */
- add(new StdDeserializer.BooleanDeserializer(Boolean.TYPE, Boolean.FALSE));
- add(new StdDeserializer.ByteDeserializer(Byte.TYPE, Byte.valueOf((byte)(0))));
- add(new StdDeserializer.ShortDeserializer(Short.TYPE, Short.valueOf((short)0)));
- add(new StdDeserializer.CharacterDeserializer(Character.TYPE, Character.valueOf('\0')));
- add(new StdDeserializer.IntegerDeserializer(Integer.TYPE, Integer.valueOf(0)));
- add(new StdDeserializer.LongDeserializer(Long.TYPE, Long.valueOf(0L)));
- add(new StdDeserializer.FloatDeserializer(Float.TYPE, Float.valueOf(0.0f)));
- add(new StdDeserializer.DoubleDeserializer(Double.TYPE, Double.valueOf(0.0)));
-
- // and related
- add(new StdDeserializer.NumberDeserializer());
- add(new StdDeserializer.BigDecimalDeserializer());
- add(new StdDeserializer.BigIntegerDeserializer());
-
- add(new CalendarDeserializer());
- add(new DateDeserializer());
- /* 24-Jan-2010, tatu: When including type information, we may
- * know that we specifically need GregorianCalendar...
- */
- add(new CalendarDeserializer(GregorianCalendar.class),
- GregorianCalendar.class);
- add(new StdDeserializer.SqlDateDeserializer());
- add(new TimestampDeserializer());
-
- // From-string deserializers:
- for (StdDeserializer<?> deser : FromStringDeserializer.all()) {
- add(deser);
- }
-
- // And finally some odds and ends
-
- // to deserialize Throwable, need stack trace elements:
- add(new StdDeserializer.StackTraceElementDeserializer());
+ // Primitives/wrappers, other Numbers:
+ add(NumberDeserializers.all());
+ // Date/time types
+ add(DateDeserializers.all());
+ // other JDK types
+ add(JdkDeserializers.all());
// [JACKSON-283] need to support atomic types, too
// (note: AtomicInteger/Long work due to single-arg constructor)
add(new AtomicBooleanDeserializer());
- // including some core Jackson types:
- add(new TokenBufferDeserializer());
- add(new JavaTypeDeserializer());
+ add(JacksonDeserializers.all());
}
/**
@@ -103,8 +46,13 @@ class StdDeserializers
return new StdDeserializers()._deserializers;
}
- private void add(StdDeserializer<?> stdDeser)
- {
+ private void add(StdDeserializer<?>[] serializers) {
+ for (StdDeserializer<?> ser : serializers) {
+ add(ser, ser.getValueClass());
+ }
+ }
+
+ private void add(StdDeserializer<?> stdDeser) {
add(stdDeser, stdDeser.getValueClass());
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/CalendarDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/CalendarDeserializer.java
deleted file mode 100644
index 8f7151196..000000000
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/CalendarDeserializer.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.fasterxml.jackson.databind.deser.std;
-
-import java.io.IOException;
-import java.util.Calendar;
-import java.util.Date;
-
-import com.fasterxml.jackson.core.*;
-
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
-
-@JacksonStdImpl
-public class CalendarDeserializer
- extends StdScalarDeserializer<Calendar>
-{
- /**
- * We may know actual expected type; if so, it will be
- * used for instantiation.
- */
- protected final Class<? extends Calendar> _calendarClass;
-
- public CalendarDeserializer() { this(null); }
- public CalendarDeserializer(Class<? extends Calendar> cc) {
- super(Calendar.class);
- _calendarClass = cc;
- }
-
- @Override
- public Calendar deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- Date d = _parseDate(jp, ctxt);
- if (d == null) {
- return null;
- }
- if (_calendarClass == null) {
- return ctxt.constructCalendar(d);
- }
- try {
- Calendar c = _calendarClass.newInstance();
- c.setTimeInMillis(d.getTime());
- return c;
- } catch (Exception e) {
- throw ctxt.instantiationException(_calendarClass, e);
- }
- }
-}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializer.java
deleted file mode 100644
index 6a17b120f..000000000
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializer.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.fasterxml.jackson.databind.deser.std;
-
-import java.io.IOException;
-import java.util.Date;
-
-import com.fasterxml.jackson.core.*;
-
-import com.fasterxml.jackson.databind.DeserializationContext;
-
-/**
- * Simple deserializer for handling {@link java.util.Date} values.
- *<p>
- * One way to customize Date formats accepted is to override method
- * {@link DeserializationContext#parseDate} that this basic
- * deserializer calls.
- */
-public class DateDeserializer
- extends StdScalarDeserializer<Date>
-{
- public DateDeserializer() { super(Date.class); }
-
- @Override
- public java.util.Date deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- return _parseDate(jp, ctxt);
- }
-}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializers.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializers.java
new file mode 100644
index 000000000..4e6c56d22
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/DateDeserializers.java
@@ -0,0 +1,157 @@
+package com.fasterxml.jackson.databind.deser.std;
+
+import java.io.IOException;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
+
+/**
+ * Container class for core JDK date/time type deserializers.
+ */
+public class DateDeserializers
+{
+ public static StdDeserializer<?>[] all()
+ {
+ return new StdDeserializer[] {
+ new CalendarDeserializer(), // for nominal type of java.util.Calendar
+ new DateDeserializer(),
+ /* 24-Jan-2010, tatu: When including type information, we may
+ * know that we specifically need GregorianCalendar...
+ */
+ new CalendarDeserializer(GregorianCalendar.class),
+ new SqlDateDeserializer(),
+ new TimestampDeserializer(),
+ new TimeZoneDeserializer()
+ };
+ }
+
+ /*
+ /**********************************************************
+ /* Deserializer implementations
+ /**********************************************************
+ */
+
+ @JacksonStdImpl
+ public static class CalendarDeserializer
+ extends StdScalarDeserializer<Calendar>
+ {
+ /**
+ * We may know actual expected type; if so, it will be
+ * used for instantiation.
+ */
+ protected final Class<? extends Calendar> _calendarClass;
+
+ public CalendarDeserializer() {
+ super(Calendar.class);
+ _calendarClass = null;
+ }
+
+ public CalendarDeserializer(Class<? extends Calendar> cc) {
+ super(cc);
+ _calendarClass = cc;
+ }
+
+ @Override
+ public Calendar deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ Date d = _parseDate(jp, ctxt);
+ if (d == null) {
+ return null;
+ }
+ if (_calendarClass == null) {
+ return ctxt.constructCalendar(d);
+ }
+ try {
+ Calendar c = _calendarClass.newInstance();
+ c.setTimeInMillis(d.getTime());
+ return c;
+ } catch (Exception e) {
+ throw ctxt.instantiationException(_calendarClass, e);
+ }
+ }
+ }
+
+ /**
+ * Simple deserializer for handling {@link java.util.Date} values.
+ *<p>
+ * One way to customize Date formats accepted is to override method
+ * {@link DeserializationContext#parseDate} that this basic
+ * deserializer calls.
+ */
+ public static class DateDeserializer
+ extends StdScalarDeserializer<Date>
+ {
+ public DateDeserializer() { super(Date.class); }
+
+ @Override
+ public java.util.Date deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ return _parseDate(jp, ctxt);
+ }
+ }
+
+ /**
+ * Compared to plain old {@link java.util.Date}, SQL version is easier
+ * to deal with: mostly because it is more limited.
+ */
+ public static class SqlDateDeserializer
+ extends StdScalarDeserializer<java.sql.Date>
+ {
+ public SqlDateDeserializer() { super(java.sql.Date.class); }
+
+ @Override
+ public java.sql.Date deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ Date d = _parseDate(jp, ctxt);
+ return (d == null) ? null : new java.sql.Date(d.getTime());
+ }
+ }
+
+ /**
+ * Simple deserializer for handling {@link java.sql.Timestamp} values.
+ *<p>
+ * One way to customize Timestamp formats accepted is to override method
+ * {@link DeserializationContext#parseDate} that this basic
+ * deserializer calls.
+ */
+ public static class TimestampDeserializer
+ extends StdScalarDeserializer<Timestamp>
+ {
+ public TimestampDeserializer() { super(Timestamp.class); }
+
+ @Override
+ public java.sql.Timestamp deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ return new Timestamp(_parseDate(jp, ctxt).getTime());
+ }
+ }
+
+ /**
+ * As per [JACKSON-522], also need special handling for TimeZones
+ *
+ * @since 1.7.4
+ */
+ protected static class TimeZoneDeserializer
+ extends FromStringDeserializer<TimeZone>
+ {
+ public TimeZoneDeserializer() { super(TimeZone.class); }
+
+ @Override
+ protected TimeZone _deserialize(String value, DeserializationContext ctxt)
+ throws IOException
+ {
+ return TimeZone.getTimeZone(value);
+ }
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java
index 6f9eaf87a..660ec3d59 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/FromStringDeserializer.java
@@ -1,21 +1,14 @@
package com.fasterxml.jackson.databind.deser.std;
import java.io.*;
-import java.net.InetAddress;
-import java.net.URI;
-import java.net.URL;
-import java.util.*;
-import java.util.regex.Pattern;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.DeserializationContext;
/**
- * Base class for simple deserializer which only accept JSON String
+ * Base class for simple deserializers that only accept JSON String
* values as the source.
- *
- * @since 1.9 (moved from higher-level package)
*/
public abstract class FromStringDeserializer<T>
extends StdScalarDeserializer<T>
@@ -24,23 +17,11 @@ public abstract class FromStringDeserializer<T>
super(vc);
}
- public static Iterable<FromStringDeserializer<?>>all()
- {
- ArrayList<FromStringDeserializer<?>> all = new ArrayList<FromStringDeserializer<?>>();
-
- all.add(new UUIDDeserializer());
- all.add(new URLDeserializer());
- all.add(new URIDeserializer());
- all.add(new CurrencyDeserializer());
- all.add(new PatternDeserializer());
- // since 1.7:
- all.add(new LocaleDeserializer());
- // 1.8:
- all.add(new InetAddressDeserializer());
- all.add(new TimeZoneDeserializer());
-
- return all;
- }
+ /*
+ /**********************************************************
+ /* Deserializer implementations
+ /**********************************************************
+ */
@SuppressWarnings("unchecked")
@Override
@@ -87,161 +68,5 @@ public abstract class FromStringDeserializer<T>
throw ctxt.mappingException("Don't know how to convert embedded Object of type "
+ob.getClass().getName()+" into "+_valueClass.getName());
}
-
- /*
- /**********************************************************
- /* Then concrete implementations
- /**********************************************************
- */
-
- public static class UUIDDeserializer
- extends FromStringDeserializer<UUID>
- {
- public UUIDDeserializer() { super(UUID.class); }
- @Override
- protected UUID _deserialize(String value, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- return UUID.fromString(value);
- }
-
- @Override
- protected UUID _deserializeEmbedded(Object ob, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- if (ob instanceof byte[]) {
- byte[] bytes = (byte[]) ob;
- if (bytes.length != 16) {
- ctxt.mappingException("Can only construct UUIDs from 16 byte arrays; got "+bytes.length+" bytes");
- }
- // clumsy, but should work for now...
- DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes));
- long l1 = in.readLong();
- long l2 = in.readLong();
- return new UUID(l1, l2);
- }
- super._deserializeEmbedded(ob, ctxt);
- return null; // never gets here
- }
- }
-
- public static class URLDeserializer
- extends FromStringDeserializer<URL>
- {
- public URLDeserializer() { super(URL.class); }
-
- @Override
- protected URL _deserialize(String value, DeserializationContext ctxt)
- throws IOException
- {
- return new URL(value);
- }
- }
-
- public static class URIDeserializer
- extends FromStringDeserializer<URI>
- {
- public URIDeserializer() { super(URI.class); }
-
- @Override
- protected URI _deserialize(String value, DeserializationContext ctxt)
- throws IllegalArgumentException
- {
- return URI.create(value);
- }
- }
-
- public static class CurrencyDeserializer
- extends FromStringDeserializer<Currency>
- {
- public CurrencyDeserializer() { super(Currency.class); }
-
- @Override
- protected Currency _deserialize(String value, DeserializationContext ctxt)
- throws IllegalArgumentException
- {
- // will throw IAE if unknown:
- return Currency.getInstance(value);
- }
- }
-
- public static class PatternDeserializer
- extends FromStringDeserializer<Pattern>
- {
- public PatternDeserializer() { super(Pattern.class); }
-
- @Override
- protected Pattern _deserialize(String value, DeserializationContext ctxt)
- throws IllegalArgumentException
- {
- // will throw IAE (or its subclass) if malformed
- return Pattern.compile(value);
- }
- }
-
- /**
- * Kept protected as it's not meant to be extensible at this point
- *
- * @since 1.7
- */
- protected static class LocaleDeserializer
- extends FromStringDeserializer<Locale>
- {
- public LocaleDeserializer() { super(Locale.class); }
-
- @Override
- protected Locale _deserialize(String value, DeserializationContext ctxt)
- throws IOException
- {
- int ix = value.indexOf('_');
- if (ix < 0) { // single argument
- return new Locale(value);
- }
- String first = value.substring(0, ix);
- value = value.substring(ix+1);
- ix = value.indexOf('_');
- if (ix < 0) { // two pieces
- return new Locale(first, value);
- }
- String second = value.substring(0, ix);
- return new Locale(first, second, value.substring(ix+1));
- }
- }
-
- /**
- * As per [JACKSON-484], also need special handling for InetAddress...
- *
- * @since 1.7.4
- */
- protected static class InetAddressDeserializer
- extends FromStringDeserializer<InetAddress>
- {
- public InetAddressDeserializer() { super(InetAddress.class); }
-
- @Override
- protected InetAddress _deserialize(String value, DeserializationContext ctxt)
- throws IOException
- {
- return InetAddress.getByName(value);
- }
- }
-
- /**
- * As per [JACKSON-522], also need special handling for InetAddress...
- *
- * @since 1.7.4
- */
- protected static class TimeZoneDeserializer
- extends FromStringDeserializer<TimeZone>
- {
- public TimeZoneDeserializer() { super(TimeZone.class); }
-
- @Override
- protected TimeZone _deserialize(String value, DeserializationContext ctxt)
- throws IOException
- {
- return TimeZone.getTimeZone(value);
- }
- }
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/JacksonDeserializers.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/JacksonDeserializers.java
new file mode 100644
index 000000000..7e294e8c1
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/JacksonDeserializers.java
@@ -0,0 +1,84 @@
+package com.fasterxml.jackson.databind.deser.std;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
+import com.fasterxml.jackson.databind.util.TokenBuffer;
+
+/**
+ * Container class for core Jackson type deserializers.
+ */
+public class JacksonDeserializers
+{
+ public static StdDeserializer<?>[] all()
+ {
+ return new StdDeserializer[] {
+ new TokenBufferDeserializer(),
+ new JavaTypeDeserializer()
+ };
+ }
+
+ /*
+ /**********************************************************
+ /* Deserializer implementations
+ /**********************************************************
+ */
+
+ /**
+ * Deserializer for {@link JavaType} values.
+ */
+ public static class JavaTypeDeserializer
+ extends StdScalarDeserializer<JavaType>
+ {
+ public JavaTypeDeserializer() { super(JavaType.class); }
+
+ @Override
+ public JavaType deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ JsonToken curr = jp.getCurrentToken();
+ // Usually should just get string value:
+ if (curr == JsonToken.VALUE_STRING) {
+ String str = jp.getText().trim();
+ if (str.length() == 0) {
+ return getEmptyValue();
+ }
+ return ctxt.getTypeFactory().constructFromCanonical(str);
+ }
+ // or occasionally just embedded object maybe
+ if (curr == JsonToken.VALUE_EMBEDDED_OBJECT) {
+ return (JavaType) jp.getEmbeddedObject();
+ }
+ throw ctxt.mappingException(_valueClass);
+ }
+ }
+
+ /**
+ * We also want to directly support deserialization of {@link TokenBuffer}.
+ *<p>
+ * Note that we use scalar deserializer base just because we claim
+ * to be of scalar for type information inclusion purposes; actual
+ * underlying content can be of any (Object, Array, scalar) type.
+ */
+ @JacksonStdImpl
+ public static class TokenBufferDeserializer
+ extends StdScalarDeserializer<TokenBuffer>
+ {
+ public TokenBufferDeserializer() { super(TokenBuffer.class); }
+
+ @Override
+ public TokenBuffer deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ TokenBuffer tb = new TokenBuffer(jp.getCodec());
+ // quite simple, given that TokenBuffer is a JsonGenerator:
+ tb.copyCurrentStructure(jp);
+ return tb;
+ }
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/JavaTypeDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/JavaTypeDeserializer.java
deleted file mode 100644
index 9c4e7f170..000000000
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/JavaTypeDeserializer.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.fasterxml.jackson.databind.deser.std;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.*;
-
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JavaType;
-
-/**
- * @since 1.9
- */
-public class JavaTypeDeserializer
- extends StdScalarDeserializer<JavaType>
-{
- public JavaTypeDeserializer() { super(JavaType.class); }
-
- @Override
- public JavaType deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- JsonToken curr = jp.getCurrentToken();
- // Usually should just get string value:
- if (curr == JsonToken.VALUE_STRING) {
- String str = jp.getText().trim();
- if (str.length() == 0) {
- return getEmptyValue();
- }
- return ctxt.getTypeFactory().constructFromCanonical(str);
- }
- // or occasionally just embedded object maybe
- if (curr == JsonToken.VALUE_EMBEDDED_OBJECT) {
- return (JavaType) jp.getEmbeddedObject();
- }
- throw ctxt.mappingException(_valueClass);
- }
-}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/JdkDeserializers.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/JdkDeserializers.java
new file mode 100644
index 000000000..63a85ca0c
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/JdkDeserializers.java
@@ -0,0 +1,272 @@
+package com.fasterxml.jackson.databind.deser.std;
+
+import java.io.*;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URL;
+import java.util.*;
+import java.util.regex.Pattern;
+
+import com.fasterxml.jackson.core.Base64Variants;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
+import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
+
+public class JdkDeserializers
+{
+ public static StdDeserializer<?>[] all()
+ {
+ return new StdDeserializer[] {
+
+ // from String types:
+ new StringDeserializer(),
+ new UUIDDeserializer(),
+ new URLDeserializer(),
+ new URIDeserializer(),
+ new CurrencyDeserializer(),
+ new PatternDeserializer(),
+ new LocaleDeserializer(),
+ new InetAddressDeserializer(),
+
+ // other types:
+ new ClassDeserializer(),
+ new StackTraceElementDeserializer()
+ };
+ }
+
+ /*
+ /**********************************************************
+ /* Deserializer implementations: from-String deserializers
+ /**********************************************************
+ */
+
+ /**
+ * Note: final as performance optimization: not expected to need sub-classing;
+ * if sub-classing was needed could re-factor into reusable part, final
+ * "Impl" sub-class
+ */
+ @JacksonStdImpl
+ public final static class StringDeserializer
+ extends StdScalarDeserializer<String>
+ {
+ public StringDeserializer() { super(String.class); }
+
+ @Override
+ public String deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ JsonToken curr = jp.getCurrentToken();
+ // Usually should just get string value:
+ if (curr == JsonToken.VALUE_STRING) {
+ return jp.getText();
+ }
+ // [JACKSON-330]: need to gracefully handle byte[] data, as base64
+ if (curr == JsonToken.VALUE_EMBEDDED_OBJECT) {
+ Object ob = jp.getEmbeddedObject();
+ if (ob == null) {
+ return null;
+ }
+ if (ob instanceof byte[]) {
+ return Base64Variants.getDefaultVariant().encode((byte[]) ob, false);
+ }
+ // otherwise, try conversion using toString()...
+ return ob.toString();
+ }
+ // Can deserialize any scalar value, but not markers
+ if (curr.isScalarValue()) {
+ return jp.getText();
+ }
+ throw ctxt.mappingException(_valueClass, curr);
+ }
+
+ // 1.6: since we can never have type info ("natural type"; String, Boolean, Integer, Double):
+ // (is it an error to even call this version?)
+ @Override
+ public String deserializeWithType(JsonParser jp, DeserializationContext ctxt,
+ TypeDeserializer typeDeserializer)
+ throws IOException, JsonProcessingException
+ {
+ return deserialize(jp, ctxt);
+ }
+ }
+
+ public static class UUIDDeserializer
+ extends FromStringDeserializer<UUID>
+ {
+ public UUIDDeserializer() { super(UUID.class); }
+
+ @Override
+ protected UUID _deserialize(String value, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ return UUID.fromString(value);
+ }
+
+ @Override
+ protected UUID _deserializeEmbedded(Object ob, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ if (ob instanceof byte[]) {
+ byte[] bytes = (byte[]) ob;
+ if (bytes.length != 16) {
+ ctxt.mappingException("Can only construct UUIDs from 16 byte arrays; got "+bytes.length+" bytes");
+ }
+ // clumsy, but should work for now...
+ DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes));
+ long l1 = in.readLong();
+ long l2 = in.readLong();
+ return new UUID(l1, l2);
+ }
+ super._deserializeEmbedded(ob, ctxt);
+ return null; // never gets here
+ }
+ }
+
+ public static class URLDeserializer
+ extends FromStringDeserializer<URL>
+ {
+ public URLDeserializer() { super(URL.class); }
+
+ @Override
+ protected URL _deserialize(String value, DeserializationContext ctxt)
+ throws IOException
+ {
+ return new URL(value);
+ }
+ }
+
+ public static class URIDeserializer
+ extends FromStringDeserializer<URI>
+ {
+ public URIDeserializer() { super(URI.class); }
+
+ @Override
+ protected URI _deserialize(String value, DeserializationContext ctxt)
+ throws IllegalArgumentException
+ {
+ return URI.create(value);
+ }
+ }
+
+ public static class CurrencyDeserializer
+ extends FromStringDeserializer<Currency>
+ {
+ public CurrencyDeserializer() { super(Currency.class); }
+
+ @Override
+ protected Currency _deserialize(String value, DeserializationContext ctxt)
+ throws IllegalArgumentException
+ {
+ // will throw IAE if unknown:
+ return Currency.getInstance(value);
+ }
+ }
+
+ public static class PatternDeserializer
+ extends FromStringDeserializer<Pattern>
+ {
+ public PatternDeserializer() { super(Pattern.class); }
+
+ @Override
+ protected Pattern _deserialize(String value, DeserializationContext ctxt)
+ throws IllegalArgumentException
+ {
+ // will throw IAE (or its subclass) if malformed
+ return Pattern.compile(value);
+ }
+ }
+
+ /**
+ * Kept protected as it's not meant to be extensible at this point
+ */
+ protected static class LocaleDeserializer
+ extends FromStringDeserializer<Locale>
+ {
+ public LocaleDeserializer() { super(Locale.class); }
+
+ @Override
+ protected Locale _deserialize(String value, DeserializationContext ctxt)
+ throws IOException
+ {
+ int ix = value.indexOf('_');
+ if (ix < 0) { // single argument
+ return new Locale(value);
+ }
+ String first = value.substring(0, ix);
+ value = value.substring(ix+1);
+ ix = value.indexOf('_');
+ if (ix < 0) { // two pieces
+ return new Locale(first, value);
+ }
+ String second = value.substring(0, ix);
+ return new Locale(first, second, value.substring(ix+1));
+ }
+ }
+
+ /**
+ * As per [JACKSON-484], also need special handling for InetAddress...
+ */
+ protected static class InetAddressDeserializer
+ extends FromStringDeserializer<InetAddress>
+ {
+ public InetAddressDeserializer() { super(InetAddress.class); }
+
+ @Override
+ protected InetAddress _deserialize(String value, DeserializationContext ctxt)
+ throws IOException
+ {
+ return InetAddress.getByName(value);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Deserializers for other JDK types
+ /**********************************************************
+ */
+
+ public static class StackTraceElementDeserializer
+ extends StdScalarDeserializer<StackTraceElement>
+ {
+ public StackTraceElementDeserializer() { super(StackTraceElement.class); }
+
+ @Override
+ public StackTraceElement deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ JsonToken t = jp.getCurrentToken();
+ // Must get an Object
+ if (t == JsonToken.START_OBJECT) {
+ String className = "", methodName = "", fileName = "";
+ int lineNumber = -1;
+
+ while ((t = jp.nextValue()) != JsonToken.END_OBJECT) {
+ String propName = jp.getCurrentName();
+ if ("className".equals(propName)) {
+ className = jp.getText();
+ } else if ("fileName".equals(propName)) {
+ fileName = jp.getText();
+ } else if ("lineNumber".equals(propName)) {
+ if (t.isNumeric()) {
+ lineNumber = jp.getIntValue();
+ } else {
+ throw JsonMappingException.from(jp, "Non-numeric token ("+t+") for property 'lineNumber'");
+ }
+ } else if ("methodName".equals(propName)) {
+ methodName = jp.getText();
+ } else if ("nativeMethod".equals(propName)) {
+ // no setter, not passed via constructor: ignore
+ } else {
+ handleUnknownProperty(jp, ctxt, _valueClass, propName);
+ }
+ }
+ return new StackTraceElement(className, methodName, fileName, lineNumber);
+ }
+ throw ctxt.mappingException(_valueClass, t);
+ }
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/NumberDeserializers.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/NumberDeserializers.java
new file mode 100644
index 000000000..83b422b9f
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/NumberDeserializers.java
@@ -0,0 +1,445 @@
+package com.fasterxml.jackson.databind.deser.std;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationConfig;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
+import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
+
+/**
+ * Container class for deserializers that handle core JDK primitive
+ * (and matching wrapper) types, as well as standard "big" numeric types.
+ * Note that this includes types such as {@link java.lang.Boolean}
+ * and {@link java.lang.Character} which are not strictly numeric,
+ * but are part of primitive/wrapper types.
+ */
+public class NumberDeserializers
+{
+ public static StdDeserializer<?>[] all()
+ {
+ return new StdDeserializer<?>[] {
+ // primitive-wrappers (simple):
+ new BooleanDeserializer(Boolean.class, null),
+ new ByteDeserializer(Byte.class, null),
+ new ShortDeserializer(Short.class, null),
+ new CharacterDeserializer(Character.class, null),
+ new IntegerDeserializer(Integer.class, null),
+ new LongDeserializer(Long.class, null),
+ new FloatDeserializer(Float.class, null),
+ new DoubleDeserializer(Double.class, null),
+
+ /* And actual primitives: difference is the way nulls are to be
+ * handled...
+ */
+ new BooleanDeserializer(Boolean.TYPE, Boolean.FALSE),
+ new ByteDeserializer(Byte.TYPE, Byte.valueOf((byte)(0))),
+ new ShortDeserializer(Short.TYPE, Short.valueOf((short)0)),
+ new CharacterDeserializer(Character.TYPE, Character.valueOf('\0')),
+ new IntegerDeserializer(Integer.TYPE, Integer.valueOf(0)),
+ new LongDeserializer(Long.TYPE, Long.valueOf(0L)),
+ new FloatDeserializer(Float.TYPE, Float.valueOf(0.0f)),
+ new DoubleDeserializer(Double.TYPE, Double.valueOf(0.0)),
+
+ // and related
+ new NumberDeserializer(),
+ new BigDecimalDeserializer(),
+ new BigIntegerDeserializer()
+ };
+ }
+
+ /*
+ /**********************************************************
+ /* Then one intermediate base class for things that have
+ /* both primitive and wrapper types
+ /**********************************************************
+ */
+
+ protected abstract static class PrimitiveOrWrapperDeserializer<T>
+ extends StdScalarDeserializer<T>
+ {
+ final T _nullValue;
+
+ protected PrimitiveOrWrapperDeserializer(Class<T> vc, T nvl)
+ {
+ super(vc);
+ _nullValue = nvl;
+ }
+
+ @Override
+ public final T getNullValue() {
+ return _nullValue;
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Then primitive/wrapper types
+ /**********************************************************
+ */
+
+ @JacksonStdImpl
+ public final static class BooleanDeserializer
+ extends PrimitiveOrWrapperDeserializer<Boolean>
+ {
+ public BooleanDeserializer(Class<Boolean> cls, Boolean nvl)
+ {
+ super(cls, nvl);
+ }
+
+ @Override
+ public Boolean deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ return _parseBoolean(jp, ctxt);
+ }
+
+ // 1.6: since we can never have type info ("natural type"; String, Boolean, Integer, Double):
+ // (is it an error to even call this version?)
+ @Override
+ public Boolean deserializeWithType(JsonParser jp, DeserializationContext ctxt,
+ TypeDeserializer typeDeserializer)
+ throws IOException, JsonProcessingException
+ {
+ return _parseBoolean(jp, ctxt);
+ }
+ }
+
+ @JacksonStdImpl
+ public final static class ByteDeserializer
+ extends PrimitiveOrWrapperDeserializer<Byte>
+ {
+ public ByteDeserializer(Class<Byte> cls, Byte nvl)
+ {
+ super(cls, nvl);
+ }
+
+ @Override
+ public Byte deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ return _parseByte(jp, ctxt);
+ }
+ }
+
+ @JacksonStdImpl
+ public final static class ShortDeserializer
+ extends PrimitiveOrWrapperDeserializer<Short>
+ {
+ public ShortDeserializer(Class<Short> cls, Short nvl)
+ {
+ super(cls, nvl);
+ }
+
+ @Override
+ public Short deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ return _parseShort(jp, ctxt);
+ }
+ }
+
+ @JacksonStdImpl
+ public final static class CharacterDeserializer
+ extends PrimitiveOrWrapperDeserializer<Character>
+ {
+ public CharacterDeserializer(Class<Character> cls, Character nvl)
+ {
+ super(cls, nvl);
+ }
+
+ @Override
+ public Character deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ JsonToken t = jp.getCurrentToken();
+ int value;
+
+ if (t == JsonToken.VALUE_NUMBER_INT) { // ok iff ascii value
+ value = jp.getIntValue();
+ if (value >= 0 && value <= 0xFFFF) {
+ return Character.valueOf((char) value);
+ }
+ } else if (t == JsonToken.VALUE_STRING) { // this is the usual type
+ // But does it have to be exactly one char?
+ String text = jp.getText();
+ if (text.length() == 1) {
+ return Character.valueOf(text.charAt(0));
+ }
+ // actually, empty should become null?
+ if (text.length() == 0) {
+ return (Character) getEmptyValue();
+ }
+ }
+ throw ctxt.mappingException(_valueClass, t);
+ }
+ }
+
+ @JacksonStdImpl
+ public final static class IntegerDeserializer
+ extends PrimitiveOrWrapperDeserializer<Integer>
+ {
+ public IntegerDeserializer(Class<Integer> cls, Integer nvl)
+ {
+ super(cls, nvl);
+ }
+
+ @Override
+ public Integer deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ return _parseInteger(jp, ctxt);
+ }
+
+ // 1.6: since we can never have type info ("natural type"; String, Boolean, Integer, Double):
+ // (is it an error to even call this version?)
+ @Override
+ public Integer deserializeWithType(JsonParser jp, DeserializationContext ctxt,
+ TypeDeserializer typeDeserializer)
+ throws IOException, JsonProcessingException
+ {
+ return _parseInteger(jp, ctxt);
+ }
+ }
+
+ @JacksonStdImpl
+ public final static class LongDeserializer
+ extends PrimitiveOrWrapperDeserializer<Long>
+ {
+ public LongDeserializer(Class<Long> cls, Long nvl)
+ {
+ super(cls, nvl);
+ }
+
+ @Override
+ public Long deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ return _parseLong(jp, ctxt);
+ }
+ }
+
+ @JacksonStdImpl
+ public final static class FloatDeserializer
+ extends PrimitiveOrWrapperDeserializer<Float>
+ {
+ public FloatDeserializer(Class<Float> cls, Float nvl)
+ {
+ super(cls, nvl);
+ }
+
+ @Override
+ public Float deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ /* 22-Jan-2009, tatu: Bounds/range checks would be tricky
+ * here, so let's not bother even trying...
+ */
+ return _parseFloat(jp, ctxt);
+ }
+ }
+
+ @JacksonStdImpl
+ public final static class DoubleDeserializer
+ extends PrimitiveOrWrapperDeserializer<Double>
+ {
+ public DoubleDeserializer(Class<Double> cls, Double nvl)
+ {
+ super(cls, nvl);
+ }
+
+ @Override
+ public Double deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ return _parseDouble(jp, ctxt);
+ }
+
+ // 1.6: since we can never have type info ("natural type"; String, Boolean, Integer, Double):
+ // (is it an error to even call this version?)
+ @Override
+ public Double deserializeWithType(JsonParser jp, DeserializationContext ctxt,
+ TypeDeserializer typeDeserializer)
+ throws IOException, JsonProcessingException
+ {
+ return _parseDouble(jp, ctxt);
+ }
+ }
+
+ /**
+ * For type <code>Number.class</code>, we can just rely on type
+ * mappings that plain {@link JsonParser#getNumberValue} returns.
+ *<p>
+ * Since 1.5, there is one additional complication: some numeric
+ * types (specifically, int/Integer and double/Double) are "non-typed";
+ * meaning that they will NEVER be output with type information.
+ * But other numeric types may need such type information.
+ * This is why {@link #deserializeWithType} must be overridden.
+ */
+ @JacksonStdImpl
+ public final static class NumberDeserializer
+ extends StdScalarDeserializer<Number>
+ {
+ public NumberDeserializer() { super(Number.class); }
+
+ @Override
+ public Number deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ JsonToken t = jp.getCurrentToken();
+ if (t == JsonToken.VALUE_NUMBER_INT) {
+ if (ctxt.isEnabled(DeserializationConfig.Feature.USE_BIG_INTEGER_FOR_INTS)) {
+ return jp.getBigIntegerValue();
+ }
+ return jp.getNumberValue();
+ } else if (t == JsonToken.VALUE_NUMBER_FLOAT) {
+ /* [JACKSON-72]: need to allow overriding the behavior
+ * regarding which type to use
+ */
+ if (ctxt.isEnabled(DeserializationConfig.Feature.USE_BIG_DECIMAL_FOR_FLOATS)) {
+ return jp.getDecimalValue();
+ }
+ return Double.valueOf(jp.getDoubleValue());
+ }
+
+ /* Textual values are more difficult... not parsing itself, but figuring
+ * out 'minimal' type to use
+ */
+ if (t == JsonToken.VALUE_STRING) { // let's do implicit re-parse
+ String text = jp.getText().trim();
+ try {
+ if (text.indexOf('.') >= 0) { // floating point
+ // as per [JACKSON-72]:
+ if (ctxt.isEnabled(DeserializationConfig.Feature.USE_BIG_DECIMAL_FOR_FLOATS)) {
+ return new BigDecimal(text);
+ }
+ return new Double(text);
+ }
+ // as per [JACKSON-100]:
+ if (ctxt.isEnabled(DeserializationConfig.Feature.USE_BIG_INTEGER_FOR_INTS)) {
+ return new BigInteger(text);
+ }
+ long value = Long.parseLong(text);
+ if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) {
+ return Integer.valueOf((int) value);
+ }
+ return Long.valueOf(value);
+ } catch (IllegalArgumentException iae) {
+ throw ctxt.weirdStringException(_valueClass, "not a valid number");
+ }
+ }
+ // Otherwise, no can do:
+ throw ctxt.mappingException(_valueClass, t);
+ }
+
+ /**
+ * As mentioned in class Javadoc, there is additional complexity in
+ * handling potentially mixed type information here. Because of this,
+ * we must actually check for "raw" integers and doubles first, before
+ * calling type deserializer.
+ */
+ @Override
+ public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt,
+ TypeDeserializer typeDeserializer)
+ throws IOException, JsonProcessingException
+ {
+ switch (jp.getCurrentToken()) {
+ case VALUE_NUMBER_INT:
+ case VALUE_NUMBER_FLOAT:
+ case VALUE_STRING:
+ // can not point to type information: hence must be non-typed (int/double)
+ return deserialize(jp, ctxt);
+ }
+ return typeDeserializer.deserializeTypedFromScalar(jp, ctxt);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* And then bit more complicated (but non-structured) number
+ /* types
+ /**********************************************************
+ */
+
+ /**
+ * This is bit trickier to implement efficiently, while avoiding
+ * overflow problems.
+ */
+ @JacksonStdImpl
+ public static class BigIntegerDeserializer
+ extends StdScalarDeserializer<BigInteger>
+ {
+ public BigIntegerDeserializer() { super(BigInteger.class); }
+
+ @Override
+ public BigInteger deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ JsonToken t = jp.getCurrentToken();
+ String text;
+
+ if (t == JsonToken.VALUE_NUMBER_INT) {
+ switch (jp.getNumberType()) {
+ case INT:
+ case LONG:
+ return BigInteger.valueOf(jp.getLongValue());
+ }
+ } else if (t == JsonToken.VALUE_NUMBER_FLOAT) {
+ /* Whether to fail if there's non-integer part?
+ * Could do by calling BigDecimal.toBigIntegerExact()
+ */
+ return jp.getDecimalValue().toBigInteger();
+ } else if (t != JsonToken.VALUE_STRING) { // let's do implicit re-parse
+ // String is ok too, can easily convert; otherwise, no can do:
+ throw ctxt.mappingException(_valueClass, t);
+ }
+ text = jp.getText().trim();
+ if (text.length() == 0) {
+ return null;
+ }
+ try {
+ return new BigInteger(text);
+ } catch (IllegalArgumentException iae) {
+ throw ctxt.weirdStringException(_valueClass, "not a valid representation");
+ }
+ }
+ }
+
+ @JacksonStdImpl
+ public static class BigDecimalDeserializer
+ extends StdScalarDeserializer<BigDecimal>
+ {
+ public BigDecimalDeserializer() { super(BigDecimal.class); }
+
+ @Override
+ public BigDecimal deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ JsonToken t = jp.getCurrentToken();
+ if (t == JsonToken.VALUE_NUMBER_INT || t == JsonToken.VALUE_NUMBER_FLOAT) {
+ return jp.getDecimalValue();
+ }
+ // String is ok too, can easily convert
+ if (t == JsonToken.VALUE_STRING) { // let's do implicit re-parse
+ String text = jp.getText().trim();
+ if (text.length() == 0) {
+ return null;
+ }
+ try {
+ return new BigDecimal(text);
+ } catch (IllegalArgumentException iae) {
+ throw ctxt.weirdStringException(_valueClass, "not a valid representation");
+ }
+ }
+ // Otherwise, no can do:
+ throw ctxt.mappingException(_valueClass, t);
+ }
+ }
+
+
+}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java
index baf56caa1..76a7152c6 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDeserializer.java
@@ -1,8 +1,6 @@
package com.fasterxml.jackson.databind.deser.std;
import java.io.IOException;
-import java.math.BigDecimal;
-import java.math.BigInteger;
import java.util.*;
import com.fasterxml.jackson.core.*;
@@ -56,8 +54,6 @@ public abstract class StdDeserializer<T>
* deserializer Jackson uses; as opposed to a custom deserializer installed by
* a module or calling application. Determination is done using
* {@link JacksonStdImpl} annotation on deserializer class.
- *
- * @since 1.7
*/
protected boolean isDefaultSerializer(JsonDeserializer<?> deserializer)
{
@@ -85,7 +81,9 @@ public abstract class StdDeserializer<T>
/*
/**********************************************************
- /* Helper methods for sub-classes, parsing
+ /* Helper methods for sub-classes, parsing: while mostly
+ /* useful for numeric types, can be also useful for dealing
+ /* with things serialized as numbers (such as Dates).
/**********************************************************
*/
@@ -570,7 +568,7 @@ public abstract class StdDeserializer<T>
/****************************************************
/* Helper methods for sub-classes, resolving dependencies
/****************************************************
- */
+ */
/**
* Helper method used to locate deserializers for properties the
@@ -644,464 +642,4 @@ public abstract class StdDeserializer<T>
}
// ... or if not, just ignore
}
-
-
- /*
- /**********************************************************
- /* Then one intermediate base class for things that have
- /* both primitive and wrapper types
- /**********************************************************
- */
-
- protected abstract static class PrimitiveOrWrapperDeserializer<T>
- extends StdScalarDeserializer<T>
- {
- final T _nullValue;
-
- protected PrimitiveOrWrapperDeserializer(Class<T> vc, T nvl)
- {
- super(vc);
- _nullValue = nvl;
- }
-
- @Override
- public final T getNullValue() {
- return _nullValue;
- }
- }
-
- /*
- /**********************************************************
- /* Then primitive/wrapper types
- /**********************************************************
- */
-
- @JacksonStdImpl
- public final static class BooleanDeserializer
- extends PrimitiveOrWrapperDeserializer<Boolean>
- {
- public BooleanDeserializer(Class<Boolean> cls, Boolean nvl)
- {
- super(cls, nvl);
- }
-
- @Override
- public Boolean deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- return _parseBoolean(jp, ctxt);
- }
-
- // 1.6: since we can never have type info ("natural type"; String, Boolean, Integer, Double):
- // (is it an error to even call this version?)
- @Override
- public Boolean deserializeWithType(JsonParser jp, DeserializationContext ctxt,
- TypeDeserializer typeDeserializer)
- throws IOException, JsonProcessingException
- {
- return _parseBoolean(jp, ctxt);
- }
- }
-
- @JacksonStdImpl
- public final static class ByteDeserializer
- extends PrimitiveOrWrapperDeserializer<Byte>
- {
- public ByteDeserializer(Class<Byte> cls, Byte nvl)
- {
- super(cls, nvl);
- }
-
- @Override
- public Byte deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- return _parseByte(jp, ctxt);
- }
- }
-
- @JacksonStdImpl
- public final static class ShortDeserializer
- extends PrimitiveOrWrapperDeserializer<Short>
- {
- public ShortDeserializer(Class<Short> cls, Short nvl)
- {
- super(cls, nvl);
- }
-
- @Override
- public Short deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- return _parseShort(jp, ctxt);
- }
- }
-
- @JacksonStdImpl
- public final static class CharacterDeserializer
- extends PrimitiveOrWrapperDeserializer<Character>
- {
- public CharacterDeserializer(Class<Character> cls, Character nvl)
- {
- super(cls, nvl);
- }
-
- @Override
- public Character deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- JsonToken t = jp.getCurrentToken();
- int value;
-
- if (t == JsonToken.VALUE_NUMBER_INT) { // ok iff ascii value
- value = jp.getIntValue();
- if (value >= 0 && value <= 0xFFFF) {
- return Character.valueOf((char) value);
- }
- } else if (t == JsonToken.VALUE_STRING) { // this is the usual type
- // But does it have to be exactly one char?
- String text = jp.getText();
- if (text.length() == 1) {
- return Character.valueOf(text.charAt(0));
- }
- // actually, empty should become null?
- if (text.length() == 0) {
- return (Character) getEmptyValue();
- }
- }
- throw ctxt.mappingException(_valueClass, t);
- }
- }
-
- @JacksonStdImpl
- public final static class IntegerDeserializer
- extends PrimitiveOrWrapperDeserializer<Integer>
- {
- public IntegerDeserializer(Class<Integer> cls, Integer nvl)
- {
- super(cls, nvl);
- }
-
- @Override
- public Integer deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- return _parseInteger(jp, ctxt);
- }
-
- // 1.6: since we can never have type info ("natural type"; String, Boolean, Integer, Double):
- // (is it an error to even call this version?)
- @Override
- public Integer deserializeWithType(JsonParser jp, DeserializationContext ctxt,
- TypeDeserializer typeDeserializer)
- throws IOException, JsonProcessingException
- {
- return _parseInteger(jp, ctxt);
- }
- }
-
- @JacksonStdImpl
- public final static class LongDeserializer
- extends PrimitiveOrWrapperDeserializer<Long>
- {
- public LongDeserializer(Class<Long> cls, Long nvl)
- {
- super(cls, nvl);
- }
-
- @Override
- public Long deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- return _parseLong(jp, ctxt);
- }
- }
-
- @JacksonStdImpl
- public final static class FloatDeserializer
- extends PrimitiveOrWrapperDeserializer<Float>
- {
- public FloatDeserializer(Class<Float> cls, Float nvl)
- {
- super(cls, nvl);
- }
-
- @Override
- public Float deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- /* 22-Jan-2009, tatu: Bounds/range checks would be tricky
- * here, so let's not bother even trying...
- */
- return _parseFloat(jp, ctxt);
- }
- }
-
- @JacksonStdImpl
- public final static class DoubleDeserializer
- extends PrimitiveOrWrapperDeserializer<Double>
- {
- public DoubleDeserializer(Class<Double> cls, Double nvl)
- {
- super(cls, nvl);
- }
-
- @Override
- public Double deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- return _parseDouble(jp, ctxt);
- }
-
- // 1.6: since we can never have type info ("natural type"; String, Boolean, Integer, Double):
- // (is it an error to even call this version?)
- @Override
- public Double deserializeWithType(JsonParser jp, DeserializationContext ctxt,
- TypeDeserializer typeDeserializer)
- throws IOException, JsonProcessingException
- {
- return _parseDouble(jp, ctxt);
- }
- }
-
- /**
- * For type <code>Number.class</code>, we can just rely on type
- * mappings that plain {@link JsonParser#getNumberValue} returns.
- *<p>
- * Since 1.5, there is one additional complication: some numeric
- * types (specifically, int/Integer and double/Double) are "non-typed";
- * meaning that they will NEVER be output with type information.
- * But other numeric types may need such type information.
- * This is why {@link #deserializeWithType} must be overridden.
- */
- @JacksonStdImpl
- public final static class NumberDeserializer
- extends StdScalarDeserializer<Number>
- {
- public NumberDeserializer() { super(Number.class); }
-
- @Override
- public Number deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- JsonToken t = jp.getCurrentToken();
- if (t == JsonToken.VALUE_NUMBER_INT) {
- if (ctxt.isEnabled(DeserializationConfig.Feature.USE_BIG_INTEGER_FOR_INTS)) {
- return jp.getBigIntegerValue();
- }
- return jp.getNumberValue();
- } else if (t == JsonToken.VALUE_NUMBER_FLOAT) {
- /* [JACKSON-72]: need to allow overriding the behavior
- * regarding which type to use
- */
- if (ctxt.isEnabled(DeserializationConfig.Feature.USE_BIG_DECIMAL_FOR_FLOATS)) {
- return jp.getDecimalValue();
- }
- return Double.valueOf(jp.getDoubleValue());
- }
-
- /* Textual values are more difficult... not parsing itself, but figuring
- * out 'minimal' type to use
- */
- if (t == JsonToken.VALUE_STRING) { // let's do implicit re-parse
- String text = jp.getText().trim();
- try {
- if (text.indexOf('.') >= 0) { // floating point
- // as per [JACKSON-72]:
- if (ctxt.isEnabled(DeserializationConfig.Feature.USE_BIG_DECIMAL_FOR_FLOATS)) {
- return new BigDecimal(text);
- }
- return new Double(text);
- }
- // as per [JACKSON-100]:
- if (ctxt.isEnabled(DeserializationConfig.Feature.USE_BIG_INTEGER_FOR_INTS)) {
- return new BigInteger(text);
- }
- long value = Long.parseLong(text);
- if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) {
- return Integer.valueOf((int) value);
- }
- return Long.valueOf(value);
- } catch (IllegalArgumentException iae) {
- throw ctxt.weirdStringException(_valueClass, "not a valid number");
- }
- }
- // Otherwise, no can do:
- throw ctxt.mappingException(_valueClass, t);
- }
-
- /**
- * As mentioned in class Javadoc, there is additional complexity in
- * handling potentially mixed type information here. Because of this,
- * we must actually check for "raw" integers and doubles first, before
- * calling type deserializer.
- */
- @Override
- public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt,
- TypeDeserializer typeDeserializer)
- throws IOException, JsonProcessingException
- {
- switch (jp.getCurrentToken()) {
- case VALUE_NUMBER_INT:
- case VALUE_NUMBER_FLOAT:
- case VALUE_STRING:
- // can not point to type information: hence must be non-typed (int/double)
- return deserialize(jp, ctxt);
- }
- return typeDeserializer.deserializeTypedFromScalar(jp, ctxt);
- }
- }
-
- /*
- /**********************************************************
- /* And then bit more complicated (but non-structured) number
- /* types
- /**********************************************************
- */
-
- @JacksonStdImpl
- public static class BigDecimalDeserializer
- extends StdScalarDeserializer<BigDecimal>
- {
- public BigDecimalDeserializer() { super(BigDecimal.class); }
-
- @Override
- public BigDecimal deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- JsonToken t = jp.getCurrentToken();
- if (t == JsonToken.VALUE_NUMBER_INT || t == JsonToken.VALUE_NUMBER_FLOAT) {
- return jp.getDecimalValue();
- }
- // String is ok too, can easily convert
- if (t == JsonToken.VALUE_STRING) { // let's do implicit re-parse
- String text = jp.getText().trim();
- if (text.length() == 0) {
- return null;
- }
- try {
- return new BigDecimal(text);
- } catch (IllegalArgumentException iae) {
- throw ctxt.weirdStringException(_valueClass, "not a valid representation");
- }
- }
- // Otherwise, no can do:
- throw ctxt.mappingException(_valueClass, t);
- }
- }
-
- /**
- * This is bit trickier to implement efficiently, while avoiding
- * overflow problems.
- */
- @JacksonStdImpl
- public static class BigIntegerDeserializer
- extends StdScalarDeserializer<BigInteger>
- {
- public BigIntegerDeserializer() { super(BigInteger.class); }
-
- @Override
- public BigInteger deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- JsonToken t = jp.getCurrentToken();
- String text;
-
- if (t == JsonToken.VALUE_NUMBER_INT) {
- switch (jp.getNumberType()) {
- case INT:
- case LONG:
- return BigInteger.valueOf(jp.getLongValue());
- }
- } else if (t == JsonToken.VALUE_NUMBER_FLOAT) {
- /* Whether to fail if there's non-integer part?
- * Could do by calling BigDecimal.toBigIntegerExact()
- */
- return jp.getDecimalValue().toBigInteger();
- } else if (t != JsonToken.VALUE_STRING) { // let's do implicit re-parse
- // String is ok too, can easily convert; otherwise, no can do:
- throw ctxt.mappingException(_valueClass, t);
- }
- text = jp.getText().trim();
- if (text.length() == 0) {
- return null;
- }
- try {
- return new BigInteger(text);
- } catch (IllegalArgumentException iae) {
- throw ctxt.weirdStringException(_valueClass, "not a valid representation");
- }
- }
- }
-
- /*
- /****************************************************
- /* Then trickier things: Date/Calendar types
- /****************************************************
- */
-
- /**
- * Compared to plain old {@link java.util.Date}, SQL version is easier
- * to deal with: mostly because it is more limited.
- */
- public static class SqlDateDeserializer
- extends StdScalarDeserializer<java.sql.Date>
- {
- public SqlDateDeserializer() { super(java.sql.Date.class); }
-
- @Override
- public java.sql.Date deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- Date d = _parseDate(jp, ctxt);
- return (d == null) ? null : new java.sql.Date(d.getTime());
- }
- }
-
- /*
- /****************************************************
- /* And other oddities
- /****************************************************
- */
-
- public static class StackTraceElementDeserializer
- extends StdScalarDeserializer<StackTraceElement>
- {
- public StackTraceElementDeserializer() { super(StackTraceElement.class); }
-
- @Override
- public StackTraceElement deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- JsonToken t = jp.getCurrentToken();
- // Must get an Object
- if (t == JsonToken.START_OBJECT) {
- String className = "", methodName = "", fileName = "";
- int lineNumber = -1;
-
- while ((t = jp.nextValue()) != JsonToken.END_OBJECT) {
- String propName = jp.getCurrentName();
- if ("className".equals(propName)) {
- className = jp.getText();
- } else if ("fileName".equals(propName)) {
- fileName = jp.getText();
- } else if ("lineNumber".equals(propName)) {
- if (t.isNumeric()) {
- lineNumber = jp.getIntValue();
- } else {
- throw JsonMappingException.from(jp, "Non-numeric token ("+t+") for property 'lineNumber'");
- }
- } else if ("methodName".equals(propName)) {
- methodName = jp.getText();
- } else if ("nativeMethod".equals(propName)) {
- // no setter, not passed via constructor: ignore
- } else {
- handleUnknownProperty(jp, ctxt, _valueClass, propName);
- }
- }
- return new StackTraceElement(className, methodName, fileName, lineNumber);
- }
- throw ctxt.mappingException(_valueClass, t);
- }
- }
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java
index 52594d008..e3b3396ae 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java
@@ -11,7 +11,11 @@ import com.fasterxml.jackson.databind.deser.ValueInstantiator;
import com.fasterxml.jackson.databind.introspect.AnnotatedWithParams;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
-
+/**
+ * Specifically optimized version for {@link java.util.Collection}s
+ * that contain String values; reason is that this is a very common
+ * type and we can make use of the fact that Strings are final.
+ */
@JacksonStdImpl
public final class StringCollectionDeserializer
extends ContainerDeserializerBase<Collection<String>>
@@ -37,7 +41,7 @@ public final class StringCollectionDeserializer
// // Instance construction settings:
/**
- * @since 1.9
+ * Instantiator used in case custom handling is needed for creation.
*/
protected final ValueInstantiator _valueInstantiator;
@@ -69,8 +73,6 @@ public final class StringCollectionDeserializer
/**
* Copy-constructor that can be used by sub-classes to allow
* copy-on-write styling copying of settings of an existing instance.
- *
- * @since 1.9
*/
protected StringCollectionDeserializer(StringCollectionDeserializer src)
{
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StringDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StringDeserializer.java
index 458299e2a..1c685e2f5 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StringDeserializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StringDeserializer.java
@@ -50,4 +50,5 @@ public class StringDeserializer
throws IOException, JsonProcessingException
{
return deserialize(jp, ctxt);
- }}
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/TimestampDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/TimestampDeserializer.java
deleted file mode 100644
index 46ee0f51c..000000000
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/TimestampDeserializer.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.fasterxml.jackson.databind.deser.std;
-
-import java.io.IOException;
-import java.sql.Timestamp;
-
-import com.fasterxml.jackson.core.*;
-
-import com.fasterxml.jackson.databind.DeserializationContext;
-
-/**
- * Simple deserializer for handling {@link java.sql.Timestamp} values.
- *<p>
- * One way to customize Timestamp formats accepted is to override method
- * {@link DeserializationContext#parseDate} that this basic
- * deserializer calls.
- */
-public class TimestampDeserializer
- extends StdScalarDeserializer<Timestamp>
-{
- public TimestampDeserializer() { super(Timestamp.class); }
-
- @Override
- public java.sql.Timestamp deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- return new Timestamp(_parseDate(jp, ctxt).getTime());
- }
-}
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/TokenBufferDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/TokenBufferDeserializer.java
deleted file mode 100644
index cf3bd7b39..000000000
--- a/src/main/java/com/fasterxml/jackson/databind/deser/std/TokenBufferDeserializer.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.fasterxml.jackson.databind.deser.std;
-
-import java.io.IOException;
-
-import com.fasterxml.jackson.core.*;
-
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
-import com.fasterxml.jackson.databind.util.TokenBuffer;
-
-/**
- * We also want to directly support deserialization of
- * {@link TokenBuffer}.
- *<p>
- * Note that we use scalar deserializer base just because we claim
- * to be of scalar for type information inclusion purposes; actual
- * underlying content can be of any (Object, Array, scalar) type.
- *
- * @since 1.9 (moved from higher-level package)
- */
-@JacksonStdImpl
-public class TokenBufferDeserializer
- extends StdScalarDeserializer<TokenBuffer>
-{
- public TokenBufferDeserializer() { super(TokenBuffer.class); }
-
- @Override
- public TokenBuffer deserialize(JsonParser jp, DeserializationContext ctxt)
- throws IOException, JsonProcessingException
- {
- TokenBuffer tb = new TokenBuffer(jp.getCodec());
- // quite simple, given that TokenBuffer is a JsonGenerator:
- tb.copyCurrentStructure(jp);
- return tb;
- }
-}
diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/TestAnyProperties.java b/src/test/java/com/fasterxml/jackson/databind/deser/TestAnyProperties.java
index 443a4ef78..08aa5d4f9 100644
--- a/src/test/java/com/fasterxml/jackson/databind/deser/TestAnyProperties.java
+++ b/src/test/java/com/fasterxml/jackson/databind/deser/TestAnyProperties.java
@@ -77,6 +77,29 @@ public class TestAnyProperties
}
}
+ static class Bean744
+ {
+ protected Map<String,Object> additionalProperties;
+
+ @JsonAnySetter
+ public void addAdditionalProperty(String key, Object value) {
+ if (additionalProperties == null) additionalProperties = new HashMap<String, Object>();
+ additionalProperties.put(key,value);
+ }
+
+ public void setAdditionalProperties(Map<String, Object> additionalProperties) {
+ this.additionalProperties = additionalProperties;
+ }
+
+ @JsonAnyGetter
+ public Map<String,Object> getAdditionalProperties() { return additionalProperties; }
+
+ @JsonIgnore
+ public String getName() {
+ return (String) additionalProperties.get("name");
+ }
+ }
+
/*
/**********************************************************
/* Test methods
@@ -139,4 +162,14 @@ public class TestAnyProperties
assertEquals("Bob", bean.map.get("name"));
assertEquals(1, bean.map.size());
}
+
+ public void testProblem744() throws Exception
+ {
+ ObjectMapper m = new ObjectMapper();
+ Bean744 bean = m.readValue("{\"name\":\"Bob\"}", Bean744.class);
+ assertNotNull(bean.additionalProperties);
+ assertEquals(1, bean.additionalProperties.size());
+ assertEquals("Bob", bean.additionalProperties.get("name"));
+ }
+
}
diff --git a/src/test/java/com/fasterxml/jackson/databind/introspect/TestPOJOPropertiesCollector.java b/src/test/java/com/fasterxml/jackson/databind/introspect/TestPOJOPropertiesCollector.java
index d6262f809..427829e7e 100644
--- a/src/test/java/com/fasterxml/jackson/databind/introspect/TestPOJOPropertiesCollector.java
+++ b/src/test/java/com/fasterxml/jackson/databind/introspect/TestPOJOPropertiesCollector.java
@@ -3,6 +3,7 @@ package com.fasterxml.jackson.databind.introspect;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -164,6 +165,29 @@ public class TestPOJOPropertiesCollector
public int getX() { return i; }
}
+
+ static class Issue744Bean
+ {
+ protected Map<String,Object> additionalProperties;
+
+ @JsonAnySetter
+ public void addAdditionalProperty(String key, Object value) {
+ if (additionalProperties == null) additionalProperties = new HashMap<String, Object>();
+ additionalProperties.put(key,value);
+ }
+
+ public void setAdditionalProperties(Map<String, Object> additionalProperties) {
+ this.additionalProperties = additionalProperties;
+ }
+
+ @JsonAnyGetter
+ public Map<String,Object> getAdditionalProperties() { return additionalProperties; }
+
+ @JsonIgnore
+ public String getName() {
+ return (String) additionalProperties.get("name");
+ }
+ }
/*
/**********************************************************
@@ -362,6 +386,15 @@ public class TestPOJOPropertiesCollector
String json = mapper.writeValueAsString(bean);
assertNotNull(json);
}
+
+ public void testJackson744() throws Exception
+ {
+ ObjectMapper mapper = new ObjectMapper();
+ BasicBeanDescription beanDesc = mapper.getDeserializationConfig().introspect(mapper.constructType(Issue744Bean.class));
+ assertNotNull(beanDesc);
+ AnnotatedMethod setter = beanDesc.findAnySetter();
+ assertNotNull(setter);
+ }
/*
/**********************************************************