Skip to content

Commit

Permalink
Start work on #101; add custom format support for Instant ser, deser
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Sep 12, 2018
1 parent a58960d commit 47289ea
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,30 @@
import com.fasterxml.jackson.core.*;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.joda.cfg.FormatConfig;
import com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat;

/**
* 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>
extends JodaDateDeserializerBase<Instant>
{
private static final long serialVersionUID = 1L;

public InstantDeserializer() {
super(Instant.class);
this(FormatConfig.DEFAULT_DATETIME_PARSER);
}

public InstantDeserializer(JacksonJodaDateFormat format) {
super(Instant.class, format);
}

@Override
public JodaDateDeserializerBase<?> withFormat(JacksonJodaDateFormat format) {
return new InstantDeserializer(format);
}

@Override
Expand All @@ -34,7 +45,9 @@ public Instant deserialize(JsonParser p, DeserializationContext ctxt) throws IOE
if (str.length() == 0) {
return null;
}
return new Instant(str);
// 11-Sep-2018, tatu: `DateTimeDeserializer` allows timezone inclusion in brackets;
// should that be checked here too?
return Instant.parse(str, _format.createParser(ctxt));
}
return _handleNotNumberOrString(p, ctxt);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ public class InstantSerializer // non final since 2.6.1
{
private static final long serialVersionUID = 1L;

// NOTE: formatter not used for printing at all, hence choice doesn't matter
public InstantSerializer() { this(FormatConfig.DEFAULT_TIMEONLY_FORMAT, 0); }
public InstantSerializer() { this(FormatConfig.DEFAULT_DATETIME_PRINTER, 0); }
public InstantSerializer(JacksonJodaDateFormat format) {
this(format, 0);
}

public InstantSerializer(JacksonJodaDateFormat format,
int shapeOverride) {
super(Instant.class, format, SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
Expand All @@ -43,7 +43,7 @@ public void serialize(Instant value, JsonGenerator gen, SerializerProvider provi
throws IOException
{
if (_serializationShape(provider) == FORMAT_STRING) {
gen.writeString(value.toString());
gen.writeString(_format.createFormatter(provider).print(value));
} else {
gen.writeNumber(value.getMillis());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
package com.fasterxml.jackson.datatype.joda;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import junit.framework.TestCase;

import java.io.IOException;
import java.util.Arrays;

import org.joda.time.Instant;

import static org.junit.Assert.*;

public abstract class JodaTestBase extends TestCase
{
protected static ObjectMapper jodaMapper()
{
protected static class FormattedInstant {
@JsonFormat(pattern = "dd/MM/yyyy HH_mm_ss_SSS")
public Instant value;

public FormattedInstant(Instant v) { value = v; }
protected FormattedInstant() { }
}

// Mix-in class for forcing polymorphic handling
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_ARRAY)
protected static interface MixinForPolymorphism {
}

/*
/**********************************************************
/* Factory methods
/**********************************************************
*/

protected static ObjectMapper jodaMapper() {
return new JodaMapper();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.fasterxml.jackson.datatype.joda;
package com.fasterxml.jackson.datatype.joda.depr;

import java.io.IOException;
import java.util.TimeZone;
Expand All @@ -8,7 +8,9 @@
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.joda.JodaTestBase;

@SuppressWarnings("deprecation") // because DateMidnight deprecated by Joda
public class DateMidnightTest extends JodaTestBase
Expand Down Expand Up @@ -48,7 +50,7 @@ public FormattedDateAsTimestamp(DateMidnight d) {

/*
/**********************************************************
/* Test methods
/* Test methods, deserialization
/**********************************************************
*/

Expand Down Expand Up @@ -119,7 +121,48 @@ public void testDateMidnightDeserWithTypeInfo() throws IOException
assertEquals(13, date2.getDayOfMonth());
}

public void testCustomFormat() throws Exception
/*
/**********************************************************
/* Test methods, serialization
/**********************************************************
*/

public void testSerializeAsTimestamp() throws Exception
{
assertEquals(aposToQuotes("{'value':0}"),
MAPPER.writeValueAsString(new FormattedDateAsTimestamp(
new DateMidnight(0, DateTimeZone.UTC))));
}

public void testDateMidnightSer() throws IOException
{
ObjectMapper mapper = jodaMapper()
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.enable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS);
final ObjectWriter writer = mapper.writer();

DateMidnight date = new DateMidnight(2001, 5, 25);
// default format is that of JSON array...
assertEquals("[2001,5,25]", writer.writeValueAsString(date));
// but we can force it to be a String as well (note: here we assume this is
// dynamically changeable)
assertEquals(quote("2001-05-25"),
writer.without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.writeValueAsString(date));

mapper = jodaMapper();
mapper.addMixIn(DateMidnight.class, MixInForTypeId.class);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
assertEquals("[\"org.joda.time.DateMidnight\",\"2001-05-25\"]", mapper.writeValueAsString(date));
}

/*
/**********************************************************
/* Test methods, custom format
/**********************************************************
*/

public void testDeserWithCustomFormat() throws Exception
{
String STR = "2015-06-19";
String ALT = "19.06.2015";
Expand Down Expand Up @@ -159,10 +202,4 @@ public void testWithTimeZoneOverride() throws Exception
assertEquals("America/New_York", resultTz.getID());
}

public void testSerializeAsTimestamp() throws Exception
{
assertEquals(aposToQuotes("{'value':0}"),
MAPPER.writeValueAsString(new FormattedDateAsTimestamp(
new DateMidnight(0, DateTimeZone.UTC))));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,11 @@
import org.joda.time.Instant;
import org.joda.time.ReadableInstant;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.joda.JodaTestBase;

public class InstantDeserTest extends JodaTestBase
{
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_ARRAY)
private static interface ObjectConfiguration {
}

/*
/**********************************************************
/* Test methods
Expand All @@ -35,11 +30,12 @@ public void testDeserReadableInstant() throws IOException {
assertNull(MAPPER.readValue(quote(""), ReadableInstant.class));
}

public void testDeserDateTimeWithTypeInfo() throws IOException
public void testDeserInstantWithTypeInfo() throws IOException
{
ObjectMapper mapper = jodaMapper();
mapper.addMixIn(DateTime.class, ObjectConfiguration.class);
DateTime date = mapper.readValue("[\"org.joda.time.DateTime\",\"1972-12-28T12:00:01.000+0000\"]", DateTime.class);
mapper.addMixIn(Instant.class, MixinForPolymorphism.class);
Instant date = mapper.readValue("[\"org.joda.time.Instant\",\"1972-12-28T12:00:01.000+0000\"]",
Instant.class);
assertNotNull(date);
assertEquals("1972-12-28T12:00:01.000Z", date.toString());
}
Expand All @@ -61,7 +57,16 @@ public void testDeserInstant() throws IOException
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 testDeserInstantCustomFormat() throws IOException
{
FormattedInstant input = MAPPER.readValue(aposToQuotes(
"{'value':'28/12/1972 12_34_56_789'}"),
FormattedInstant.class);
DateTime date = input.value.toDateTime();
assertEquals(1972, date.getYear());
assertEquals(789, date.getMillisOfSecond());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ private static interface ObjectConfiguration {

private final ObjectMapper MAPPER = jodaMapper();

/*
/**********************************************************
/* Test methods
/**********************************************************
*/

/*
/**********************************************************
/* Tests for Interval type
Expand All @@ -46,20 +40,19 @@ public void testIntervalDeser() throws IOException

public void testIntervalDeserWithTimeZone() throws IOException
{
MAPPER.setTimeZone(TimeZone.getTimeZone("Europe/Paris"));
MAPPER.setTimeZone(TimeZone.getTimeZone("Europe/Paris"));

Interval interval = MAPPER.readValue(quote("1396439982-1396440001"), Interval.class);
assertEquals(1396439982, interval.getStartMillis());
assertEquals(1396440001, interval.getEndMillis());
assertEquals(ISOChronology.getInstance(DateTimeZone.forID("Europe/Paris")), interval.getChronology());

MAPPER.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
MAPPER.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));

interval = MAPPER.readValue(quote("-100-1396440001"), Interval.class);
assertEquals(-100, interval.getStartMillis());
assertEquals(1396440001, interval.getEndMillis());
assertEquals(ISOChronology.getInstance(DateTimeZone.forID("America/Los_Angeles")), interval.getChronology());

}

public void testIntervalDeserWithTypeInfo() throws IOException
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ public class LocalTimeDeserTest extends JodaTestBase
private static interface ObjectConfiguration {
}

/*
/**********************************************************
/* Test methods
/**********************************************************
*/

private final ObjectMapper MAPPER = jodaMapper();

/*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.fasterxml.jackson.datatype.joda.ser;

import java.text.SimpleDateFormat;

import org.joda.time.DateTime;
import org.joda.time.Instant;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.joda.JodaTestBase;

public class InstantSerializationTest extends JodaTestBase
{
private final ObjectMapper MAPPER = jodaMapper();
{
MAPPER.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
MAPPER.enable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS);
}

public void testInstantSer() throws Exception {
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
assertEquals(quote("1970-01-01T00:00:00.000Z"), MAPPER.writer()
.without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.writeValueAsString(instant));
}

public void testCustomFormatInstantSer() throws Exception
{
final String json = MAPPER.writer()
.without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.writeValueAsString(new FormattedInstant(new Instant(0L)));
assertEquals(aposToQuotes(
"{'value':'01/01/1970 00_00_00_000'}"), json);
}

// [datatype-joda#60]
public void testInstantConversion() throws Exception
{
final ObjectMapper mapper = jodaMapper();

// Configure Date Formatting
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"));

// Create an instant and serialize and additionally serialize the instant as DateTime to demonstrate the difference
org.joda.time.Instant now = new DateTime(1431498572205L).toInstant();

String instantString = mapper.writeValueAsString(now);

assertEquals("\"2015-05-13T06:29:32.205Z\"", instantString);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.fasterxml.jackson.datatype.joda;
package com.fasterxml.jackson.datatype.joda.ser;

import java.io.IOException;

Expand All @@ -8,6 +8,7 @@
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.joda.JodaTestBase;

public class IntervalSerializationTest extends JodaTestBase
{
Expand Down
Loading

0 comments on commit 47289ea

Please sign in to comment.