Skip to content

Commit

Permalink
Fix #1762 (for 3.0)
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Sep 13, 2017
1 parent d402a0f commit 91a3636
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 149 deletions.
2 changes: 1 addition & 1 deletion release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ Versions: 3.x (for earlier see VERSION-2.x)

3.0.0 (not yet released)


#1762: `StdDateFormat`: serialize time offset using colon
87 changes: 56 additions & 31 deletions src/main/java/com/fasterxml/jackson/databind/ext/Java7Support.java
Original file line number Diff line number Diff line change
@@ -1,49 +1,74 @@
package com.fasterxml.jackson.databind.ext;

import java.beans.ConstructorProperties;
import java.beans.Transient;
import java.nio.file.Path;

import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.PropertyName;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.AnnotatedParameter;
import com.fasterxml.jackson.databind.util.ClassUtil;
import com.fasterxml.jackson.databind.introspect.AnnotatedWithParams;

/**
* To support Java7-incomplete platforms, we will offer support for JDK 7
* annotations through this class, loaded dynamically; if loading fails,
* support will be missing. This class is the non-JDK-7-dependent API,
* and {@link Java7SupportImpl} is JDK7-dependent implementation of
* functionality.
* Due to historical reasons, Java 7 type support has been separate.
*/
public abstract class Java7Support
public class Java7Support
{
private final static Java7Support IMPL;

static {
Java7Support impl = null;
try {
Class<?> cls = Class.forName("com.fasterxml.jackson.databind.ext.Java7SupportImpl");
impl = (Java7Support) ClassUtil.createInstance(cls, false);
} catch (Throwable t) {
// 24-Nov-2015, tatu: Should we log or not?
java.util.logging.Logger.getLogger(Java7Support.class.getName())
.warning("Unable to load JDK7 types (annotations, java.nio.file.Path): no Java7 support added");
}
IMPL = impl;
}

public static Java7Support instance() {
return IMPL;
return new Java7Support();
}

public abstract Boolean findTransient(Annotated a);

public abstract Boolean hasCreatorAnnotation(Annotated a);
public Class<?> getClassJavaNioFilePath() {
return Path.class;
}

public abstract PropertyName findConstructorName(AnnotatedParameter p);
public JsonDeserializer<?> getDeserializerForJavaNioFilePath(Class<?> rawType) {
if (rawType == Path.class) {
return new NioPathDeserializer();
}
return null;
}

public abstract Class<?> getClassJavaNioFilePath();
public JsonSerializer<?> getSerializerForJavaNioFilePath(Class<?> rawType) {
if (Path.class.isAssignableFrom(rawType)) {
return new NioPathSerializer();
}
return null;
}

public abstract JsonDeserializer<?> getDeserializerForJavaNioFilePath(Class<?> rawType);
public Boolean findTransient(Annotated a) {
Transient t = a.getAnnotation(Transient.class);
if (t != null) {
return t.value();
}
return null;
}

public Boolean hasCreatorAnnotation(Annotated a) {
ConstructorProperties props = a.getAnnotation(ConstructorProperties.class);
// 08-Nov-2015, tatu: One possible check would be to ensure there is at least
// one name iff constructor has arguments. But seems unnecessary for now.
if (props != null) {
return Boolean.TRUE;
}
return null;
}

public abstract JsonSerializer<?> getSerializerForJavaNioFilePath(Class<?> rawType);
}
public PropertyName findConstructorName(AnnotatedParameter p)
{
AnnotatedWithParams ctor = p.getOwner();
if (ctor != null) {
ConstructorProperties props = ctor.getAnnotation(ConstructorProperties.class);
if (props != null) {
String[] names = props.value();
int ix = p.getIndex();
if (ix < names.length) {
return PropertyName.construct(names[ix]);
}
}
}
return null;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,6 @@ public class StdDateFormat
*<p>
* Cannot be `final` because {@link #setLenient(boolean)} returns
* `void`.
*
* @since 2.7
*/
protected Boolean _lenient;

Expand All @@ -145,10 +143,10 @@ public class StdDateFormat

/**
* Whether the TZ offset must be formatted with a colon between hours and minutes ({@code HH:mm} format)
*
* @since 2.9.1
*<p>
* NOTE: default changed to `true` in Jackson 3.0; was `false` earlier.
*/
private boolean _tzSerializedWithColon = false;
protected boolean _tzSerializedWithColon = true;

/*
/**********************************************************
Expand Down Expand Up @@ -428,12 +426,11 @@ protected void _format(TimeZone tz, Locale loc, Date date,
// 24-Jun-2017, tatu: While `Z` would be conveniently short, older specs
// mandate use of full `+0000`
// formatted.append('Z');
if( _tzSerializedWithColon ) {
buffer.append("+00:00");
}
else {
buffer.append("+0000");
}
if (_tzSerializedWithColon ) {
buffer.append("+00:00");
} else {
buffer.append("+0000");
}
}
}

Expand Down Expand Up @@ -496,12 +493,12 @@ public String toPattern() { // same as SimpleDateFormat
return sb.toString();
}

@Override // since 2.7[.2], as per [databind#1130]
@Override
public boolean equals(Object o) {
return (o == this);
}

@Override // since 2.7[.2], as per [databind#1130]
@Override
public int hashCode() {
return System.identityHashCode(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ private String removeZ(String dateStr) {
if (dateStr.endsWith("Z")) {
return dateStr.substring(0, dateStr.length()-1);
}
if (dateStr.endsWith("+0000")) {
return dateStr.substring(0, dateStr.length()-5);
if (dateStr.endsWith("+00:00")) {
return dateStr.substring(0, dateStr.length()-6);
}
return dateStr;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ public void testDateISO8601() throws IOException
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

serialize( mapper, judate(1970, 1, 1, 02, 00, 00, 0, "GMT+2"), "1970-01-01T00:00:00.000+0000");
serialize( mapper, judate(1970, 1, 1, 00, 00, 00, 0, "UTC"), "1970-01-01T00:00:00.000+0000");
serialize( mapper, judate(1970, 1, 1, 02, 00, 00, 0, "GMT+2"), "1970-01-01T00:00:00.000+00:00");
serialize( mapper, judate(1970, 1, 1, 00, 00, 00, 0, "UTC"), "1970-01-01T00:00:00.000+00:00");
}

/**
Expand All @@ -130,8 +130,8 @@ public void testDateISO8601_customTZ() throws IOException
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.setTimeZone(TimeZone.getTimeZone("GMT+2"));

serialize( mapper, judate(1970, 1, 1, 00, 00, 00, 0, "GMT+2"), "1970-01-01T00:00:00.000+0200");
serialize( mapper, judate(1970, 1, 1, 00, 00, 00, 0, "UTC"), "1970-01-01T02:00:00.000+0200");
serialize( mapper, judate(1970, 1, 1, 00, 00, 00, 0, "GMT+2"), "1970-01-01T00:00:00.000+02:00");
serialize( mapper, judate(1970, 1, 1, 00, 00, 00, 0, "UTC"), "1970-01-01T02:00:00.000+02:00");
}

/**
Expand All @@ -142,16 +142,16 @@ public void testDateISO8601_customTZ() throws IOException
public void testDateISO8601_colonInTZ() throws IOException
{
StdDateFormat dateFormat = new StdDateFormat();
assertFalse(dateFormat.isColonIncludedInTimeZone());
dateFormat = dateFormat.withColonInTimeZone(true);
assertTrue(dateFormat.isColonIncludedInTimeZone());
dateFormat = dateFormat.withColonInTimeZone(false);
assertFalse(dateFormat.isColonIncludedInTimeZone());

ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.setDateFormat(dateFormat);

serialize( mapper, judate(1970, 1, 1, 02, 00, 00, 0, "GMT+2"), "1970-01-01T00:00:00.000+00:00");
serialize( mapper, judate(1970, 1, 1, 00, 00, 00, 0, "UTC"), "1970-01-01T00:00:00.000+00:00");
serialize( mapper, judate(1970, 1, 1, 02, 00, 00, 0, "GMT+2"), "1970-01-01T00:00:00.000+0000");
serialize( mapper, judate(1970, 1, 1, 00, 00, 00, 0, "UTC"), "1970-01-01T00:00:00.000+0000");
}

public void testDateOther() throws IOException
Expand Down Expand Up @@ -202,7 +202,7 @@ public void testDatesAsMapKeys() throws IOException
assertFalse(mapper.isEnabled(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS));
map.put(new Date(0L), Integer.valueOf(1));
// by default will serialize as ISO-8601 values...
assertEquals("{\"1970-01-01T00:00:00.000+0000\":1}", mapper.writeValueAsString(map));
assertEquals("{\"1970-01-01T00:00:00.000+00:00\":1}", mapper.writeValueAsString(map));

// but can change to use timestamps too
mapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, true);
Expand Down Expand Up @@ -234,7 +234,7 @@ public void testDateWithJsonFormat() throws Exception

// and with default (ISO8601) format (databind#1109)
json = mapper.writeValueAsString(new DateAsDefaultStringBean(0L));
assertEquals("{\"date\":\"1970-01-01T00:00:00.000+0000\"}", json);
assertEquals("{\"date\":\"1970-01-01T00:00:00.000+00:00\"}", json);
}

/**
Expand Down Expand Up @@ -275,15 +275,15 @@ public void testDateDefaultShape() throws Exception
assertEquals(aposToQuotes("{'date':0}"), json);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
json = mapper.writeValueAsString(new DateAsDefaultBean(0L));
assertEquals(aposToQuotes("{'date':'1970-01-01T00:00:00.000+0000'}"), json);
assertEquals(aposToQuotes("{'date':'1970-01-01T00:00:00.000+00:00'}"), json);

// Empty @JsonFormat => default to user config
mapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
json = mapper.writeValueAsString(new DateAsDefaultBeanWithEmptyJsonFormat(0L));
assertEquals(aposToQuotes("{'date':0}"), json);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
json = mapper.writeValueAsString(new DateAsDefaultBeanWithEmptyJsonFormat(0L));
assertEquals(aposToQuotes("{'date':'1970-01-01T00:00:00.000+0000'}"), json);
assertEquals(aposToQuotes("{'date':'1970-01-01T00:00:00.000+00:00'}"), json);

// @JsonFormat with Shape.ANY and pattern => STRING shape, regardless of user config
mapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
Expand All @@ -296,18 +296,18 @@ public void testDateDefaultShape() throws Exception
// @JsonFormat with Shape.ANY and locale => STRING shape, regardless of user config
mapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
json = mapper.writeValueAsString(new DateAsDefaultBeanWithLocale(0L));
assertEquals(aposToQuotes("{'date':'1970-01-01T00:00:00.000+0000'}"), json);
assertEquals(aposToQuotes("{'date':'1970-01-01T00:00:00.000+00:00'}"), json);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
json = mapper.writeValueAsString(new DateAsDefaultBeanWithLocale(0L));
assertEquals(aposToQuotes("{'date':'1970-01-01T00:00:00.000+0000'}"), json);
assertEquals(aposToQuotes("{'date':'1970-01-01T00:00:00.000+00:00'}"), json);

// @JsonFormat with Shape.ANY and timezone => STRING shape, regardless of user config
mapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
json = mapper.writeValueAsString(new DateAsDefaultBeanWithTimezone(0L));
assertEquals(aposToQuotes("{'date':'1970-01-01T01:00:00.000+0100'}"), json);
assertEquals(aposToQuotes("{'date':'1970-01-01T01:00:00.000+01:00'}"), json);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
json = mapper.writeValueAsString(new DateAsDefaultBeanWithTimezone(0L));
assertEquals(aposToQuotes("{'date':'1970-01-01T01:00:00.000+0100'}"), json);
assertEquals(aposToQuotes("{'date':'1970-01-01T01:00:00.000+01:00'}"), json);
}

// [databind#1648]: contextual default format should be used
Expand Down

0 comments on commit 91a3636

Please sign in to comment.