Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spring.jackson.date-format configuration does not affect serialisation of Joda DateTime instances #2225

Closed
csavory opened this issue Dec 23, 2014 · 22 comments
Assignees
Milestone

Comments

@csavory
Copy link
Contributor

csavory commented Dec 23, 2014

I have breakpoints set in both:
MappingJackson2HttpMessageConverterConfiguration.mappingJackson2HttpMessageConverter JacksonObjectMapperConfiguration.jacksonObjectMapper

I can see that there is an ObjectMapper bean being created because jacksonObjectMapper is never called and thus MappingJackson2HttpMessageConverterConfiguration uses this other ObjectMapper and not the one that I'm trying to configure. How do I tell what is creating that bean? From that logs, my guess is that it is HypermediaSupportBeanDefinitionRegistrar.registerBeanDefinitions that is doing it from:

        <dependency>
            <groupId>org.springframework.hateoas</groupId>
            <artifactId>spring-hateoas</artifactId>
        </dependency>

If I put a breakpoint there it is definitely called before MappingJackson2HttpMessageConverterConfiguration.mappingJackson2HttpMessageConverter but it is so hard to tell if this is the root of my problem. I can't remove that dependency because it is so pervasively used in my project that it would take me hours to refactor.

@csavory
Copy link
Contributor Author

csavory commented Dec 23, 2014

FYI, I'm using 1.2.0.RELEASE

@philwebb philwebb added this to the 1.2.1 milestone Dec 23, 2014
@philwebb philwebb modified the milestones: 1.2.2, 1.2.1 Jan 7, 2015
@wilkinsona wilkinsona self-assigned this Jan 15, 2015
@wilkinsona
Copy link
Member

@csavory Can you provide some more information about what you're trying to configure and how you're trying to configure it please?

Any spring.jackson.* properties that you specify are applied to the auto-configured JackonObjectMapperBuilder. This builder is then used to configure the default ObjectMapper as well as those created by the Spring HATEOAS and Spring Data REST auto-configuration.

@wilkinsona wilkinsona added the status: waiting-for-feedback We need additional information before we can continue label Jan 15, 2015
@csavory
Copy link
Contributor Author

csavory commented Jan 15, 2015

All I'm trying to do is get the Joda DateTime objects written out as Strings instead of timestamps. It works if I put the @JsonFormat(shape = Shape.STRING) annotation right on the property in the object, but it won't work if I try to configure the ObjectMapper holistically. This is because the ObjectMapper that is used is being defined somewhere else.

This is how I'm trying to configure:

  jackson:
    date-format: com.fasterxml.jackson.databind.util.ISO8601DateFormat
    serialization:
      write-dates-as-timestamps: false

@csavory
Copy link
Contributor Author

csavory commented Jan 15, 2015

@wilkinsona do I remove the waiting-for-feedback label now that I responded?

@wilkinsona
Copy link
Member

That helps, thanks. In investigating #2322 I'd been using java.util.Date. I'll take another look using DateTime this time.

@wilkinsona wilkinsona removed the status: waiting-for-feedback We need additional information before we can continue label Jan 15, 2015
@csavory
Copy link
Contributor Author

csavory commented Jan 15, 2015

@wilkinsona here is my configuration I'm using.

        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-joda</artifactId>
        </dependency>
    @Bean
    public Module jodaModule() {
        return new JodaModule();
    }

@wilkinsona
Copy link
Member

You're hitting a limitation in Jackson. Jackson treats the date format configured on the ObjectMapper separately to the one used by the custom serialiser for Joda's DataTime. This is with good reason as you can't format a Joda DateTime with a standard java.text.DateFormat.

@wilkinsona wilkinsona changed the title MappingJackson2HttpMessageConverterConfiguration.mappingJackson2HttpMessageConverter called before JacksonObjectMapperConfiguration.jacksonObjectMapper spring.jackson.date-format configuration does not affect serialisation of Joda DataTime instances Jan 15, 2015
@wilkinsona wilkinsona changed the title spring.jackson.date-format configuration does not affect serialisation of Joda DataTime instances spring.jackson.date-format configuration does not affect serialisation of Joda DateTime instances Jan 15, 2015
@csavory
Copy link
Contributor Author

csavory commented Jan 15, 2015

@wilkinsona I'm not sure I agree that writing it out as a string is a limitation of Joda. If you look at com.fasterxml.jackson.datatype.joda.ser.DateTimeSerializer line 34, there is a test to see whether it should write as a string or a timestamp based on the provider settings. The problem is that I can never get that statement to return false even though I am configuring my mapper via Spring Boot as write-dates-as-timestamps: false

if you look at com.fasterxml.jackson.datatype.joda.ser.JodaDateSerializerBase<T> on line 48, I can get it to write as a string if I set the property's annotation correctly.

The problem is that I want to do this globally through the ObjectMapper, but something is preventing Spring Boot from configuring the ObjectMapper as JacksonAutoConfiguration.JacksonObjectMapperConfiguration.jacksonObjectMapper is never called in my environment.

The problem is that I want to do this globally through the ObjectMapper, but something is preventing Spring Boot from configuring the ObjectMapper as JacksonAutoConfiguration.JacksonObjectMapperConfiguration.jacksonObjectMapper is never called in my environment.

@wilkinsona
Copy link
Member

The configuration of write-dates-as-timestamps works correctly as far as I can tell, and it affects the serialisation of both java.util.Date and org.joda.time.DateTime instances. The problem is that when write-dates-as-timestamps is false spring.jackson.date-format only affects the serialisation of java.util.Date instances.

This configuration:

spring:
  jackson:
    date-format: "YYYY-MM-dd"
    serialization:
      write_dates_as_timestamps: true

Gives me this output:

{"date":1421343027885,"dateTime":1421343027895}

Note that both the java.util.Date and org.joda.time.DateTime instances have been serialised as timestamps.

On the other hand this configuration:

spring:
  jackson:
    date-format: "YYYY-MM-dd"
    serialization:
      write_dates_as_timestamps: false

Gives me this output:

{"date":"2015-01-15","dateTime":"2015-01-15T17:31:28.884Z"}

Note that both are now being formatted as strings but that only java.util.Date has obeyed the DateFormat configuration. This is due to the Jackson limitation that I linked to above.

I see this behaviour both with and without Spring HATEOAS on the classpath. If you're seeing behaviour that's different to what I've described above, then please describe your application's configuration and its dependencies in more detail. Ideally, please provide a sample that shows a DateTime always being serialised as a timestamp.

@wilkinsona wilkinsona added the status: waiting-for-feedback We need additional information before we can continue label Jan 15, 2015
@csavory
Copy link
Contributor Author

csavory commented Jan 15, 2015

Andy, thanks for the info. It'll take me a couple of days to put together a sample for you. Is there a place I check it into or is just my repo fine?

Sent from my iPhone

On Jan 15, 2015, at 10:37 AM, Andy Wilkinson notifications@github.com wrote:

The configuration of write-dates-as-timestamps works correctly as far as I can tell, and it affects the serialisation of both java.util.Date and org.joda.time.DateTime instances. The problem is that when write-dates-as-timestamps is false spring.jackson.date-format only affects the serialisation of java.util.Date instances.

This configuration:

spring:
jackson:
date-format: "YYYY-MM-dd"
serialization:
write_dates_as_timestamps: true
Gives me this output:

{"date":1421343027885,"dateTime":1421343027895}
Note that both the java.util.Data and org.joda.time.DateTime instances have been serialised as timestamps.

On the other hand this configuration:

spring:
jackson:
date-format: "YYYY-MM-dd"
serialization:
write_dates_as_timestamps: false
Gives me this output:

{"date":"2015-01-15","dateTime":"2015-01-15T17:31:28.884Z"}
Note that both are now being formatted as strings but that only java.util.Date has obeyed the DateFormat configuration. This is due to the Jackson limitation that I linked to above.

I see this behaviour both with and without Spring HATEOAS on the classpath. If you're seeing behaviour that's different to what I've described above, then please describe your application's configuration and its dependencies in more detail. Ideally, please provide a sample that shows a DateTime always being serialised as a timestamp.


Reply to this email directly or view it on GitHub.

@wilkinsona
Copy link
Member

Thanks. Either something in your own repo, or as a PR against Spring Boot issues is fine.

@csavory
Copy link
Contributor Author

csavory commented Jan 21, 2015

@wilkinsona
Copy link
Member

Thanks.

You've annotated your configuration class with @EnableHypermediaSupport so you've opted to configure Spring HATEOAS yourself. Crucially, this means that you've disabled the logic which applies your spring.jackson.* configuration to the _halObjectMapper bean. Removing this annotation will mean that the configuration takes effect. You should also get rid of your ObjectMapper and JodaModule beans and allow Boot to automatically configure them for you.

With these three changes your sample app produces this output:

{"date":"2015-01-22T10:44:06Z","jodaDate":"2015-01-22T10:44:06.911Z","jodaDateForceAsString":"2015-01-22T10:44:06.913Z"}

@wilkinsona wilkinsona removed the status: waiting-for-feedback We need additional information before we can continue label Jan 22, 2015
@wilkinsona wilkinsona removed this from the 1.2.2 milestone Jan 22, 2015
@wilkinsona wilkinsona added the status: invalid An issue that we don't feel is valid label Jan 22, 2015
@wilkinsona wilkinsona reopened this Jan 22, 2015
@wilkinsona wilkinsona removed the status: invalid An issue that we don't feel is valid label Jan 22, 2015
@wilkinsona
Copy link
Member

I've reopened this as I'd like to address the Jackson limitation that stops spring.jackson.date-format from affecting the serialisation of a Joda DateTime. This'll require a change in Spring Framework.

@csavory
Copy link
Contributor Author

csavory commented Jan 22, 2015

Thank you @wilkinsona
Your suggestions work for me.

When we started using Spring Boot (v0.5), HypermediaAutoConfiguration was not part of Boot so that was how it was configured for us.

By the way, there is no documentation in the Boot docs about how to configure HATEOAS support with Boot. The only docs are found at https://github.com/spring-projects/spring-hateoas/blob/master/readme.md
I only mention that since it might help the next person trying to configure HATEOAS if it was mentioned on the Spring Boot reference page.

@wilkinsona
Copy link
Member

You don't really need to do anything to configure HATEOAS support other than having the right things on the classpath, i.e. there's not much to say in the manual that wouldn't end up being a duplication of Spring HATEOAS's existing documentation. I've just added a starter to help with the classpath part. We also have a sample application that shows Spring HATEOAS in action with Spring Boot.

@csavory
Copy link
Contributor Author

csavory commented Jan 22, 2015

I agree with you that you need to do anything to configure HATEOAS support for Boot.

But the configuration is different if I am using:
Spring Framework + Spring HATEOAS
vs.
Spring Framework + Spring HATEOAS + Spring Boot

I would think since there is a difference in how you configure it the latter scenario (even if it's a negative configuration) it would be worth mentioning in the Boot reference. If it was there in the reference, I would have never created this issue b/c I would have read it there and removed my @EnableHypermediaSupport annotation.

As I said before, just trying to help folks out coming after me and don't look through the specifics of how all the AutoConfigurators work by looking at the code.

As I said before, just trying to help folks out coming after me and don't look through the specifics of how all the AutoConfigurators work by looking at the code.

@csavory
Copy link
Contributor Author

csavory commented Jan 27, 2015

@wilkinsona this solution stops working when I merged in my temporary solution for #2360 where my WebConfig extends WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter. I now have an ObjectMapper that is created without Jackson2ObjectMapperBuilder and I cannot figure out who is creating that. I can tell it isn't created with Jackson2ObjectMapperBuilder because it doesn't have the Joda module serializers in its SerializerFactory that are created in Jackson2ObjectMapperBuilder.registerWellKnownModulesIfAvailable.

I don't see any ObjectMapper stuff in `WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter. Could extending that class be preventingJacksonAutoConfiguration`` from doing something it needs?

@csavory
Copy link
Contributor Author

csavory commented Jan 27, 2015

@wilkinsona nevermind. I found a way to put our WebConfig back to

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter implements EnvironmentAware {

It's working again.

@wilkinsona
Copy link
Member

@csavory You make a good point about the Spring HATEOAS auto-configuration. Thanks. I've opened #2426 to improve the docs.

@wilkinsona wilkinsona added this to the 1.2.2 milestone Feb 12, 2015
@pavelfomin
Copy link

pavelfomin commented Aug 11, 2016

I have the same problem as @csavory described - if I add a WebConfig that extends WebMvcConfigurerAdapter then my date format specified for jackson in application.properties is not taking effect:

spring.jackson.date-format=yyyy-MM-dd'T'HH:mm:ss.SSSZ
spring.jackson.serialization.write_dates_as_timestamps=false

I'm using boot spring boot 1.4.0. Does my WebConfig need to implement EnvironmentAware? @csavory, can you provide an example?

P.S. I'm using WebConfig to add resource handlers for swagger.

@snicoll
Copy link
Member

snicoll commented Aug 11, 2016

@pavelfomin this issue is closed. If you believe you've found an issue with a recent version of Spring Boot, please create separate issue. Consider using stackoverflow or gitter for questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants