[jackson-datatype-joda] 01/11: Imported Upstream version 2.4.3
Tim Potter
tpot-guest at moszumanska.debian.org
Thu Nov 6 00:19:57 UTC 2014
This is an automated email from the git hooks/post-receive script.
tpot-guest pushed a commit to branch master
in repository jackson-datatype-joda.
commit 0244e0231f0b25399544280c04f6bb205c81a31e
Author: Tim Potter <tpot at hp.com>
Date: Tue Nov 4 11:06:56 2014 +1100
Imported Upstream version 2.4.3
---
.gitignore | 22 +
README.md | 70 +++
pom.xml | 90 ++++
release-notes/CREDITS | 26 ++
release-notes/VERSION | 112 +++++
.../jackson/datatype/joda/JodaMapper.java | 33 ++
.../jackson/datatype/joda/JodaModule.java | 70 +++
.../jackson/datatype/joda/PackageVersion.java.in | 20 +
.../joda/deser/DateMidnightDeserializer.java | 58 +++
.../datatype/joda/deser/DateTimeDeserializer.java | 64 +++
.../joda/deser/DateTimeZoneDeserializer.java | 37 ++
.../datatype/joda/deser/DurationDeserializer.java | 37 ++
.../datatype/joda/deser/InstantDeserializer.java | 44 ++
.../datatype/joda/deser/IntervalDeserializer.java | 46 ++
.../datatype/joda/deser/JodaDeserializerBase.java | 21 +
.../datatype/joda/deser/LocalDateDeserializer.java | 53 +++
.../joda/deser/LocalDateTimeDeserializer.java | 69 +++
.../datatype/joda/deser/LocalTimeDeserializer.java | 59 +++
.../datatype/joda/deser/MonthDayDeserializer.java | 42 ++
.../datatype/joda/deser/PeriodDeserializer.java | 34 ++
.../joda/deser/ReadablePeriodDeserializer.java | 53 +++
.../datatype/joda/deser/YearMonthDeserializer.java | 42 ++
.../joda/deser/key/DateTimeKeyDeserializer.java | 17 +
.../joda/deser/key/JodaKeyDeserializer.java | 21 +
.../joda/deser/key/LocalDateKeyDeserializer.java | 18 +
.../deser/key/LocalDateTimeKeyDeserializer.java | 18 +
.../joda/deser/key/LocalTimeKeyDeserializer.java | 18 +
.../datatype/joda/ser/DateMidnightSerializer.java | 48 ++
.../datatype/joda/ser/DateTimeSerializer.java | 45 ++
.../datatype/joda/ser/DateTimeZoneSerializer.java | 21 +
.../datatype/joda/ser/DurationSerializer.java | 46 ++
.../datatype/joda/ser/InstantSerializer.java | 42 ++
.../datatype/joda/ser/IntervalSerializer.java | 24 +
.../datatype/joda/ser/JacksonJodaFormat.java | 184 ++++++++
.../datatype/joda/ser/JodaDateSerializerBase.java | 78 ++++
.../datatype/joda/ser/JodaSerializerBase.java | 21 +
.../datatype/joda/ser/LocalDateSerializer.java | 48 ++
.../datatype/joda/ser/LocalDateTimeSerializer.java | 52 +++
.../datatype/joda/ser/LocalTimeSerializer.java | 49 ++
.../datatype/joda/ser/PeriodSerializer.java | 37 ++
src/main/resources/META-INF/LICENSE | 8 +
.../services/com.fasterxml.jackson.databind.Module | 1 +
.../jackson/datatype/joda/DateTimeTest.java | 100 ++++
.../jackson/datatype/joda/JodaMapperTest.java | 32 ++
.../datatype/joda/JodaSerializationTest.java | 246 ++++++++++
.../jackson/datatype/joda/JodaTestBase.java | 46 ++
.../jackson/datatype/joda/MixedListTest.java | 42 ++
.../jackson/datatype/joda/TestVersions.java | 29 ++
.../joda/deser/MiscDeserializationTest.java | 516 +++++++++++++++++++++
.../joda/deser/ReadablePeriodDeserializerTest.java | 73 +++
50 files changed, 2982 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c3bde80
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,22 @@
+# use glob syntax.
+syntax: glob
+*.class
+*~
+*.bak
+*.off
+*.old
+.DS_Store
+
+# building
+target
+
+# Eclipse
+.classpath
+.project
+.settings
+
+# IDEA
+*.iml
+*.ipr
+*.iws
+.idea
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d423888
--- /dev/null
+++ b/README.md
@@ -0,0 +1,70 @@
+Project to build [Jackson](http://jackson.codehaus.org) module (jar)
+to support JSON serialization and deserialization of
+[Joda](http://joda-time.sourceforge.net/) data types.
+
+## Status
+
+[](https://fasterxml.ci.cloudbees.com/job/jackson-datatype-joda-master/)
+
+As of version 2.0 module is usable and relatively extensive.
+Contributions are always welcome -- not all types are yet supported; and we may want to support even wider alternative
+formats on input side.
+
+## Usage
+
+Since this module extends basic [Jackson databind](../../../jackson-databind) functionality, you may want to check out
+documentation at [Jackson-docs](../../../jackson-docs) first.
+
+### Maven dependency
+
+To use module on Maven-based projects, use following dependency:
+
+```xml
+<dependency>
+ <groupId>com.fasterxml.jackson.datatype</groupId>
+ <artifactId>jackson-datatype-joda</artifactId>
+ <version>2.4.0</version>
+</dependency>
+```
+
+(or whatever version is most up-to-date at the moment)
+
+### Registering module
+
+To use Joda datatypes with Jackson, you will first need to register the module first (same as
+with all Jackson datatype modules):
+
+```java
+ObjectMapper mapper = new ObjectMapper();
+mapper.registerModule(new JodaModule());
+```
+
+### Reading and Writing Joda types
+
+After registering Joda module, [Jackson Databind](../../../jackson-databind) will be able to write values
+of supported Joda types as JSON (and other formats Jackson supports), and read Joda values
+from same formats.
+
+With JSON, for example, following would work
+
+```java
+public class Bean {
+ public DateTime start;
+}
+
+final String INPUT_JSON = "{\"start\" : \"1972-12-28T12:00:01.000Z\"}";
+Bean bean = mapper.readValue(INPUT_JSON, Bean.class);
+```
+
+and property `start` of Bean would have expected `DateTime` value.
+
+Conversely, you can produce JSON (and other supported formats) simply with:
+
+```java
+String json = mapper.writeValueAsString(bean);
+Assert.assertEquals(INPUT_JSON, json);
+```
+
+## More
+
+See [Wiki](../../wiki) for more information (javadocs, downloads).
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..5cdfa22
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.fasterxml.jackson</groupId>
+ <artifactId>jackson-parent</artifactId>
+ <version>2.4</version>
+ </parent>
+ <groupId>com.fasterxml.jackson.datatype</groupId>
+ <artifactId>jackson-datatype-joda</artifactId>
+ <name>Jackson-datatype-Joda</name>
+ <version>2.4.3</version>
+ <packaging>bundle</packaging>
+ <description>Add-on module for Jackson (http://jackson.codehaus.org) to support
+Joda (http://joda-time.sourceforge.net/) data types.
+ </description>
+ <url>http://wiki.fasterxml.com/JacksonModuleJoda</url>
+ <scm>
+ <connection>scm:git:git at github.com:FasterXML/jackson-datatype-joda.git</connection>
+ <developerConnection>scm:git:git at github.com:FasterXML/jackson-datatype-joda.git</developerConnection>
+ <url>http://github.com/FasterXML/jackson-datatype-joda</url>
+ <tag>jackson-datatype-joda-2.4.3</tag>
+ </scm>
+ <properties>
+ <version.jackson.annotations>2.4.0</version.jackson.annotations>
+ <version.jackson.core>2.4.3</version.jackson.core>
+ <!-- Generate PackageVersion.java into this directory. -->
+ <packageVersion.dir>com/fasterxml/jackson/datatype/joda</packageVersion.dir>
+ <packageVersion.package>${project.groupId}.joda</packageVersion.package>
+
+ <!-- Configuration properties for the OSGi maven-bundle-plugin -->
+ <osgi.export>${project.groupId}.joda.*</osgi.export>
+ <osgi.versionpolicy>${range;[===,+);${@}}</osgi.versionpolicy>
+ </properties>
+
+ <dependencies>
+ <!-- Extends Jackson mapper; but also needs annotations slightly,
+ to support JsonFormat
+ -->
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-annotations</artifactId>
+ <version>${version.jackson.annotations}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <version>${version.jackson.core}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>${version.jackson.core}</version>
+ </dependency>
+
+ <!-- And obviously also depends on Joda lib -->
+ <dependency>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ <!-- Upgraded to 2.2 for Jackson 2.4: but let's try not to call any 2.2 methods
+ -->
+ <version>2.2</version>
+ </dependency>
+<!-- 26-Jun-2012, tatu: Not sure if this should be included; it appears to be
+ a transitive dependency. Leaving out for now.
+ <dependency>
+ <groupId>org.joda</groupId>
+ <artifactId>joda-convert</artifactId>
+ <version>1.2</version>
+ </dependency>
+-->
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <!-- Inherited from oss-base. Generate PackageVersion.java.-->
+ <groupId>com.google.code.maven-replacer-plugin</groupId>
+ <artifactId>replacer</artifactId>
+ <executions>
+ <execution>
+ <id>process-packageVersion</id>
+ <phase>generate-sources</phase>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/release-notes/CREDITS b/release-notes/CREDITS
new file mode 100644
index 0000000..eae5873
--- /dev/null
+++ b/release-notes/CREDITS
@@ -0,0 +1,26 @@
+Here are people who have contributed to the development of Jackson JSON processor
+Joda datatype module.
+(version numbers in brackets indicate release in which the problem was fixed)
+
+Tatu Saloranta, tatu.saloranta at iki.fi: author
+
+ncjones at github.com:
+ * Contributed #19: Add support for `MonthDay` and `YearMonth`
+ (2.3.1)
+
+Łukasz D:
+ * Suggested #23: package as a bundle
+ (2.3.1)
+
+Lorcan C
+ * Contributed #25: Add `KeyDeserializer` for `DateTime`
+ (2.3.1)
+
+Hendy Irawan (ceefour at github)
+ * Contributed #27: Allow support for `DateTimeZone`
+ (2.3.1)
+
+Brad Kennedy (bkenned4 at github)
+ * Contributed #45: Can't use LocalTime, LocalDate & LocalDateTime as Key type for a Map
+ (2.4.3)
+
diff --git a/release-notes/VERSION b/release-notes/VERSION
new file mode 100644
index 0000000..3dad9bd
--- /dev/null
+++ b/release-notes/VERSION
@@ -0,0 +1,112 @@
+Project: jackson-datatype-joda
+Version: 2.4.3 (04-Oct-2014)
+
+#45: Can't use LocalTime, LocalDate & LocalDateTime as Key type for a Map
+ (contributed by Brad K, reported by Guido M)
+#46: Interval deserialization fails for negative start instants
+ (reported by Dan G, dgrabows at github)
+
+------------------------------------------------------------------------
+=== History: ===
+------------------------------------------------------------------------
+
+2.4.2 (15-Aug-2014)
+
+No changes since 2.4.0
+
+2.4.1 (17-Jun-2014)
+
+No changes since 2.4.0
+
+2.4.0 (03-Jun-2014)
+
+#40: Add support for `ReadablePeriod`
+ (contributed by 'wimdeblauwe at github')
+- Joda dependency now to 2.2
+
+2.3.3 (14-Apr-2014)
+
+#32: Support use of `@JsonFormat(shape=...)` for timestamp/string choice
+
+2.3.2 (01-Mar-2014)
+
+#16: Adjust existing Date/Time deserializers to support `DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE`
+ (contributed by lukelukeluke at github)
+
+2.3.1 (28-Dec-2013)
+
+#19: Add serializers and deserializers for MonthDay and YearMonth
+ (contributed by ncjones at github)
+#21: Make `DateTimeSerializer` use configured timezone
+ (contributed by pavax at github)
+#23: Package as a bundle (was accidentally not, just bare jar)
+ (suggested by Łukasz D)
+#24: Allow serializing `Duration` using ISO-8601 notation
+ (requested by cowwoc at github)
+#25: Add `KeyDeserializer` for `DateTime`
+ (contributed by Lorcan C)
+#26: Implement `equals()` and `hashCode()` for JodaModule
+ (suggested by Henning S)
+#27: Add support for `DateTimeZone`
+ (requested by Hendy Irawan)
+
+2.3.0 (14-Nov-2013)
+
+#18: Add `JodaMapper`, sub-class of basic `ObjectMapper` that auto-registers
+ Joda module
+
+2.2.3 (25-Aug-2013)
+2.2.2 (27-May-2013)
+2.2.1 (04-May-2013)
+
+No functional changes.
+
+2.2.0 (23-Apr-2013)
+
+#8: Make DateTimeDeserializer abide by configured TimeZone
+- Upgraded version detection not to use VERSION.txt file
+
+2.1.2 (08-Dec-2012)
+2.1.1 (13-Nov-2012)
+
+No functional changes.
+
+2.1.0 (08-Oct-2012)
+
+New minor version, based on Jackson core 2.1.
+
+Improvements:
+
+- [Issue#9]: Add support for (de)serialiazing Interval
+ (submitted by jkolobok at github)
+
+2.0.4 (26-Jun-2012)
+
+Improvements:
+
+- [Issue-6] Add support for handling Local date types
+ (submitted by Chris Stivers)
+- Add support for Joda Instant data type
+
+2.0.3 (15-Jun-2012)
+
+Fixes:
+
+- [Issue-3] Add support for Duration serialization, deserialization
+ (reported by Marshall Pierce)
+
+2.0.2 (18-May-2012)
+
+No fixes, just syncing up with core releases.
+
+2.0.1 (29-Mar-2012)
+
+Fixes:
+
+* Issue-1: Deserializers registered so they would handle Object type,
+ messing up 'untyped' Lists, Maps
+ (reported by Pierre-Alexander M)
+
+2.0.0 (25-Mar-2012)
+
+The first official release
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/JodaMapper.java b/src/main/java/com/fasterxml/jackson/datatype/joda/JodaMapper.java
new file mode 100644
index 0000000..d5e4929
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/JodaMapper.java
@@ -0,0 +1,33 @@
+package com.fasterxml.jackson.datatype.joda;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+public class JodaMapper extends ObjectMapper
+{
+ private static final long serialVersionUID = 1L;
+
+ public JodaMapper() {
+ registerModule(new JodaModule());
+ }
+
+ /**
+ * Convenience method that is shortcut for:
+ *<pre>
+ * module.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ *<pre>
+ */
+ public boolean getWriteDatesAsTimestamps() {
+ return getSerializationConfig().isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ }
+
+ /**
+ * Convenience method that is shortcut for:
+ *<pre>
+ * configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, state)
+ *<pre>
+ */
+ public void setWriteDatesAsTimestamps(boolean state) {
+ configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, state);
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/JodaModule.java b/src/main/java/com/fasterxml/jackson/datatype/joda/JodaModule.java
new file mode 100644
index 0000000..91eca1c
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/JodaModule.java
@@ -0,0 +1,70 @@
+package com.fasterxml.jackson.datatype.joda;
+
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.fasterxml.jackson.datatype.joda.deser.*;
+import com.fasterxml.jackson.datatype.joda.deser.key.*;
+import com.fasterxml.jackson.datatype.joda.ser.*;
+import org.joda.time.*;
+
+public class JodaModule extends SimpleModule
+{
+ private static final long serialVersionUID = 1L;
+
+ public JodaModule()
+ {
+ super(PackageVersion.VERSION);
+ // first deserializers
+ addDeserializer(DateMidnight.class, new DateMidnightDeserializer());
+ addDeserializer(DateTime.class, DateTimeDeserializer.forType(DateTime.class));
+ addDeserializer(DateTimeZone.class, new DateTimeZoneDeserializer());
+
+ addDeserializer(Duration.class, new DurationDeserializer());
+ addDeserializer(Instant.class, new InstantDeserializer());
+ addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
+ addDeserializer(LocalDate.class, new LocalDateDeserializer());
+ addDeserializer(LocalTime.class, new LocalTimeDeserializer());
+ addDeserializer(Period.class, new PeriodDeserializer());
+ addDeserializer(ReadableDateTime.class, DateTimeDeserializer.forType(ReadableDateTime.class));
+ addDeserializer(ReadableInstant.class, DateTimeDeserializer.forType(ReadableInstant.class));
+ addDeserializer(Interval.class, new IntervalDeserializer());
+ addDeserializer(MonthDay.class, new MonthDayDeserializer());
+ addDeserializer(YearMonth.class, new YearMonthDeserializer());
+
+ addDeserializer(ReadablePeriod.class, new ReadablePeriodDeserializer());
+
+ // then serializers:
+ final JsonSerializer<Object> stringSer = ToStringSerializer.instance;
+ addSerializer(DateMidnight.class, new DateMidnightSerializer());
+ addSerializer(DateTime.class, new DateTimeSerializer());
+ addSerializer(DateTimeZone.class, new DateTimeZoneSerializer());
+ addSerializer(Duration.class, new DurationSerializer());
+ addSerializer(Instant.class, new InstantSerializer());
+ addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
+ addSerializer(LocalDate.class, new LocalDateSerializer());
+ addSerializer(LocalTime.class, new LocalTimeSerializer());
+ addSerializer(Period.class, new PeriodSerializer());
+ addSerializer(Interval.class, new IntervalSerializer());
+ addSerializer(MonthDay.class, stringSer);
+ addSerializer(YearMonth.class, stringSer);
+
+ // then key deserializers
+ addKeyDeserializer(DateTime.class, new DateTimeKeyDeserializer());
+ addKeyDeserializer(LocalTime.class, new LocalTimeKeyDeserializer());
+ addKeyDeserializer(LocalDate.class, new LocalDateKeyDeserializer());
+ addKeyDeserializer(LocalDateTime.class, new LocalDateTimeKeyDeserializer());
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return getClass().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ return this == o;
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/PackageVersion.java.in b/src/main/java/com/fasterxml/jackson/datatype/joda/PackageVersion.java.in
new file mode 100644
index 0000000..7860aa1
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/PackageVersion.java.in
@@ -0,0 +1,20 @@
+package @package@;
+
+import com.fasterxml.jackson.core.Version;
+import com.fasterxml.jackson.core.Versioned;
+import com.fasterxml.jackson.core.util.VersionUtil;
+
+/**
+ * Automatically generated from PackageVersion.java.in during
+ * packageVersion-generate execution of maven-replacer-plugin in
+ * pom.xml.
+ */
+public final class PackageVersion implements Versioned {
+ public final static Version VERSION = VersionUtil.parseVersion(
+ "@projectversion@", "@projectgroupid@", "@projectartifactid@");
+
+ @Override
+ public Version version() {
+ return VERSION;
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateMidnightDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateMidnightDeserializer.java
new file mode 100644
index 0000000..43ddce8
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateMidnightDeserializer.java
@@ -0,0 +1,58 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+import java.io.IOException;
+
+import org.joda.time.DateMidnight;
+import org.joda.time.LocalDate;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+
+public class DateMidnightDeserializer
+ extends JodaDeserializerBase<DateMidnight>
+{
+ private static final long serialVersionUID = 1L;
+
+ final static DateTimeFormatter parser = ISODateTimeFormat.localDateParser();
+
+ public DateMidnightDeserializer() { super(DateMidnight.class); }
+
+ @Override
+ public DateMidnight deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ // We'll accept either long (timestamp) or array:
+ if (jp.isExpectedStartArrayToken()) {
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int year = jp.getIntValue();
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int month = jp.getIntValue();
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int day = jp.getIntValue();
+ if (jp.nextToken() != JsonToken.END_ARRAY) {
+ throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY, "after DateMidnight ints");
+ }
+ return new DateMidnight(year, month, day);
+ }
+ switch (jp.getCurrentToken()) {
+ case VALUE_NUMBER_INT:
+ return new DateMidnight(jp.getLongValue());
+ case VALUE_STRING:
+ String str = jp.getText().trim();
+ if (str.length() == 0) { // [JACKSON-360]
+ return null;
+ }
+ LocalDate local = parser.parseLocalDate(str);
+ if (local == null) {
+ return null;
+ }
+ return local.toDateMidnight();
+ default:
+ }
+ throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "expected JSON Array, Number or String");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateTimeDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateTimeDeserializer.java
new file mode 100644
index 0000000..92b5753
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateTimeDeserializer.java
@@ -0,0 +1,64 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+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.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.ReadableDateTime;
+import org.joda.time.ReadableInstant;
+
+import java.io.IOException;
+import java.util.TimeZone;
+
+/**
+ * Basic deserializer for {@link ReadableDateTime} and its subtypes.
+ * Accepts JSON String and Number values and passes those to single-argument constructor.
+ * Does not (yet?) support JSON object; support can be added if desired.
+ */
+public class DateTimeDeserializer
+ extends JodaDeserializerBase<ReadableInstant>
+{
+ private static final long serialVersionUID = 1L;
+
+ @SuppressWarnings("unchecked")
+ public DateTimeDeserializer(Class<? extends ReadableInstant> cls) {
+ super((Class<ReadableInstant>)cls);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T extends ReadableInstant> JsonDeserializer<T> forType(Class<T> cls)
+ {
+ return (JsonDeserializer<T>) new DateTimeDeserializer(cls);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public ReadableDateTime deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ JsonToken t = jp.getCurrentToken();
+ TimeZone tz = ctxt.getTimeZone();
+ DateTimeZone dtz = (tz == null) ? DateTimeZone.UTC : DateTimeZone.forTimeZone(tz);
+
+ if (t == JsonToken.VALUE_NUMBER_INT) {
+ return new DateTime(jp.getLongValue(), dtz);
+ }
+ if (t == JsonToken.VALUE_STRING) {
+ String str = jp.getText().trim();
+ if (str.length() == 0) { // [JACKSON-360]
+ return null;
+ }
+ if (ctxt.isEnabled(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE))
+ return new DateTime(str, dtz);
+ else
+ return DateTime.parse(str);
+ }
+ // TODO: in 2.4, use 'handledType()'
+ throw ctxt.mappingException(getValueClass());
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateTimeZoneDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateTimeZoneDeserializer.java
new file mode 100644
index 0000000..f8fbac0
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateTimeZoneDeserializer.java
@@ -0,0 +1,37 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+import java.io.IOException;
+
+import org.joda.time.DateTimeZone;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+
+/**
+ * Deserializes Joda {@link DateTimeZone}.
+ * Until https://jira.codehaus.org/browse/JACKSON-909 is fixed, here's my take.
+ * @author ceefour
+ */
+public class DateTimeZoneDeserializer extends JodaDeserializerBase<DateTimeZone>
+{
+ private static final long serialVersionUID = 1L;
+
+ public DateTimeZoneDeserializer() { super(DateTimeZone.class); }
+
+ @Override
+ public DateTimeZone deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ JsonToken t = jp.getCurrentToken();
+ if (t == JsonToken.VALUE_NUMBER_INT) {
+ // for fun let's allow use of offsets...
+ return DateTimeZone.forOffsetHours(jp.getIntValue());
+ }
+ if (t == JsonToken.VALUE_STRING) {
+ return DateTimeZone.forID(jp.getText().trim());
+ }
+ throw ctxt.mappingException(DateTimeZone.class, JsonToken.VALUE_STRING);
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DurationDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DurationDeserializer.java
new file mode 100644
index 0000000..268370b
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DurationDeserializer.java
@@ -0,0 +1,37 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+import java.io.IOException;
+
+import org.joda.time.Duration;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
+
+/**
+ * Deserializes a Duration from either an int number of millis or using the {@link Duration#Duration(Object)}
+ * constructor on a JSON string. By default the only supported string format is that used by {@link
+ * Duration#toString()}. (That format for a 3,248 millisecond duration is "PT3.248S".)
+ */
+public final class DurationDeserializer extends StdScalarDeserializer<Duration>
+{
+ private static final long serialVersionUID = 1L;
+
+ public DurationDeserializer() { super(Duration.class); }
+
+ @Override
+ public Duration deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws
+ IOException, JsonProcessingException
+ {
+ switch (jsonParser.getCurrentToken()) {
+ case VALUE_NUMBER_INT: // assume it's millisecond count
+ return new Duration(jsonParser.getLongValue());
+ case VALUE_STRING:
+ return new Duration(jsonParser.getText());
+ default:
+ }
+ throw deserializationContext.mappingException("expected JSON Number or String");
+ }
+}
+
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/InstantDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/InstantDeserializer.java
new file mode 100644
index 0000000..d1373f9
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/InstantDeserializer.java
@@ -0,0 +1,44 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+import java.io.IOException;
+
+import org.joda.time.Instant;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+
+/**
+ * Basic deserializer for {@link org.joda.time.ReadableDateTime} and its subtypes.
+ * Accepts JSON String and Number values and passes those to single-argument constructor.
+ * Does not (yet?) support JSON object; support can be added if desired.
+ */
+public class InstantDeserializer
+ extends JodaDeserializerBase<Instant>
+{
+ private static final long serialVersionUID = 1L;
+
+ public InstantDeserializer() {
+ super(Instant.class);
+ }
+
+ @Override
+ public Instant deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ JsonToken t = jp.getCurrentToken();
+ if (t == JsonToken.VALUE_NUMBER_INT) {
+ return new Instant(jp.getLongValue());
+ }
+ if (t == JsonToken.VALUE_STRING) {
+ String str = jp.getText().trim();
+ if (str.length() == 0) { // [JACKSON-360]
+ return null;
+ }
+ return new Instant(str);
+ }
+ // TODO: in 2.4, use 'handledType()'
+ throw ctxt.mappingException(Instant.class);
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/IntervalDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/IntervalDeserializer.java
new file mode 100644
index 0000000..d902096
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/IntervalDeserializer.java
@@ -0,0 +1,46 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+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 org.joda.time.Interval;
+
+import java.io.IOException;
+
+public class IntervalDeserializer extends JodaDeserializerBase<Interval>
+{
+ private static final long serialVersionUID = 5196071166239332742L;
+
+ public IntervalDeserializer() {
+ super(Interval.class);
+ }
+
+ @Override
+ public Interval deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException
+ {
+ JsonToken t = jsonParser.getCurrentToken();
+ if (t != JsonToken.VALUE_STRING) {
+ throw deserializationContext.mappingException("expected JSON String, got "+t);
+ }
+ String v = jsonParser.getText().trim();
+
+ int dashIndex = v.isEmpty() ? -1 : v.indexOf('-', 1);
+ if (dashIndex < 0) {
+ throw deserializationContext.weirdStringException(v, handledType(), "no hyphen found to separate start, end");
+ }
+ long start, end;
+ String str = v.substring(0, dashIndex);
+ try {
+ start = Long.valueOf(str);
+ str = v.substring(dashIndex + 1);
+ end = Long.valueOf(str);
+ } catch (NumberFormatException e) {
+ throw JsonMappingException.from(jsonParser,
+ "Failed to parse number from '"+str+"' (full source String '"+v+"') to construct "+handledType().getName());
+ }
+ return new Interval(start, end);
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/JodaDeserializerBase.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/JodaDeserializerBase.java
new file mode 100644
index 0000000..b8caed0
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/JodaDeserializerBase.java
@@ -0,0 +1,21 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
+import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
+
+ at SuppressWarnings("serial")
+abstract class JodaDeserializerBase<T> extends StdScalarDeserializer<T>
+{
+ protected JodaDeserializerBase(Class<T> cls) {
+ super(cls);
+ }
+
+ @Override
+ public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException, JsonProcessingException {
+ return typeDeserializer.deserializeTypedFromAny(jp, ctxt);
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateDeserializer.java
new file mode 100644
index 0000000..c8ed47f
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateDeserializer.java
@@ -0,0 +1,53 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+import java.io.IOException;
+
+import org.joda.time.LocalDate;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+
+public class LocalDateDeserializer
+ extends JodaDeserializerBase<LocalDate>
+{
+ private static final long serialVersionUID = 1L;
+
+ final static DateTimeFormatter parser = ISODateTimeFormat.localDateParser();
+
+ public LocalDateDeserializer() { super(LocalDate.class); }
+
+ @Override
+ public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ // [yyyy,mm,dd]
+ if (jp.isExpectedStartArrayToken()) {
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int year = jp.getIntValue();
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int month = jp.getIntValue();
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int day = jp.getIntValue();
+ if (jp.nextToken() != JsonToken.END_ARRAY) {
+ throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY, "after LocalDate ints");
+ }
+ return new LocalDate(year, month, day);
+ }
+ switch (jp.getCurrentToken()) {
+ case VALUE_NUMBER_INT:
+ return new LocalDate(jp.getLongValue());
+ case VALUE_STRING:
+ String str = jp.getText().trim();
+ if (str.length() == 0) { // [JACKSON-360]
+ return null;
+ }
+ return parser.parseLocalDate(str);
+ default:
+ }
+ throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "expected JSON Array, String or Number");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateTimeDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateTimeDeserializer.java
new file mode 100644
index 0000000..7daabc8
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateTimeDeserializer.java
@@ -0,0 +1,69 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+import java.io.IOException;
+
+import org.joda.time.LocalDateTime;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+
+
+public class LocalDateTimeDeserializer
+ extends JodaDeserializerBase<LocalDateTime>
+{
+ private static final long serialVersionUID = 1L;
+
+ final static DateTimeFormatter parser = ISODateTimeFormat.localDateOptionalTimeParser();
+
+ public LocalDateTimeDeserializer() { super(LocalDateTime.class); }
+
+ @Override
+ public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ switch (jp.getCurrentToken()) {
+ case START_ARRAY:
+ // [yyyy,mm,dd,hh,MM,ss,ms]
+ if (jp.isExpectedStartArrayToken()) {
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int year = jp.getIntValue();
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int month = jp.getIntValue();
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int day = jp.getIntValue();
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int hour = jp.getIntValue();
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int minute = jp.getIntValue();
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int second = jp.getIntValue();
+ jp.nextToken(); // VALUE_NUMBER_INT | END_ARRAY
+ // let's leave milliseconds optional?
+ int millisecond = 0;
+ if (jp.getCurrentToken() != JsonToken.END_ARRAY) { // VALUE_NUMBER_INT
+ millisecond = jp.getIntValue();
+ jp.nextToken(); // END_ARRAY?
+ }
+ if (jp.getCurrentToken() != JsonToken.END_ARRAY) {
+ throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY, "after LocalDateTime ints");
+ }
+ return new LocalDateTime(year, month, day, hour, minute, second, millisecond);
+ }
+ break;
+ case VALUE_NUMBER_INT:
+ return new LocalDateTime(jp.getLongValue());
+ case VALUE_STRING:
+ String str = jp.getText().trim();
+ if (str.length() == 0) { // [JACKSON-360]
+ return null;
+ }
+ return parser.parseLocalDateTime(str);
+ default:
+ }
+ throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "expected JSON Array, Number or String");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalTimeDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalTimeDeserializer.java
new file mode 100644
index 0000000..6e92888
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalTimeDeserializer.java
@@ -0,0 +1,59 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+import java.io.IOException;
+
+import org.joda.time.LocalTime;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.databind.DeserializationContext;
+
+public class LocalTimeDeserializer
+ extends JodaDeserializerBase<LocalTime>
+{
+ private static final long serialVersionUID = 1L;
+
+ final static DateTimeFormatter parser = ISODateTimeFormat.localTimeParser();
+
+ public LocalTimeDeserializer() { super(LocalTime.class); }
+
+ @Override
+ public LocalTime deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ switch (jp.getCurrentToken()) {
+ case START_ARRAY:
+ // [HH,MM,ss,ms?]
+ if (jp.isExpectedStartArrayToken()) {
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int hour = jp.getIntValue();
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int minute = jp.getIntValue();
+ jp.nextToken(); // VALUE_NUMBER_INT
+ int second = jp.getIntValue();
+ jp.nextToken(); // VALUE_NUMBER_INT | END_ARRAY
+ int millis = 0;
+ if (jp.getCurrentToken() != JsonToken.END_ARRAY) {
+ millis = jp.getIntValue();
+ jp.nextToken(); // END_ARRAY?
+ }
+ if (jp.getCurrentToken() != JsonToken.END_ARRAY) {
+ throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY, "after LocalTime ints");
+ }
+ return new LocalTime(hour, minute, second, millis);
+ }
+ break;
+ case VALUE_NUMBER_INT:
+ return new LocalTime(jp.getLongValue());
+ case VALUE_STRING:
+ String str = jp.getText().trim();
+ if (str.length() == 0) { // [JACKSON-360]
+ return null;
+ }
+ return parser.parseLocalTime(str);
+ default:
+ }
+ throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "expected JSON Array, String or Number");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/MonthDayDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/MonthDayDeserializer.java
new file mode 100644
index 0000000..46fa442
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/MonthDayDeserializer.java
@@ -0,0 +1,42 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+import java.io.IOException;
+
+import org.joda.time.MonthDay;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+
+/**
+ * A Jackson deserializer for Joda MonthDay objects.
+ * <p>
+ * Expects a string value compatible with MonthDay's parse operation.
+ */
+public class MonthDayDeserializer extends JodaDeserializerBase<MonthDay>
+{
+
+ private static final long serialVersionUID = -2360834248497553111L;
+
+ public MonthDayDeserializer()
+ {
+ super(MonthDay.class);
+ }
+
+ @Override
+ public MonthDay deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException
+ {
+ JsonToken t = jp.getCurrentToken();
+ if (t == JsonToken.VALUE_STRING)
+ {
+ String str = jp.getText().trim();
+ if (str.isEmpty())
+ {
+ return null;
+ }
+ return MonthDay.parse(str);
+ }
+ throw ctxt.wrongTokenException(jp, JsonToken.VALUE_STRING, "expected JSON String");
+ }
+
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/PeriodDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/PeriodDeserializer.java
new file mode 100644
index 0000000..f00f32b
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/PeriodDeserializer.java
@@ -0,0 +1,34 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+import java.io.IOException;
+
+import org.joda.time.Period;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+
+public class PeriodDeserializer
+ extends JodaDeserializerBase<Period>
+{
+ private static final long serialVersionUID = 1L;
+
+ public PeriodDeserializer() { super(Period.class); }
+
+ @Override
+ public Period deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException
+ {
+ // TODO: perhaps support array of numbers...
+ //if (jp.isExpectedStartArrayToken()) { ]
+ switch (jp.getCurrentToken()) {
+ case VALUE_NUMBER_INT: // assume it's millisecond count
+ return new Period(jp.getLongValue());
+ case VALUE_STRING:
+ return new Period(jp.getText());
+ default:
+ }
+ throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "expected JSON Number or String");
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/ReadablePeriodDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/ReadablePeriodDeserializer.java
new file mode 100644
index 0000000..7178005
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/ReadablePeriodDeserializer.java
@@ -0,0 +1,53 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.*;
+
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import org.joda.time.*;
+
+public class ReadablePeriodDeserializer extends JodaDeserializerBase<ReadablePeriod>
+{
+ private static final long serialVersionUID = 1L;
+
+ public ReadablePeriodDeserializer() {
+ super(ReadablePeriod.class);
+ }
+
+ @Override
+ public ReadablePeriod deserialize(JsonParser jsonParser, DeserializationContext ctxt)
+ throws IOException
+ {
+ JsonNode treeNode = jsonParser.readValueAsTree();
+ String periodType = treeNode.path("fieldType").path("name").asText();
+ String periodName = treeNode.path("periodType").path("name").asText();
+ // any "weird" numbers we should worry about?
+ int periodValue = treeNode.path(periodType).asInt();
+ if (periodName.equals( "Seconds" )) {
+ return Seconds.seconds( periodValue );
+ }
+ if (periodName.equals( "Minutes" )) {
+ return Minutes.minutes( periodValue );
+ }
+ if (periodName.equals( "Hours" )) {
+ return Hours.hours( periodValue );
+ }
+ if (periodName.equals( "Days" )) {
+ return Days.days( periodValue );
+ }
+ if (periodName.equals( "Weeks" )) {
+ return Weeks.weeks( periodValue );
+ }
+ if (periodName.equals( "Months" )) {
+ return Months.months( periodValue );
+ }
+ if (periodName.equals( "Years" )) {
+ return Years.years( periodValue );
+ }
+ throw ctxt.mappingException("Don't know how to deserialize ReadablePeriod using periodName '"
+ +periodName+"'");
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/YearMonthDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/YearMonthDeserializer.java
new file mode 100644
index 0000000..ffb515d
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/YearMonthDeserializer.java
@@ -0,0 +1,42 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+import java.io.IOException;
+
+import org.joda.time.YearMonth;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+
+/**
+ * A Jackson deserializer for Joda YearMonth objects.
+ * <p>
+ * Expects a string value compatible with YearMonth's parse operation.
+ */
+public class YearMonthDeserializer extends JodaDeserializerBase<YearMonth>
+{
+
+ private static final long serialVersionUID = -3830851040664795250L;
+
+ public YearMonthDeserializer()
+ {
+ super(YearMonth.class);
+ }
+
+ @Override
+ public YearMonth deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException
+ {
+ JsonToken t = jp.getCurrentToken();
+ if (t == JsonToken.VALUE_STRING)
+ {
+ String str = jp.getText().trim();
+ if (str.isEmpty())
+ {
+ return null;
+ }
+ return YearMonth.parse(str);
+ }
+ throw ctxt.wrongTokenException(jp, JsonToken.VALUE_STRING, "expected JSON String");
+ }
+
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/DateTimeKeyDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/DateTimeKeyDeserializer.java
new file mode 100644
index 0000000..dfd1a49
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/DateTimeKeyDeserializer.java
@@ -0,0 +1,17 @@
+package com.fasterxml.jackson.datatype.joda.deser.key;
+
+import java.io.IOException;
+
+import org.joda.time.*;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+
+public class DateTimeKeyDeserializer extends JodaKeyDeserializer {
+
+ @Override
+ protected DateTime deserialize(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException{
+ return new DateTime(key, DateTimeZone.forTimeZone(ctxt.getTimeZone()));
+ }
+
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/JodaKeyDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/JodaKeyDeserializer.java
new file mode 100644
index 0000000..f08f9a9
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/JodaKeyDeserializer.java
@@ -0,0 +1,21 @@
+package com.fasterxml.jackson.datatype.joda.deser.key;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.KeyDeserializer;
+
+import java.io.IOException;
+
+abstract class JodaKeyDeserializer extends KeyDeserializer {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public final Object deserializeKey(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+ if (key.length() == 0) { // [JACKSON-360]
+ return null;
+ }
+ return deserialize(key, ctxt);
+ }
+
+ protected abstract Object deserialize(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException;
+}
\ No newline at end of file
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/LocalDateKeyDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/LocalDateKeyDeserializer.java
new file mode 100644
index 0000000..88154cf
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/LocalDateKeyDeserializer.java
@@ -0,0 +1,18 @@
+package com.fasterxml.jackson.datatype.joda.deser.key;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import org.joda.time.LocalDate;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+
+import java.io.IOException;
+
+public class LocalDateKeyDeserializer extends JodaKeyDeserializer {
+ private static final DateTimeFormatter parser = ISODateTimeFormat.localDateParser();
+
+ @Override
+ protected LocalDate deserialize(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+ return parser.parseLocalDate(key);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/LocalDateTimeKeyDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/LocalDateTimeKeyDeserializer.java
new file mode 100644
index 0000000..d766760
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/LocalDateTimeKeyDeserializer.java
@@ -0,0 +1,18 @@
+package com.fasterxml.jackson.datatype.joda.deser.key;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import org.joda.time.LocalDateTime;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+
+import java.io.IOException;
+
+public class LocalDateTimeKeyDeserializer extends JodaKeyDeserializer {
+ private static final DateTimeFormatter parser = ISODateTimeFormat.localDateOptionalTimeParser();
+
+ @Override
+ protected LocalDateTime deserialize(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+ return parser.parseLocalDateTime(key);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/LocalTimeKeyDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/LocalTimeKeyDeserializer.java
new file mode 100644
index 0000000..c74da5b
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/LocalTimeKeyDeserializer.java
@@ -0,0 +1,18 @@
+package com.fasterxml.jackson.datatype.joda.deser.key;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import org.joda.time.LocalTime;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+
+import java.io.IOException;
+
+public class LocalTimeKeyDeserializer extends JodaKeyDeserializer {
+ private static final DateTimeFormatter parser = ISODateTimeFormat.localTimeParser();
+
+ @Override
+ protected LocalTime deserialize(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+ return parser.parseLocalTime(key);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateMidnightSerializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateMidnightSerializer.java
new file mode 100644
index 0000000..d76e15b
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateMidnightSerializer.java
@@ -0,0 +1,48 @@
+package com.fasterxml.jackson.datatype.joda.ser;
+
+import java.io.IOException;
+
+import org.joda.time.DateMidnight;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+public final class DateMidnightSerializer
+ extends JodaDateSerializerBase<DateMidnight>
+{
+ protected final static JacksonJodaFormat DEFAULT_FORMAT
+ = new JacksonJodaFormat(DEFAULT_DATEONLY_FORMAT);
+
+ public DateMidnightSerializer() { this(DEFAULT_FORMAT); }
+ public DateMidnightSerializer(JacksonJodaFormat format) {
+ super(DateMidnight.class, format);
+ }
+
+ @Override
+ public DateMidnightSerializer withFormat(JacksonJodaFormat formatter) {
+ return (_format == formatter) ? this : new DateMidnightSerializer(_format);
+ }
+
+ @Override
+ public void serialize(DateMidnight value, JsonGenerator jgen, SerializerProvider provider)
+ throws IOException, JsonGenerationException
+ {
+ if (_useTimestamp(provider)) {
+ // same as with other date-only values
+ jgen.writeStartArray();
+ jgen.writeNumber(value.year().get());
+ jgen.writeNumber(value.monthOfYear().get());
+ jgen.writeNumber(value.dayOfMonth().get());
+ jgen.writeEndArray();
+ } else {
+ jgen.writeString(_format.createFormatter(provider).print(value));
+ }
+ }
+
+ @Override
+ public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) {
+ return createSchemaNode(_useTimestamp(provider) ? "array" : "string", true);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeSerializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeSerializer.java
new file mode 100644
index 0000000..29f6856
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeSerializer.java
@@ -0,0 +1,45 @@
+package com.fasterxml.jackson.datatype.joda.ser;
+
+import java.io.IOException;
+
+import org.joda.time.DateTime;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import org.joda.time.format.ISODateTimeFormat;
+
+public final class DateTimeSerializer
+ extends JodaDateSerializerBase<DateTime>
+{
+ protected final static JacksonJodaFormat DEFAULT_FORMAT
+ = new JacksonJodaFormat(ISODateTimeFormat.dateTime().withZoneUTC());
+
+ public DateTimeSerializer() { this(DEFAULT_FORMAT); }
+ public DateTimeSerializer(JacksonJodaFormat format) {
+ super(DateTime.class, format);
+ }
+
+ @Override
+ public DateTimeSerializer withFormat(JacksonJodaFormat formatter) {
+ return (_format == formatter) ? this : new DateTimeSerializer(formatter);
+ }
+
+ @Override
+ public void serialize(DateTime value, JsonGenerator jgen, SerializerProvider provider)
+ throws IOException, JsonGenerationException
+ {
+ if (_useTimestamp(provider)) {
+ jgen.writeNumber(value.getMillis());
+ } else {
+ jgen.writeString(_format.createFormatter(provider).print(value));
+ }
+ }
+
+ @Override
+ public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) {
+ return createSchemaNode(_useTimestamp(provider) ? "number" : "string", true);
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeZoneSerializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeZoneSerializer.java
new file mode 100644
index 0000000..fab5f76
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeZoneSerializer.java
@@ -0,0 +1,21 @@
+package com.fasterxml.jackson.datatype.joda.ser;
+
+import java.io.IOException;
+
+import org.joda.time.DateTimeZone;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+public class DateTimeZoneSerializer extends JodaSerializerBase<DateTimeZone>
+{
+ public DateTimeZoneSerializer() { super(DateTimeZone.class); }
+
+ @Override
+ public void serialize(DateTimeZone value, JsonGenerator jgen, SerializerProvider provider)
+ throws IOException, JsonProcessingException
+ {
+ jgen.writeString(value.getID());
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DurationSerializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DurationSerializer.java
new file mode 100644
index 0000000..60a0dfe
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DurationSerializer.java
@@ -0,0 +1,46 @@
+package com.fasterxml.jackson.datatype.joda.ser;
+
+import java.io.IOException;
+
+import org.joda.time.Duration;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+/**
+ * Serializes a Duration; either as number of millis, or, if textual output
+ * requested, using ISO-8601 format.
+ */
+public final class DurationSerializer
+ extends JodaDateSerializerBase<Duration>
+{
+ protected final static JacksonJodaFormat DEFAULT_FORMAT = new JacksonJodaFormat(DEFAULT_DATEONLY_FORMAT);
+
+ public DurationSerializer() { this(DEFAULT_FORMAT); }
+ public DurationSerializer(JacksonJodaFormat formatter) {
+ super(Duration.class, formatter);
+ }
+
+ @Override
+ public DurationSerializer withFormat(JacksonJodaFormat formatter) {
+ return (_format == formatter) ? this : new DurationSerializer(formatter);
+ }
+
+ @Override
+ public void serialize(Duration value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
+ JsonProcessingException
+ {
+ if (_useTimestamp(provider)) {
+ jgen.writeNumber(value.getMillis());
+ } else {
+ jgen.writeString(value.toString());
+ }
+ }
+
+ @Override
+ public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) {
+ return createSchemaNode(_useTimestamp(provider) ? "number" : "string", true);
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/InstantSerializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/InstantSerializer.java
new file mode 100644
index 0000000..ab10b49
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/InstantSerializer.java
@@ -0,0 +1,42 @@
+package com.fasterxml.jackson.datatype.joda.ser;
+
+import java.io.IOException;
+
+import org.joda.time.Instant;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+public final class InstantSerializer
+ extends JodaDateSerializerBase<Instant>
+{
+ protected final static JacksonJodaFormat DEFAULT_FORMAT = new JacksonJodaFormat(DEFAULT_DATEONLY_FORMAT);
+
+ public InstantSerializer() { this(DEFAULT_FORMAT); }
+ public InstantSerializer(JacksonJodaFormat format) {
+ super(Instant.class, format);
+ }
+
+ @Override
+ public InstantSerializer withFormat(JacksonJodaFormat formatter) {
+ return (_format == formatter) ? this : new InstantSerializer(formatter);
+ }
+
+ @Override
+ public void serialize(Instant value, JsonGenerator jgen, SerializerProvider provider)
+ throws IOException, JsonGenerationException
+ {
+ if (_useTimestamp(provider)) {
+ jgen.writeNumber(value.getMillis());
+ } else {
+ jgen.writeString(value.toString());
+ }
+ }
+
+ @Override
+ public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) {
+ return createSchemaNode(_useTimestamp(provider) ? "number" : "string", true);
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/IntervalSerializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/IntervalSerializer.java
new file mode 100644
index 0000000..f5b8552
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/IntervalSerializer.java
@@ -0,0 +1,24 @@
+package com.fasterxml.jackson.datatype.joda.ser;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import org.joda.time.Interval;
+
+import java.io.IOException;
+
+/**
+ * @author jkolobok
+ */
+public class IntervalSerializer extends JodaSerializerBase<Interval> {
+
+ public IntervalSerializer() {
+ super(Interval.class);
+ }
+
+ @Override
+ public void serialize(Interval interval, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonGenerationException {
+ jsonGenerator.writeString(interval.getStartMillis() + "-" + interval.getEndMillis());
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/JacksonJodaFormat.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/JacksonJodaFormat.java
new file mode 100644
index 0000000..ba46f6d
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/JacksonJodaFormat.java
@@ -0,0 +1,184 @@
+package com.fasterxml.jackson.datatype.joda.ser;
+
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.joda.time.DateTimeZone;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+/**
+ * Simple container used to encapsulate (some of) gory details of
+ * customizations related to date/time formatting.
+ */
+public class JacksonJodaFormat
+{
+ private final static String JODA_STYLE_CHARS = "SMLF-";
+
+ protected final static Locale DEFAULT_LOCALE;
+ static {
+ DEFAULT_LOCALE = Locale.getDefault();
+ }
+
+ protected final DateTimeFormatter _formatter;
+
+ /**
+ * Flag that indicates that serialization must be done as the
+ * Java timestamp, regardless of other settings.
+ */
+ protected final Boolean _useTimestamp;
+
+ protected final TimeZone _jdkTimezone;
+
+ protected final boolean _explicitTimezone;
+
+ protected final Locale _locale;
+
+ protected final boolean _explicitLocale;
+
+ public JacksonJodaFormat(DateTimeFormatter defaultFormatter) {
+ _useTimestamp = null;
+ _jdkTimezone = defaultFormatter.getZone().toTimeZone();
+ _locale = DEFAULT_LOCALE;
+ _formatter = defaultFormatter;
+ _explicitTimezone = false;
+ _explicitLocale = false;
+ }
+
+ public JacksonJodaFormat(JacksonJodaFormat base, Boolean useTimestamp)
+ {
+ _useTimestamp = useTimestamp;
+ _formatter = base._formatter;
+ _jdkTimezone = base._jdkTimezone;
+ _explicitTimezone = base._explicitTimezone;
+ _locale = base._locale;
+ _explicitLocale = base._explicitLocale;
+ }
+
+ public JacksonJodaFormat(JacksonJodaFormat base,
+ DateTimeFormatter formatter)
+ {
+ _useTimestamp = base._useTimestamp;
+ _formatter = formatter;
+ _jdkTimezone = base._jdkTimezone;
+ _explicitTimezone = base._explicitTimezone;
+ _locale = base._locale;
+ _explicitLocale = base._explicitLocale;
+ }
+
+ public JacksonJodaFormat(JacksonJodaFormat base, TimeZone jdkTimezone)
+ {
+ _useTimestamp = base._useTimestamp;
+ _jdkTimezone = jdkTimezone;
+ _explicitTimezone = true;
+ _locale = base._locale;
+ _explicitLocale = base._explicitLocale;
+ _formatter = base._formatter.withZone(DateTimeZone.forTimeZone(jdkTimezone));
+ }
+
+ public JacksonJodaFormat(JacksonJodaFormat base, Locale locale)
+ {
+ _useTimestamp = base._useTimestamp;
+ _jdkTimezone = base._jdkTimezone;
+ _explicitTimezone = base._explicitTimezone;
+ _locale = locale;
+ _explicitLocale = true;
+ _formatter = base._formatter.withLocale(locale);
+ }
+
+ /*
+ /**********************************************************
+ /* Factory methods
+ /**********************************************************
+ */
+
+ protected JacksonJodaFormat withUseTimestamp(Boolean useTimestamp) {
+ if (_useTimestamp != null && _useTimestamp.equals(useTimestamp)) {
+ return this;
+ }
+ return new JacksonJodaFormat(this, useTimestamp);
+ }
+
+ protected JacksonJodaFormat withFormat(String format) {
+ if (format == null || format.isEmpty()) {
+ return this;
+ }
+ DateTimeFormatter formatter;
+
+ if (_isStyle(format)) {
+ formatter = DateTimeFormat.forStyle(format);
+ } else {
+ formatter = DateTimeFormat.forPattern(format);
+ }
+ if (_locale != null) {
+ formatter = formatter.withLocale(_locale);
+ }
+ formatter = formatter.withZone(_formatter.getZone());
+ return new JacksonJodaFormat(this, formatter);
+ }
+
+ protected JacksonJodaFormat withTimeZone(TimeZone tz) {
+ if ((tz == null) || (_jdkTimezone != null && _jdkTimezone.equals(tz))) {
+ return this;
+ }
+ return new JacksonJodaFormat(this, tz);
+ }
+
+ protected JacksonJodaFormat withLocale(Locale locale) {
+ if ((locale == null) || (_locale != null && _locale.equals(locale))) {
+ return this;
+ }
+ return new JacksonJodaFormat(this, locale);
+ }
+
+ /*
+ /**********************************************************
+ /* Factory methods for other types
+ /**********************************************************
+ */
+
+ public boolean useTimestamp(SerializerProvider provider)
+ {
+ if (_useTimestamp != null) {
+ return _useTimestamp.booleanValue();
+ }
+ return provider.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ }
+
+ public DateTimeFormatter createFormatter(SerializerProvider provider)
+ {
+ DateTimeFormatter formatter = _formatter;
+
+ if (!_explicitLocale) {
+ Locale loc = provider.getLocale();
+ if (loc != null && !loc.equals(_locale)) {
+ formatter = formatter.withLocale(loc);
+ }
+ }
+ if (!_explicitTimezone) {
+ TimeZone tz = provider.getTimeZone();
+ if (tz != null && !tz.equals(_jdkTimezone)) {
+ formatter = formatter.withZone(DateTimeZone.forTimeZone(tz));
+ }
+ }
+
+ return formatter;
+ }
+
+ /*
+ /**********************************************************
+ /* Helper methods
+ /**********************************************************
+ */
+
+ protected static boolean _isStyle(String formatStr) {
+ if (formatStr.length() != 2) {
+ return false;
+ }
+ return (JODA_STYLE_CHARS.indexOf(formatStr.charAt(0)) >= 0)
+ && (JODA_STYLE_CHARS.indexOf(formatStr.charAt(0)) >= 0);
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/JodaDateSerializerBase.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/JodaDateSerializerBase.java
new file mode 100644
index 0000000..a642c52
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/JodaDateSerializerBase.java
@@ -0,0 +1,78 @@
+package com.fasterxml.jackson.datatype.joda.ser;
+
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.introspect.Annotated;
+import com.fasterxml.jackson.databind.ser.ContextualSerializer;
+
+public abstract class JodaDateSerializerBase<T> extends JodaSerializerBase<T>
+// need contextualization to read per-property annotations
+ implements ContextualSerializer
+{
+ protected final static DateTimeFormatter DEFAULT_DATEONLY_FORMAT
+ = ISODateTimeFormat.date().withZoneUTC();
+
+ protected final static DateTimeFormatter DEFAULT_TIMEONLY_FORMAT
+ = ISODateTimeFormat.time().withZoneUTC();
+
+ protected final static DateTimeFormatter DEFAULT_LOCAL_DATETIME_FORMAT
+ = ISODateTimeFormat.dateTime().withZoneUTC();
+
+ protected final JacksonJodaFormat _format;
+
+ protected JodaDateSerializerBase(Class<T> type, JacksonJodaFormat format)
+ {
+ super(type);
+ _format = format;
+ }
+
+ public abstract JodaDateSerializerBase<T> withFormat(JacksonJodaFormat format);
+
+ @Override
+ public JsonSerializer<?> createContextual(SerializerProvider prov,
+ BeanProperty property) throws JsonMappingException
+ {
+ if (property != null) {
+ JsonFormat.Value ann = prov.getAnnotationIntrospector().findFormat((Annotated)property.getMember());
+ if (ann != null) {
+ JacksonJodaFormat format = _format;
+
+ Boolean useTimestamp;
+
+ // Simple case first: serialize as numeric timestamp?
+ if (ann.getShape().isNumeric()) {
+ useTimestamp = Boolean.TRUE;
+ } else if (ann.getShape() == JsonFormat.Shape.STRING) {
+ useTimestamp = Boolean.FALSE;
+ } else {
+ useTimestamp = null;
+ }
+ // must not call if flag defined, to rely on defaults:
+ if (useTimestamp != null) {
+ format = format.withUseTimestamp(useTimestamp);
+ }
+ // for others, safe to call, null/empty just ignored
+ format = format.withFormat(ann.getPattern().trim());
+ format = format.withLocale(ann.getLocale());
+ format = format.withTimeZone(ann.getTimeZone());
+ if (format != _format) {
+ return withFormat(format);
+ }
+ }
+ }
+ return this;
+ }
+
+ /*
+ /**********************************************************
+ /* Helper methods
+ /**********************************************************
+ */
+
+ protected boolean _useTimestamp(SerializerProvider provider) {
+ return _format.useTimestamp(provider);
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/JodaSerializerBase.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/JodaSerializerBase.java
new file mode 100644
index 0000000..c74f175
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/JodaSerializerBase.java
@@ -0,0 +1,21 @@
+package com.fasterxml.jackson.datatype.joda.ser;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+abstract class JodaSerializerBase<T> extends StdSerializer<T>
+{
+ protected JodaSerializerBase(Class<T> cls) { super(cls); }
+
+ @Override
+ public void serializeWithType(T value, JsonGenerator jgen, SerializerProvider provider, TypeSerializer typeSer) throws IOException, JsonProcessingException {
+ typeSer.writeTypePrefixForScalar(value, jgen);
+ serialize(value, jgen, provider);
+ typeSer.writeTypeSuffixForScalar(value, jgen);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/LocalDateSerializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/LocalDateSerializer.java
new file mode 100644
index 0000000..51bae6f
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/LocalDateSerializer.java
@@ -0,0 +1,48 @@
+package com.fasterxml.jackson.datatype.joda.ser;
+
+import java.io.IOException;
+
+import org.joda.time.LocalDate;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+public final class LocalDateSerializer
+ extends JodaDateSerializerBase<LocalDate>
+{
+ protected final static JacksonJodaFormat DEFAULT_FORMAT
+ = new JacksonJodaFormat(DEFAULT_DATEONLY_FORMAT);
+
+ public LocalDateSerializer() { this(DEFAULT_FORMAT); }
+ public LocalDateSerializer(JacksonJodaFormat format) {
+ super(LocalDate.class, format);
+ }
+
+ @Override
+ public LocalDateSerializer withFormat(JacksonJodaFormat formatter) {
+ return (_format == formatter) ? this : new LocalDateSerializer(formatter);
+ }
+
+ @Override
+ public void serialize(LocalDate value, JsonGenerator jgen, SerializerProvider provider)
+ throws IOException, JsonGenerationException
+ {
+ if (_useTimestamp(provider)) {
+ // Timestamp here actually means an array of values
+ jgen.writeStartArray();
+ jgen.writeNumber(value.year().get());
+ jgen.writeNumber(value.monthOfYear().get());
+ jgen.writeNumber(value.dayOfMonth().get());
+ jgen.writeEndArray();
+ } else {
+ jgen.writeString(_format.createFormatter(provider).print(value));
+ }
+ }
+
+ @Override
+ public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) {
+ return createSchemaNode(_useTimestamp(provider) ? "array" : "string", true);
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/LocalDateTimeSerializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/LocalDateTimeSerializer.java
new file mode 100644
index 0000000..a361cdd
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/LocalDateTimeSerializer.java
@@ -0,0 +1,52 @@
+package com.fasterxml.jackson.datatype.joda.ser;
+
+import java.io.IOException;
+
+import org.joda.time.LocalDateTime;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+public final class LocalDateTimeSerializer
+ extends JodaDateSerializerBase<LocalDateTime>
+{
+ protected final static JacksonJodaFormat DEFAULT_FORMAT
+ = new JacksonJodaFormat(DEFAULT_LOCAL_DATETIME_FORMAT);
+
+ public LocalDateTimeSerializer() { this(DEFAULT_FORMAT); }
+ public LocalDateTimeSerializer(JacksonJodaFormat format) {
+ super(LocalDateTime.class, format);
+ }
+
+ @Override
+ public LocalDateTimeSerializer withFormat(JacksonJodaFormat formatter) {
+ return (_format == formatter) ? this : new LocalDateTimeSerializer(formatter);
+ }
+
+ @Override
+ public void serialize(LocalDateTime value, JsonGenerator jgen, SerializerProvider provider)
+ throws IOException, JsonGenerationException
+ {
+ if (_useTimestamp(provider)) {
+ // Timestamp here actually means an array of values
+ jgen.writeStartArray();
+ jgen.writeNumber(value.year().get());
+ jgen.writeNumber(value.monthOfYear().get());
+ jgen.writeNumber(value.dayOfMonth().get());
+ jgen.writeNumber(value.hourOfDay().get());
+ jgen.writeNumber(value.minuteOfHour().get());
+ jgen.writeNumber(value.secondOfMinute().get());
+ jgen.writeNumber(value.millisOfSecond().get());
+ jgen.writeEndArray();
+ } else {
+ jgen.writeString(_format.createFormatter(provider).print(value));
+ }
+ }
+
+ @Override
+ public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) {
+ return createSchemaNode(_useTimestamp(provider) ? "array" : "string", true);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/LocalTimeSerializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/LocalTimeSerializer.java
new file mode 100644
index 0000000..841895c
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/LocalTimeSerializer.java
@@ -0,0 +1,49 @@
+package com.fasterxml.jackson.datatype.joda.ser;
+
+import java.io.IOException;
+
+import org.joda.time.LocalTime;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+public final class LocalTimeSerializer
+ extends JodaDateSerializerBase<LocalTime>
+{
+ protected final static JacksonJodaFormat DEFAULT_FORMAT
+ = new JacksonJodaFormat(DEFAULT_TIMEONLY_FORMAT);
+
+ public LocalTimeSerializer() { this(DEFAULT_FORMAT); }
+ public LocalTimeSerializer(JacksonJodaFormat format) {
+ super(LocalTime.class, format);
+ }
+
+ @Override
+ public LocalTimeSerializer withFormat(JacksonJodaFormat formatter) {
+ return (_format == formatter) ? this : new LocalTimeSerializer(formatter);
+ }
+
+ @Override
+ public void serialize(LocalTime value, JsonGenerator jgen, SerializerProvider provider)
+ throws IOException, JsonGenerationException
+ {
+ if (_useTimestamp(provider)) {
+ // Timestamp here actually means an array of values
+ jgen.writeStartArray();
+ jgen.writeNumber(value.hourOfDay().get());
+ jgen.writeNumber(value.minuteOfHour().get());
+ jgen.writeNumber(value.secondOfMinute().get());
+ jgen.writeNumber(value.millisOfSecond().get());
+ jgen.writeEndArray();
+ } else {
+ jgen.writeString(_format.createFormatter(provider).print(value));
+ }
+ }
+
+ @Override
+ public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) {
+ return createSchemaNode(_useTimestamp(provider) ? "array" : "string", true);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/PeriodSerializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/PeriodSerializer.java
new file mode 100644
index 0000000..ee3cff3
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/PeriodSerializer.java
@@ -0,0 +1,37 @@
+package com.fasterxml.jackson.datatype.joda.ser;
+
+import java.io.IOException;
+
+import org.joda.time.ReadablePeriod;
+import org.joda.time.format.ISOPeriodFormat;
+import org.joda.time.format.PeriodFormatter;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+/**
+ * Serializes a {@link ReadablePeriod} using Joda default formatting.
+ *<p>
+ * TODO: allow serialization as an array of numbers, for numeric ("timestamp")
+ * notation?
+ */
+public final class PeriodSerializer extends JodaSerializerBase<ReadablePeriod>
+{
+ protected final PeriodFormatter defaultFormat = ISOPeriodFormat.standard();
+
+ public PeriodSerializer() { super(ReadablePeriod.class); }
+
+ @Override
+ public void serialize(ReadablePeriod value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
+ JsonProcessingException
+ {
+ jgen.writeString(defaultFormat.print(value));
+ }
+
+ @Override
+ public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) {
+ return createSchemaNode("string", true);
+ }
+}
diff --git a/src/main/resources/META-INF/LICENSE b/src/main/resources/META-INF/LICENSE
new file mode 100644
index 0000000..f5f45d2
--- /dev/null
+++ b/src/main/resources/META-INF/LICENSE
@@ -0,0 +1,8 @@
+This copy of Jackson JSON processor streaming parser/generator is licensed under the
+Apache (Software) License, version 2.0 ("the License").
+See the License for details about distribution rights, and the
+specific rights regarding derivate works.
+
+You may obtain a copy of the License at:
+
+http://www.apache.org/licenses/LICENSE-2.0
diff --git a/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module b/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module
new file mode 100644
index 0000000..f21f03f
--- /dev/null
+++ b/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module
@@ -0,0 +1 @@
+com.fasterxml.jackson.datatype.joda.JodaModule
diff --git a/src/test/java/com/fasterxml/jackson/datatype/joda/DateTimeTest.java b/src/test/java/com/fasterxml/jackson/datatype/joda/DateTimeTest.java
new file mode 100644
index 0000000..f7da384
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/datatype/joda/DateTimeTest.java
@@ -0,0 +1,100 @@
+package com.fasterxml.jackson.datatype.joda;
+
+import java.io.IOException;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+public class DateTimeTest extends JodaTestBase
+{
+ private static class DateAsText {
+ @JsonFormat(shape=JsonFormat.Shape.STRING)
+ public DateTime date;
+
+ public DateAsText(DateTime d) {
+ date = d;
+ }
+ }
+
+ private static class CustomDate {
+ @JsonFormat(shape=JsonFormat.Shape.STRING, pattern="SS")
+ public DateTime date;
+
+ public CustomDate(DateTime d) {
+ date = d;
+ }
+ }
+
+ @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_ARRAY, property = "@class")
+ private static interface ObjectConfiguration {
+ }
+
+ /*
+ /**********************************************************
+ /* Test methods
+ /**********************************************************
+ */
+
+ private final ObjectMapper MAPPER = jodaMapper();
+
+ private final static ObjectMapper STRING_MAPPER = jodaMapper();
+ static {
+ STRING_MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ }
+
+ private final DateTime DATE_JAN_1_1970_UTC = new DateTime(0L, DateTimeZone.UTC);
+
+ /**
+ * First: let's ensure that serialization does not fail
+ * with an error (see [JACKSON-157]).
+ */
+ public void testSerializationDefaultAsTimestamp() throws IOException
+ {
+ // let's use epoch time (Jan 1, 1970, UTC)
+ // by default, dates use timestamp, so:
+ assertEquals("0", MAPPER.writeValueAsString(DATE_JAN_1_1970_UTC));
+ }
+
+ public void testSerializationFeatureNoTimestamp() throws IOException
+ {
+ ObjectMapper m = jodaMapper();
+ m.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ assertEquals(quote("1970-01-01T00:00:00.000Z"), m.writeValueAsString(DATE_JAN_1_1970_UTC));
+ }
+
+ public void testAnnotationAsText() throws IOException
+ {
+ ObjectMapper m = jodaMapper();
+ m.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ // with annotations, doesn't matter if mapper configured to use timestamps
+ assertEquals(aposToQuotes("{'date':'1970-01-01T00:00:00.000Z'}"),
+ m.writeValueAsString(new DateAsText(DATE_JAN_1_1970_UTC)));
+ }
+
+ public void testCustomPatternStyle() throws IOException
+ {
+ // or, using annotations
+ assertEquals(aposToQuotes("{'date':'1/1/70 12:00 AM'}"),
+ STRING_MAPPER.writeValueAsString(new CustomDate(DATE_JAN_1_1970_UTC)));
+ }
+
+ public void testSerializationWithTypeInfo() throws IOException
+ {
+ // let's use epoch time (Jan 1, 1970, UTC)
+ DateTime dt = new DateTime(0L, DateTimeZone.UTC);
+ // by default, dates use timestamp, so:
+ assertEquals("0", MAPPER.writeValueAsString(dt));
+
+ // but if re-configured, as regular ISO-8601 string
+ ObjectMapper m = jodaMapper();
+ m.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ m.addMixInAnnotations(DateTime.class, ObjectConfiguration.class);
+ assertEquals("[\"org.joda.time.DateTime\",\"1970-01-01T00:00:00.000Z\"]",
+ m.writeValueAsString(dt));
+ }
+}
diff --git a/src/test/java/com/fasterxml/jackson/datatype/joda/JodaMapperTest.java b/src/test/java/com/fasterxml/jackson/datatype/joda/JodaMapperTest.java
new file mode 100644
index 0000000..fbf1e7a
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/datatype/joda/JodaMapperTest.java
@@ -0,0 +1,32 @@
+package com.fasterxml.jackson.datatype.joda;
+
+import com.fasterxml.jackson.databind.SerializationFeature;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+public class JodaMapperTest
+{
+ @Test
+ public void test_writeDatesAsTimestamps_property()
+ {
+ JodaMapper objectUnderTest = new JodaMapper();
+
+ objectUnderTest.setWriteDatesAsTimestamps(true);
+ assertThat(objectUnderTest.getWriteDatesAsTimestamps(), is(true));
+
+ objectUnderTest.setWriteDatesAsTimestamps(false);
+ assertThat(objectUnderTest.getWriteDatesAsTimestamps(), is(false));
+ }
+
+ @Test
+ public void setWriteDatesAsTimestamps_sets_the_WRITE_DATES_AS_TIMESTAMPS_configuration()
+ {
+ JodaMapper objectUnderTest = new JodaMapper();
+
+ objectUnderTest.setWriteDatesAsTimestamps(true);
+
+ assertThat(objectUnderTest.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS), is(true));
+ }
+}
diff --git a/src/test/java/com/fasterxml/jackson/datatype/joda/JodaSerializationTest.java b/src/test/java/com/fasterxml/jackson/datatype/joda/JodaSerializationTest.java
new file mode 100644
index 0000000..4037391
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/datatype/joda/JodaSerializationTest.java
@@ -0,0 +1,246 @@
+package com.fasterxml.jackson.datatype.joda;
+
+import java.io.IOException;
+
+import org.joda.time.*;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+public class JodaSerializationTest extends JodaTestBase
+{
+ @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_ARRAY, property = "@class")
+ private static interface ObjectConfiguration {
+ }
+
+ private final ObjectMapper MAPPER = jodaMapper();
+
+ /*
+ /**********************************************************
+ /* Tests for DateMidnight type
+ /**********************************************************
+ */
+
+ public void testDateMidnightSer() throws IOException
+ {
+ DateMidnight date = new DateMidnight(2001, 5, 25);
+ // default format is that of JSON array...
+ assertEquals("[2001,5,25]", MAPPER.writeValueAsString(date));
+ // but we can force it to be a String as well (note: here we assume this is
+ // dynamically changeable)
+ ObjectMapper mapper = jodaMapper();
+ mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ assertEquals(quote("2001-05-25"), mapper.writeValueAsString(date));
+ }
+
+ public void testDateMidnightSerWithTypeInfo() throws IOException
+ {
+ DateMidnight date = new DateMidnight(2001, 5, 25);
+ // default format is that of JSON array...
+ assertEquals("[2001,5,25]", MAPPER.writeValueAsString(date));
+ // but we can force it to be a String as well (note: here we assume this is
+ // dynamically changeable)
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(DateMidnight.class, ObjectConfiguration.class);
+ mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ assertEquals("[\"org.joda.time.DateMidnight\",\"2001-05-25\"]", mapper.writeValueAsString(date));
+ }
+
+ /*
+ /**********************************************************
+ /* Tests for Interval type
+ /**********************************************************
+ */
+
+ public void testIntervalSer() throws IOException
+ {
+ Interval interval = new Interval(1396439982, 1396440001);
+ assertEquals(quote("1396439982-1396440001"), MAPPER.writeValueAsString(interval));
+ }
+
+ public void testIntervalSerWithTypeInfo() throws IOException
+ {
+ Interval interval = new Interval(1396439982, 1396440001);
+
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(Interval.class, ObjectConfiguration.class);
+ assertEquals("[\"org.joda.time.Interval\"," + quote("1396439982-1396440001") + "]",
+ mapper.writeValueAsString(interval));
+ }
+
+ /*
+ /**********************************************************
+ /* Tests for LocalDate type
+ /**********************************************************
+ */
+
+ public void testLocalDateSer() throws IOException
+ {
+ LocalDate date = new LocalDate(2001, 5, 25);
+ // default format is that of JSON array...
+ assertEquals("[2001,5,25]", MAPPER.writeValueAsString(date));
+
+ // but we can force it to be a String as well (note: here we assume this is
+ // dynamically changeable)
+ ObjectMapper mapper = jodaMapper();
+ mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ assertEquals(quote("2001-05-25"), mapper.writeValueAsString(date));
+ }
+
+ public void testLocalDateSerWithTypeInfo() throws IOException
+ {
+ LocalDate date = new LocalDate(2001, 5, 25);
+ // default format is that of JSON array...
+ assertEquals("[2001,5,25]", MAPPER.writeValueAsString(date));
+
+ // but we can force it to be a String as well (note: here we assume this is
+ // dynamically changeable)
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(LocalDate.class, ObjectConfiguration.class);
+ mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ assertEquals("[\"org.joda.time.LocalDate\",\"2001-05-25\"]", mapper.writeValueAsString(date));
+ }
+
+
+ /*
+ /**********************************************************
+ /* Tests for LocalTime type
+ /**********************************************************
+ */
+
+ public void testLocalTimeSer() throws IOException
+ {
+ LocalTime date = new LocalTime(13,20,54);
+ // default format is that of JSON array...
+ assertEquals("[13,20,54,0]", MAPPER.writeValueAsString(date));
+
+ // but we can force it to be a String as well (note: here we assume this is
+ // dynamically changeable)
+ ObjectMapper mapper = jodaMapper();
+ mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ assertEquals(quote("13:20:54.000"), mapper.writeValueAsString(date));
+ }
+
+ public void testLocalTimeSerWithTypeInfo() throws IOException
+ {
+ LocalTime date = new LocalTime(13,20,54);
+ // default format is that of JSON array...
+ assertEquals("[13,20,54,0]", MAPPER.writeValueAsString(date));
+
+ // but we can force it to be a String as well (note: here we assume this is
+ // dynamically changeable)
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(LocalTime.class, ObjectConfiguration.class);
+ mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ assertEquals("[\"org.joda.time.LocalTime\",\"13:20:54.000\"]", mapper.writeValueAsString(date));
+ }
+
+ /*
+ /**********************************************************
+ /* Tests for LocalDateTime type
+ /**********************************************************
+ */
+
+ public void testLocalDateTimeSer() throws IOException
+ {
+ LocalDateTime date = new LocalDateTime(2001, 5, 25,
+ 10, 15, 30, 37);
+ // default format is that of JSON array...
+ assertEquals("[2001,5,25,10,15,30,37]", MAPPER.writeValueAsString(date));
+ // but we can force it to be a String as well (note: here we assume this is
+ // dynamically changeable)
+ ObjectMapper mapper = jodaMapper();
+ mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ assertEquals(quote("2001-05-25T10:15:30.037"), mapper.writeValueAsString(date));
+ }
+
+ public void testLocalDateTimeSerWithTypeInfo() throws IOException
+ {
+ LocalDateTime date = new LocalDateTime(2001, 5, 25,
+ 10, 15, 30, 37);
+ // default format is that of JSON array...
+ assertEquals("[2001,5,25,10,15,30,37]", MAPPER.writeValueAsString(date));
+ // but we can force it to be a String as well (note: here we assume this is
+ // dynamically changeable)
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(LocalDateTime.class, ObjectConfiguration.class);
+ mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ assertEquals("[\"org.joda.time.LocalDateTime\",\"2001-05-25T10:15:30.037\"]", mapper.writeValueAsString(date));
+ }
+
+ /*
+ /**********************************************************
+ /* Tests for Period type
+ /**********************************************************
+ */
+
+ public void testPeriodSer() throws IOException
+ {
+ Period in = new Period(1, 2, 3, 4);
+ assertEquals(quote("PT1H2M3.004S"), MAPPER.writeValueAsString(in));
+ }
+
+ public void testPeriodSerWithTypeInfo() throws IOException
+ {
+ Period in = new Period(1, 2, 3, 4);
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(Period.class, ObjectConfiguration.class);
+ assertEquals("[\"org.joda.time.Period\",\"PT1H2M3.004S\"]", mapper.writeValueAsString(in));
+ }
+
+ /*
+ /**********************************************************
+ /* Tests for Duration type
+ /**********************************************************
+ */
+
+ public void testDurationSer() throws IOException
+ {
+ Duration d = new Duration(3123422);
+ String json = MAPPER.writeValueAsString(d);
+ assertEquals("3123422", json);
+
+ assertEquals(quote("PT3123.422S"), MAPPER.writer()
+ .without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
+ .writeValueAsString(d));
+ }
+
+ public void testDurationSerWithTypeInfo() throws IOException
+ {
+ Duration d = new Duration(3123422);
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(Duration.class, ObjectConfiguration.class);
+ String json = mapper.writeValueAsString(d);
+ assertEquals("[\"org.joda.time.Duration\",3123422]", json);
+ }
+
+ public void testInstantSer() throws IOException {
+ Instant instant = new Instant(0L);
+
+ // by default, dates use timestamp, so:
+ assertEquals("0", MAPPER.writeValueAsString(instant));
+
+ // but if re-configured, as regular ISO-8601 string
+ ObjectMapper m = jodaMapper();
+ m.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ assertEquals(quote("1970-01-01T00:00:00.000Z"), m.writeValueAsString(instant));
+ }
+
+ public void testMonthDaySer() throws Exception
+ {
+ MonthDay monthDay = new MonthDay(7, 23);
+ ObjectMapper mapper = jodaMapper();
+ String json = mapper.writeValueAsString(monthDay);
+ assertEquals(quote("--07-23"), json);
+ }
+
+ public void testYearMonthSer() throws Exception
+ {
+ YearMonth yearMonth = new YearMonth(2013, 8);
+ ObjectMapper mapper = jodaMapper();
+ String json = mapper.writeValueAsString(yearMonth);
+ assertEquals(quote("2013-08"), json);
+ }
+
+}
diff --git a/src/test/java/com/fasterxml/jackson/datatype/joda/JodaTestBase.java b/src/test/java/com/fasterxml/jackson/datatype/joda/JodaTestBase.java
new file mode 100644
index 0000000..d22d1bd
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/datatype/joda/JodaTestBase.java
@@ -0,0 +1,46 @@
+package com.fasterxml.jackson.datatype.joda;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import junit.framework.TestCase;
+
+import java.io.IOException;
+
+import static org.junit.Assert.*;
+
+public abstract class JodaTestBase extends TestCase
+{
+ protected static ObjectMapper jodaMapper()
+ {
+ return new JodaMapper();
+ }
+
+ /*
+ /**********************************************************
+ /* Additional assert methods
+ /**********************************************************
+ */
+
+ protected void assertEquals(int[] exp, int[] act) {
+ assertArrayEquals(exp, act);
+ }
+
+ /*
+ /**********************************************************
+ /* Helper methods
+ /**********************************************************
+ */
+
+ public String quote(String str) {
+ return '"'+str+'"';
+ }
+
+ protected String aposToQuotes(String json) {
+ return json.replace("'", "\"");
+ }
+
+ protected <T> T readAndMapFromString(ObjectMapper m, String input, Class<T> cls)
+ throws IOException
+ {
+ return (T) m.readValue("\""+input+"\"", cls);
+ }
+}
diff --git a/src/test/java/com/fasterxml/jackson/datatype/joda/MixedListTest.java b/src/test/java/com/fasterxml/jackson/datatype/joda/MixedListTest.java
new file mode 100644
index 0000000..c529c96
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/datatype/joda/MixedListTest.java
@@ -0,0 +1,42 @@
+package com.fasterxml.jackson.datatype.joda;
+
+import java.util.*;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class MixedListTest extends JodaTestBase
+{
+ private final ObjectMapper MAPPER = jodaMapper();
+
+ public void testMixedList() throws Exception
+ {
+ final Map<String, Object> map = new HashMap<String, Object>();
+ DateTime dt = new DateTime(DateTimeZone.UTC);
+ map.put("A", dt);
+ map.put("B", 0);
+
+ final String json = MAPPER.writeValueAsString(map);
+ // by default, timestamps should come out as longs...
+
+ final Map<String, Object> result = MAPPER.readValue(json,
+ new TypeReference<Map<String, Object>>() { });
+
+ assertEquals(2, result.size());
+ Object obB = result.get("B");
+ assertNotNull(obB);
+ if (!(obB instanceof Number)) {
+ fail("Expected 'B' to be a Number; instead of value of type "+obB.getClass().getName());
+ }
+
+ assertEquals(Integer.valueOf(0), result.get("B"));
+ Object obA = result.get("A");
+ assertNotNull(obA);
+ if (!(obA instanceof Number)) {
+ fail("Expected 'A' to be a number; instead of value of type "+obA.getClass().getName());
+ }
+ }
+}
diff --git a/src/test/java/com/fasterxml/jackson/datatype/joda/TestVersions.java b/src/test/java/com/fasterxml/jackson/datatype/joda/TestVersions.java
new file mode 100644
index 0000000..d82af95
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/datatype/joda/TestVersions.java
@@ -0,0 +1,29 @@
+package com.fasterxml.jackson.datatype.joda;
+
+import java.io.*;
+
+import com.fasterxml.jackson.core.Versioned;
+
+/**
+ * Simple verification that version access works.
+ */
+public class TestVersions extends JodaTestBase
+{
+ public void testVersions() throws IOException
+ {
+ JodaModule m = new JodaModule();
+ assertVersion(m);
+ }
+
+ /*
+ /**********************************************************
+ /* Helper methods
+ /**********************************************************
+ */
+
+ private void assertVersion(Versioned v)
+ {
+ assertEquals(PackageVersion.VERSION, v.version());
+ }
+}
+
diff --git a/src/test/java/com/fasterxml/jackson/datatype/joda/deser/MiscDeserializationTest.java b/src/test/java/com/fasterxml/jackson/datatype/joda/deser/MiscDeserializationTest.java
new file mode 100644
index 0000000..20209e1
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/datatype/joda/deser/MiscDeserializationTest.java
@@ -0,0 +1,516 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.joda.JodaTestBase;
+
+import org.joda.time.*;
+
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Map;
+import java.util.TimeZone;
+
+/**
+ * Unit tests for verifying limited interoperability for Joda time.
+ * Basic support is added for handling {@link DateTime}; more can be
+ * added over time if and when requested.
+ */
+public class MiscDeserializationTest extends JodaTestBase
+{
+ /*
+ /**********************************************************
+ /* Tests for DateTime (and closely related)
+ /**********************************************************
+ */
+
+ private final ObjectMapper MAPPER = jodaMapper();
+
+ /**
+ * Ok, then: should be able to convert from JSON String or Number,
+ * with standard deserializer we provide.
+ */
+ public void testDeserFromNumber() throws IOException
+ {
+ Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
+ // use some arbitrary but non-default time point (after 1.1.1970)
+ cal.set(Calendar.YEAR, 1972);
+ long timepoint = cal.getTime().getTime();
+
+ // Ok, first: using JSON number (milliseconds since epoch)
+ DateTime dt = MAPPER.readValue(String.valueOf(timepoint), DateTime.class);
+ assertEquals(timepoint, dt.getMillis());
+
+ // And then ISO-8601 String
+ dt = MAPPER.readValue(quote("1972-12-28T12:00:01.000+0000"), DateTime.class);
+ assertEquals("1972-12-28T12:00:01.000Z", dt.toString());
+ }
+
+ public void testDeserReadableDateTime() throws IOException
+ {
+ ReadableDateTime date = MAPPER.readValue(quote("1972-12-28T12:00:01.000+0000"), ReadableDateTime.class);
+ assertNotNull(date);
+ assertEquals("1972-12-28T12:00:01.000Z", date.toString());
+
+ // since 1.6.1, for [JACKSON-360]
+ assertNull(MAPPER.readValue(quote(""), ReadableDateTime.class));
+ }
+
+ // since 2.1.3, for github issue #8
+ public void testDeserReadableDateTimeWithTimeZoneInfo() throws IOException {
+ TimeZone timeZone = TimeZone.getTimeZone("GMT-6");
+ DateTimeZone dateTimeZone = DateTimeZone.forTimeZone(timeZone);
+ MAPPER.setTimeZone(timeZone);
+ ReadableDateTime date = MAPPER.readValue(quote("1972-12-28T12:00:01.000-0600"), ReadableDateTime.class);
+ assertNotNull(date);
+ assertEquals("1972-12-28T12:00:01.000-06:00", date.toString());
+ assertEquals(dateTimeZone, date.getZone());
+
+ // default behavior is to ignore the timezone in serialized data
+ ReadableDateTime otherTzDate = MAPPER.readValue(quote("1972-12-28T12:00:01.000-0700"), ReadableDateTime.class);
+ assertEquals(dateTimeZone, otherTzDate.getZone());
+
+ // since 1.6.1, for [JACKSON-360]
+ assertNull(MAPPER.readValue(quote(""), ReadableDateTime.class));
+ }
+
+ public void testDeserReadableDateTimeWithTimeZoneFromData() throws IOException {
+ ObjectMapper mapper = jodaMapper();
+ mapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
+ mapper.setTimeZone(TimeZone.getTimeZone("GMT-6"));
+ ReadableDateTime date = mapper.readValue(quote("2014-01-20T08:59:01.000-0500"), ReadableDateTime.class);
+ assertEquals(DateTimeZone.forOffsetHours(-5), date.getZone());
+ }
+
+ public void testDeserReadableInstant() throws IOException {
+ ReadableInstant date = MAPPER.readValue(quote("1972-12-28T12:00:01.000+0000"), ReadableInstant.class);
+ assertNotNull(date);
+ assertEquals("1972-12-28T12:00:01.000Z", date.toString());
+
+ // since 1.6.1, for [JACKSON-360]
+ assertNull(MAPPER.readValue(quote(""), ReadableInstant.class));
+ }
+
+ public void testDeserDateTimeWithTypeInfo() throws IOException
+ {
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(DateTime.class, ObjectConfiguration.class);
+ DateTime date = mapper.readValue("[\"org.joda.time.DateTime\",\"1972-12-28T12:00:01.000+0000\"]", DateTime.class);
+ assertNotNull(date);
+ assertEquals("1972-12-28T12:00:01.000Z", date.toString());
+ }
+
+ /*
+ /**********************************************************
+ /* Tests for DateMidnight type
+ /**********************************************************
+ */
+
+ public void testDateMidnightDeser() throws IOException
+ {
+ // couple of acceptable formats, so:
+ DateMidnight date = MAPPER.readValue("[2001,5,25]", DateMidnight.class);
+ assertEquals(2001, date.getYear());
+ assertEquals(5, date.getMonthOfYear());
+ assertEquals(25, date.getDayOfMonth());
+
+ DateMidnight date2 = MAPPER.readValue(quote("2005-07-13"), DateMidnight.class);
+ assertEquals(2005, date2.getYear());
+ assertEquals(7, date2.getMonthOfYear());
+ assertEquals(13, date2.getDayOfMonth());
+
+ // since 1.6.1, for [JACKSON-360]
+ assertNull(MAPPER.readValue(quote(""), DateMidnight.class));
+ }
+
+ public void testDateMidnightDeserWithTypeInfo() throws IOException
+ {
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(DateMidnight.class, ObjectConfiguration.class);
+
+ // couple of acceptable formats, so:
+ DateMidnight date = mapper.readValue("[\"org.joda.time.DateMidnight\",[2001,5,25]]", DateMidnight.class);
+ assertEquals(2001, date.getYear());
+ assertEquals(5, date.getMonthOfYear());
+ assertEquals(25, date.getDayOfMonth());
+
+ DateMidnight date2 = mapper.readValue("[\"org.joda.time.DateMidnight\",\"2005-07-13\"]", DateMidnight.class);
+ assertEquals(2005, date2.getYear());
+ assertEquals(7, date2.getMonthOfYear());
+ assertEquals(13, date2.getDayOfMonth());
+ }
+
+ /*
+ /**********************************************************
+ /* Tests for LocalDate type
+ /**********************************************************
+ */
+
+ public void testLocalDateDeser() throws IOException
+ {
+ // couple of acceptable formats, so:
+ LocalDate date = MAPPER.readValue("[2001,5,25]", LocalDate.class);
+ assertEquals(2001, date.getYear());
+ assertEquals(5, date.getMonthOfYear());
+ assertEquals(25, date.getDayOfMonth());
+
+ LocalDate date2 = MAPPER.readValue(quote("2005-07-13"), LocalDate.class);
+ assertEquals(2005, date2.getYear());
+ assertEquals(7, date2.getMonthOfYear());
+ assertEquals(13, date2.getDayOfMonth());
+
+ // since 1.6.1, for [JACKSON-360]
+ assertNull(MAPPER.readValue(quote(""), LocalDate.class));
+ }
+
+ public void testLocalDateDeserWithTypeInfo() throws IOException
+ {
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(LocalDate.class, ObjectConfiguration.class);
+
+ // couple of acceptable formats, so:
+ LocalDate date = mapper.readValue("[\"org.joda.time.LocalDate\",[2001,5,25]]", LocalDate.class);
+ assertEquals(2001, date.getYear());
+ assertEquals(5, date.getMonthOfYear());
+ assertEquals(25, date.getDayOfMonth());
+
+ LocalDate date2 = mapper.readValue("[\"org.joda.time.LocalDate\",\"2005-07-13\"]", LocalDate.class);
+ assertEquals(2005, date2.getYear());
+ assertEquals(7, date2.getMonthOfYear());
+ assertEquals(13, date2.getDayOfMonth());
+ }
+
+ /*
+ /**********************************************************
+ /* Tests for LocalTime type
+ /**********************************************************
+ */
+
+ public void testLocalTimeDeser() throws IOException
+ {
+ // couple of acceptable formats, so:
+ LocalTime time = MAPPER.readValue("[23,59,1,222]", LocalTime.class);
+ assertEquals(23, time.getHourOfDay());
+ assertEquals(59, time.getMinuteOfHour());
+ assertEquals(1, time.getSecondOfMinute());
+ assertEquals(222, time.getMillisOfSecond());
+
+ LocalTime time2 = MAPPER.readValue(quote("13:45:22"), LocalTime.class);
+ assertEquals(13, time2.getHourOfDay());
+ assertEquals(45, time2.getMinuteOfHour());
+ assertEquals(22, time2.getSecondOfMinute());
+ assertEquals(0, time2.getMillisOfSecond());
+
+ // since 1.6.1, for [JACKSON-360]
+ assertNull(MAPPER.readValue(quote(""), LocalTime.class));
+ }
+
+ public void testLocalTimeDeserWithTypeInfo() throws IOException
+ {
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(LocalTime.class, ObjectConfiguration.class);
+
+ // couple of acceptable formats, so:
+ LocalTime time = mapper.readValue("[\"org.joda.time.LocalTime\",[23,59,1,10]]", LocalTime.class);
+ assertEquals(23, time.getHourOfDay());
+ assertEquals(59, time.getMinuteOfHour());
+ assertEquals(1, time.getSecondOfMinute());
+ assertEquals(10, time.getMillisOfSecond());
+
+ LocalTime time2 = mapper.readValue("[\"org.joda.time.LocalTime\",\"13:45:22\"]", LocalTime.class);
+ assertEquals(13, time2.getHourOfDay());
+ assertEquals(45, time2.getMinuteOfHour());
+ assertEquals(22, time2.getSecondOfMinute());
+ assertEquals(0, time2.getMillisOfSecond());
+ }
+
+ /*
+ /**********************************************************
+ /* Tests for Interval type
+ /**********************************************************
+ */
+ public void testIntervalDeser() throws IOException
+ {
+ Interval interval = MAPPER.readValue(quote("1396439982-1396440001"), Interval.class);
+ assertEquals(1396439982, interval.getStartMillis());
+ assertEquals(1396440001, interval.getEndMillis());
+
+ interval = MAPPER.readValue(quote("-100-1396440001"), Interval.class);
+ assertEquals(-100, interval.getStartMillis());
+ assertEquals(1396440001, interval.getEndMillis());
+ }
+
+ public void testIntervalDeserWithTypeInfo() throws IOException
+ {
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(Interval.class, ObjectConfiguration.class);
+
+ Interval interval= mapper.readValue("[\"org.joda.time.Interval\",\"1396439982-1396440001\"]", Interval.class);
+ assertEquals(1396439982, interval.getStartMillis());
+ assertEquals(1396440001, interval.getEndMillis());
+ }
+
+ /*
+ /**********************************************************
+ /* Tests for LocalDateTime type
+ /**********************************************************
+ */
+
+ public void testLocalDateTimeDeser() throws IOException
+ {
+ // couple of acceptable formats again:
+ LocalDateTime date = MAPPER.readValue("[2001,5,25,10,15,30,37]", LocalDateTime.class);
+ assertEquals(2001, date.getYear());
+ assertEquals(5, date.getMonthOfYear());
+ assertEquals(25, date.getDayOfMonth());
+
+ assertEquals(10, date.getHourOfDay());
+ assertEquals(15, date.getMinuteOfHour());
+ assertEquals(30, date.getSecondOfMinute());
+ assertEquals(37, date.getMillisOfSecond());
+
+ LocalDateTime date2 = MAPPER.readValue(quote("2007-06-30T08:34:09.001"), LocalDateTime.class);
+ assertEquals(2007, date2.getYear());
+ assertEquals(6, date2.getMonthOfYear());
+ assertEquals(30, date2.getDayOfMonth());
+
+ assertEquals(8, date2.getHourOfDay());
+ assertEquals(34, date2.getMinuteOfHour());
+ assertEquals(9, date2.getSecondOfMinute());
+ assertEquals(1, date2.getMillisOfSecond());
+
+ // since 1.6.1, for [JACKSON-360]
+ assertNull(MAPPER.readValue(quote(""), LocalDateTime.class));
+ }
+
+ public void testLocalDateTimeDeserWithTypeInfo() throws IOException
+ {
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(LocalDateTime.class, ObjectConfiguration.class);
+
+ // couple of acceptable formats again:
+ LocalDateTime date = mapper.readValue("[\"org.joda.time.LocalDateTime\",[2001,5,25,10,15,30,37]]", LocalDateTime.class);
+ assertEquals(2001, date.getYear());
+ assertEquals(5, date.getMonthOfYear());
+ assertEquals(25, date.getDayOfMonth());
+
+ assertEquals(10, date.getHourOfDay());
+ assertEquals(15, date.getMinuteOfHour());
+ assertEquals(30, date.getSecondOfMinute());
+ assertEquals(37, date.getMillisOfSecond());
+
+ LocalDateTime date2 = mapper.readValue("[\"org.joda.time.LocalDateTime\",\"2007-06-30T08:34:09.001\"]", LocalDateTime.class);
+ assertEquals(2007, date2.getYear());
+ assertEquals(6, date2.getMonthOfYear());
+ assertEquals(30, date2.getDayOfMonth());
+
+ assertEquals(8, date2.getHourOfDay());
+ assertEquals(34, date2.getMinuteOfHour());
+ assertEquals(9, date2.getSecondOfMinute());
+ assertEquals(1, date2.getMillisOfSecond());
+ }
+
+ /*
+ /**********************************************************
+ /* Tests for Period type
+ /**********************************************************
+ */
+
+ public void testPeriodDeser() throws IOException
+ {
+ Period out = MAPPER.readValue(quote("PT1H2M3.004S"), Period.class);
+ assertEquals(1, out.getHours());
+ assertEquals(2, out.getMinutes());
+ assertEquals(3, out.getSeconds());
+ assertEquals(4, out.getMillis());
+
+ // also, should work as number:
+ String json = String.valueOf(1000 * out.toStandardSeconds().getSeconds());
+ out = MAPPER.readValue(json, Period.class);
+ assertEquals(1, out.getHours());
+ assertEquals(2, out.getMinutes());
+ assertEquals(3, out.getSeconds());
+ // but millis are actually truncated...
+ assertEquals(0, out.getMillis());
+ }
+
+ public void testPeriodDeserWithTypeInfo() throws IOException
+ {
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(Period.class, ObjectConfiguration.class);
+
+ Period out = mapper.readValue("[\"org.joda.time.Period\",\"PT1H2M3.004S\"]", Period.class);
+ assertEquals(1, out.getHours());
+ assertEquals(2, out.getMinutes());
+ assertEquals(3, out.getSeconds());
+ assertEquals(4, out.getMillis());
+
+ // also, should work as number:
+ String json = "[\"org.joda.time.Period\"," + String.valueOf(1000 * out.toStandardSeconds().getSeconds()) + "]";
+ out = mapper.readValue(json, Period.class);
+ assertEquals(1, out.getHours());
+ assertEquals(2, out.getMinutes());
+ assertEquals(3, out.getSeconds());
+ // but millis are actually truncated...
+ assertEquals(0, out.getMillis());
+ }
+
+ /*
+ /**********************************************************
+ /* Tests for Duration type
+ /**********************************************************
+ */
+
+ public void testDurationDeserFromInt() throws IOException
+ {
+ Duration d = MAPPER.readValue("1234", Duration.class);
+ assertEquals(1234, d.getMillis());
+ }
+
+ public void testDurationDeserFromString() throws IOException
+ {
+ Duration d = MAPPER.readValue(quote("PT1.234S"), Duration.class);
+ assertEquals(1234, d.getMillis());
+ }
+
+ public void testDurationRoundtrip() throws IOException
+ {
+ Duration d = new Duration(5513);
+ assertEquals(d, MAPPER.readValue(MAPPER.writeValueAsString(d), Duration.class));
+ }
+
+ public void testDurationFailsDeserializingUnexpectedType() throws IOException
+ {
+ try {
+ MAPPER.readValue("{\"foo\":1234}", Duration.class);
+ fail();
+ } catch (JsonMappingException e) {
+ // there's location info involving a string object id on the second line, so just use the first line
+ assertEquals("expected JSON Number or String", e.getMessage().split("\n")[0]);
+ }
+ }
+
+ public void testDurationDeserFromIntWithTypeInfo() throws IOException
+ {
+ ObjectMapper mapper = jodaMapper();
+ mapper.addMixInAnnotations(Duration.class, ObjectConfiguration.class);
+
+ Duration d = mapper.readValue("[\"org.joda.time.Duration\",1234]", Duration.class);
+ assertEquals(1234, d.getMillis());
+ }
+
+ @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_ARRAY, property = "@class")
+ private static interface ObjectConfiguration {
+ }
+
+
+
+ public void testDeserInstantFromNumber() throws IOException
+ {
+ Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+ cal.set(Calendar.YEAR, 1972);
+ long timepoint = cal.getTime().getTime();
+
+ // Ok, first: using JSON number (milliseconds since epoch)
+ Instant instant = MAPPER.readValue(String.valueOf(timepoint), Instant.class);
+ assertEquals(timepoint, instant.getMillis());
+ }
+
+ public void testDeserInstant() throws IOException
+ {
+ Instant date = MAPPER.readValue(quote("1972-12-28T12:00:01.000Z"), Instant.class);
+ assertNotNull(date);
+ assertEquals("1972-12-28T12:00:01.000Z", date.toString());
+
+ // since 1.6.1, for [JACKSON-360]
+ assertNull(MAPPER.readValue(quote(""), Instant.class));
+ }
+
+ public void testDateTimeKeyDeserialize() throws IOException {
+
+ final String json = "{" + quote("1970-01-01T00:00:00.000Z") + ":0}";
+ final Map<DateTime, Long> map = MAPPER.readValue(json, new TypeReference<Map<DateTime, String>>() { });
+
+ assertNotNull(map);
+ assertTrue(map.containsKey(DateTime.parse("1970-01-01T00:00:00.000Z")));
+ }
+
+ public void testLocalDateKeyDeserialize() throws IOException {
+
+ final String json = "{" + quote("2014-05-23") + ":0}";
+ final Map<LocalDate, Long> map = MAPPER.readValue(json, new TypeReference<Map<LocalDate, String>>() { });
+
+ assertNotNull(map);
+ assertTrue(map.containsKey(LocalDate.parse("2014-05-23")));
+ }
+
+ public void testLocalTimeKeyDeserialize() throws IOException {
+
+ final String json = "{" + quote("00:00:00.000") + ":0}";
+ final Map<LocalTime, Long> map = MAPPER.readValue(json, new TypeReference<Map<LocalTime, String>>() { });
+ assertNotNull(map);
+ assertTrue(map.containsKey(LocalTime.parse("00:00:00.000")));
+ }
+ public void testLocalDateTimeKeyDeserialize() throws IOException {
+
+ final String json = "{" + quote("2014-05-23T00:00:00.000") + ":0}";
+ final Map<LocalDateTime, Long> map = MAPPER.readValue(json, new TypeReference<Map<LocalDateTime, String>>() { });
+ assertNotNull(map);
+ assertTrue(map.containsKey(LocalDateTime.parse("2014-05-23T00:00:00.000")));
+ }
+
+ public void testDeserMonthDay() throws Exception
+ {
+ String monthDayString = new MonthDay(7, 23).toString();
+ MonthDay monthDay = MAPPER.readValue(quote(monthDayString), MonthDay.class);
+ assertEquals(new MonthDay(7, 23), monthDay);
+ }
+
+ public void testDeserMonthDayFromEmptyString() throws Exception
+ {
+ MonthDay monthDay = MAPPER.readValue(quote(""), MonthDay.class);
+ assertNull(monthDay);
+ }
+
+ public void testDeserMonthDayFailsForUnexpectedType() throws IOException
+ {
+ try
+ {
+ MAPPER.readValue("{\"month\":8}", MonthDay.class);
+ fail();
+ } catch (JsonMappingException e)
+ {
+ assertTrue(e.getMessage().contains("expected JSON String"));
+ }
+ }
+
+ public void testDeserYearMonth() throws Exception
+ {
+ String yearMonthString = new YearMonth(2013, 8).toString();
+ YearMonth yearMonth = MAPPER.readValue(quote(yearMonthString), YearMonth.class);
+ assertEquals(new YearMonth(2013, 8), yearMonth);
+ }
+
+ public void testDeserYearMonthFromEmptyString() throws Exception
+ {
+ YearMonth yearMonth = MAPPER.readValue(quote(""), YearMonth.class);
+ assertNull(yearMonth);
+ }
+
+ public void testDeserYearMonthFailsForUnexpectedType() throws IOException
+ {
+ try
+ {
+ MAPPER.readValue("{\"year\":2013}", YearMonth.class);
+ fail();
+ } catch (JsonMappingException e)
+ {
+ assertTrue(e.getMessage().contains("expected JSON String"));
+ }
+ }
+
+}
diff --git a/src/test/java/com/fasterxml/jackson/datatype/joda/deser/ReadablePeriodDeserializerTest.java b/src/test/java/com/fasterxml/jackson/datatype/joda/deser/ReadablePeriodDeserializerTest.java
new file mode 100644
index 0000000..f3e4daf
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/datatype/joda/deser/ReadablePeriodDeserializerTest.java
@@ -0,0 +1,73 @@
+package com.fasterxml.jackson.datatype.joda.deser;
+
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.joda.JodaTestBase;
+import org.joda.time.Days;
+import org.joda.time.Hours;
+import org.joda.time.Minutes;
+import org.joda.time.Months;
+import org.joda.time.ReadablePeriod;
+import org.joda.time.Seconds;
+import org.joda.time.Weeks;
+import org.joda.time.Years;
+
+public class ReadablePeriodDeserializerTest extends JodaTestBase
+{
+
+ public void testDeserializeSeconds() throws Exception
+ {
+ ObjectMapper objectMapper = jodaMapper();
+ ReadablePeriod readablePeriod = objectMapper.readValue( "{\"fieldType\":{\"name\":\"seconds\"},\"seconds\":12,\"periodType\":{\"name\":\"Seconds\"}}", ReadablePeriod.class );
+ assertNotNull( readablePeriod );
+ assertEquals( Seconds.seconds( 12 ), readablePeriod );
+ }
+
+ public void testDeserializeMinutes() throws Exception
+ {
+ ObjectMapper objectMapper = jodaMapper();
+ ReadablePeriod readablePeriod = objectMapper.readValue( "{\"fieldType\":{\"name\":\"minutes\"},\"minutes\":1,\"periodType\":{\"name\":\"Minutes\"}}", ReadablePeriod.class );
+ assertNotNull( readablePeriod );
+ assertEquals( Minutes.minutes( 1 ), readablePeriod );
+ }
+
+ public void testDeserializeHours() throws Exception
+ {
+ ObjectMapper objectMapper = jodaMapper();
+ ReadablePeriod readablePeriod = objectMapper.readValue( "{\"fieldType\":{\"name\":\"hours\"},\"hours\":2,\"periodType\":{\"name\":\"Hours\"}}", ReadablePeriod.class );
+ assertNotNull( readablePeriod );
+ assertEquals( Hours.hours( 2 ), readablePeriod );
+ }
+
+ public void testDeserializeDays() throws Exception
+ {
+ ObjectMapper objectMapper = jodaMapper();
+ ReadablePeriod readablePeriod = objectMapper.readValue( "{\"fieldType\":{\"name\":\"days\"},\"days\":2,\"periodType\":{\"name\":\"Days\"}}", ReadablePeriod.class );
+ assertNotNull( readablePeriod );
+ assertEquals( Days.days( 2 ), readablePeriod );
+ }
+
+ public void testDeserializeWeeks() throws Exception
+ {
+ ObjectMapper objectMapper = jodaMapper();
+ ReadablePeriod readablePeriod = objectMapper.readValue( "{\"fieldType\":{\"name\":\"weeks\"},\"weeks\":2,\"periodType\":{\"name\":\"Weeks\"}}", ReadablePeriod.class );
+ assertNotNull( readablePeriod );
+ assertEquals( Weeks.weeks( 2 ), readablePeriod );
+ }
+
+ public void testDeserializeMonths() throws Exception
+ {
+ ObjectMapper objectMapper = jodaMapper();
+ ReadablePeriod readablePeriod = objectMapper.readValue( "{\"fieldType\":{\"name\":\"months\"},\"months\":2,\"periodType\":{\"name\":\"Months\"}}", ReadablePeriod.class );
+ assertNotNull( readablePeriod );
+ assertEquals( Months.months( 2 ), readablePeriod );
+ }
+
+ public void testDeserializeYears() throws Exception
+ {
+ ObjectMapper objectMapper = jodaMapper();
+ ReadablePeriod readablePeriod = objectMapper.readValue( "{\"fieldType\":{\"name\":\"years\"},\"years\":2,\"periodType\":{\"name\":\"Years\"}}", ReadablePeriod.class );
+ assertNotNull( readablePeriod );
+ assertEquals( Years.years( 2 ), readablePeriod );
+ }
+}
\ No newline at end of file
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/jackson-datatype-joda.git
More information about the pkg-java-commits
mailing list