2

After upgrading a Spring Boot upgrade from 1.3.3 to 1.4.0, I have noticed a change of behavior when serializing a org.joda.time.DateTime.

Let's build up a simple Spring boot + Maven Project.

The pom.xml dependencies:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.7.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-joda</artifactId>
    </dependency>
<dependencies>

The domain object:

@Document(collection="items")
@TypeAlias("item")
public class Item {
    @Id
    private String id;
    private DateTime date;

    /* getters/setters omitted */
}

The repository:

public interface ItemRepository extends MongoRepository<Item, String>{}

Now, if I GET any item resource, I get the following result:

{
  "_embedded" : {
    "items" : [ {
      "id" : "57bf084a452105f14763cce7",
      "date" : "1970-01-01T00:00:00.000Z",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8082/items/57bf084a452105f14763cce7"
        },
        "item" : {
          "href" : "http://localhost:8082/items/57bf084a452105f14763cce7"
        }
      }
    } ]
  },
  /* omitted links and meta data */
}

Which is fine.

Now, if i upgrade Spring Boot to 1.4.0.RELEASE, without touching anything else in my code base, I get the following:

{
  "_embedded" : {
    "items" : [ {
      "id" : "57bf084a452105f14763cce7",
      "date" : {
        "content" : "1970-01-01T00:00:00.000Z"
      },
      "_links" : {
        "self" : {
          "href" : "http://localhost:8082/items/57bf084a452105f14763cce7"
        },
        "item" : {
          "href" : "http://localhost:8082/items/57bf084a452105f14763cce7"
        }
      }
    } ]
  },
  /* links and metadata omitted */
}

The datetime is now serialized as { "content" : "1970-01-01T00:00:00.000Z" } instead of "1970-01-01T00:00:00.000Z"

This problem is easily solved by annotating the DateTime field with @JsonFormat:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
private DateTime date;

Actually, I don't like using @JsonFormat. Instead, I use a custom Jackson2ObjectMapperBuilder (it lets me handle my other serializers and deserializers, manually or via @JsonComponent...)

@Configuration
public class JacksonConfiguration {

    @Bean
    public Jackson2ObjectMapperBuilder jacksonBuilder() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();

        builder.serializerByType(DateTime.class, new DateTimeSerializer());
        
        return builder;
    }

}

Bad news, I still get the same result. I've tried with a custom serializer, I still get the "content" key in the way. Only by using the com.fasterxml.jackson.databind.ser.std.ToStringSerializer instead of the com.fasterxml.jackson.datatype.joda.ser.DateTimeSerializer do I (almost) get what I want:

{
  "_embedded" : {
    "items" : [ {
      "id" : "57bf084a452105f14763cce7",
      "date" : "1970-01-01T01:00:00.000+01:00",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8082/items/57bf084a452105f14763cce7"
        },
        "item" : {
          "href" : "http://localhost:8082/items/57bf084a452105f14763cce7"
        }
      }
    } ]
  },
  /* links and metadata omitted */
}

In a nutshell, what's happening? Where does that extra "content" key come from and should it be there? I'd like to report this bug, but I don't know who is concerned, the developers from Spring Boot, or Jackson?

Marc Tarin
  • 3,109
  • 17
  • 49
  • See also http://stackoverflow.com/q/39172792/466738 for the same problem – Adam Michalik Sep 01 '16 at 07:20
  • Try using `JavaTimeModule` and register it with `ObjectMapper` – Akber Choudhry Sep 01 '16 at 12:46
  • 1
    Given that the dependency on `jackson-datatype-joda` is declared, it should automatically be configured with the `ObjectMapper`. The issue Marc outlines is the same as I've come across (see link above) and in that case I've explicitly registered the `JodaModule` and it has no effect. This issue seems to be due to a change in Spring since the upgrade to 1.4.0 as in both of our cases the code worked prior to the upgrade. – roborative Sep 01 '16 at 16:15
  • 1
    Spring Boot 1.4.0 upgraded both JodaTime from 2.8.2 to 2.9.4 and Jackson from 2.6.7 to 2.8.1 comparing with Boot 1.3.7. However using raw JodaTime and Jackson gives correct results using either of the versions. See test here: https://gist.github.com/adammichalik/29e4d181409af312adab3a9f4ef6d6fe – Adam Michalik Sep 02 '16 at 07:14
  • 1
    @adam The behavior isn't demonstrated by using Jackson alone. That is, I can serialize the same object with an object mapper and the 'content' field is absent. It seems peculiar to the REST interface. As I mentioned in my post, it seems like the date is being treated as a resource. – roborative Sep 02 '16 at 17:01
  • 1
    @roborative - yes, I wanted to demonstrate that raw JodaTime + Jackson work fine and it's only messed up when Spring comes to play – Adam Michalik Sep 02 '16 at 17:09
  • you need to use the `Jackson2ObjectMapperBuilderCustomizer` or some such... https://github.com/spring-projects/spring-boot/issues/6678 or `RepositoryRestConfigurerAdapter` https://github.com/spring-projects/spring-boot/issues/6673 – xenoterracide Sep 02 '16 at 21:22
  • Possible duplicate of [How can I change Jacksons Configuration when using Spring Data REST?](http://stackoverflow.com/questions/32924510/how-can-i-change-jacksons-configuration-when-using-spring-data-rest) – xenoterracide Sep 02 '16 at 21:25
  • @AkberChoudhry JavaTimeModule is used for java.time object, not org.joda.time objects such as org.joda.time.DateTime. The thing is the DateTime object are indeed serialized, but the result gets wrapped as a resource, hence the "content" key, as roborative points out. – Marc Tarin Sep 05 '16 at 13:01
  • I've opened a ticket on this: https://jira.spring.io/browse/DATAREST-888 – roborative Sep 06 '16 at 16:52
  • Problem solved with Spring Boot 1.4.1. – Marc Tarin Sep 26 '16 at 20:49

0 Answers0