Skip to content

CoreJacksonModule forces WRITE_DATES_AS_TIMESTAMPS=true, overriding user configuration #18561

@neinhart

Description

@neinhart

Issue: CoreJacksonModule forces WRITE_DATES_AS_TIMESTAMPS=true, overriding user configuration

Summary

CoreJacksonModule (Jackson 3 version) explicitly enables DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS in its setupModule() method, which overrides any user configuration and forces LocalDateTime to be serialized as arrays instead of ISO-8601 strings.

Current Behavior

In CoreJacksonModule.java line 104:

@Override
public void setupModule(SetupContext context) {
    ((MapperBuilder<?, ?>) context.getOwner()).enable(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS);
    // ... mixin registrations
}

This causes LocalDateTime to be serialized as:

{"time": [2026, 1, 23, 12, 34, 56, 789000000]}

Even when users explicitly disable this feature:

GenericJacksonJsonRedisSerializer.builder()
    .customize(mapperBuilder -> {
        mapperBuilder.addModules(SecurityJacksonModules.getModules(loader));
        mapperBuilder.disable(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS); // This gets overridden!
    })
    .build();

Expected Behavior

Jackson 3's default for WRITE_DATES_AS_TIMESTAMPS is false, which serializes dates as ISO-8601 strings:

{"time": "2026-01-23T12:34:56.789"}

Users should be able to use this default or configure it themselves without CoreJacksonModule overriding their settings.

Why This Matters

  1. User configuration is silently ignored: There's no way to use ISO-8601 format when using SecurityJacksonModules
  2. Undocumented behavior: This is not mentioned in migration guides or release notes
  3. Inconsistent with Jackson 3 defaults: Jackson 3 intentionally changed the default to ISO-8601 for better readability and interoperability

Comparison with Jackson 2 Version

CoreJackson2Module does not set WRITE_DATES_AS_TIMESTAMPS at all - it relies on Jackson 2's default (true).

The Jackson 3 version explicitly enables it, presumably for backward compatibility with existing serialized data. However, this should be:

  1. Documented in migration guides
  2. Ideally configurable or opt-in

Suggested Solutions

  1. Remove the forced enable: Let users control this setting
  2. Or make it configurable: Add a way to opt-out of this behavior
  3. At minimum: Document this behavior in the Spring Security 7 / Jackson 3 migration guide

Environment

  • Spring Security: 7.0.x
  • Spring Boot: 4.0.x
  • Jackson: 3.x

Workaround

Currently, the only workaround is to filter out CoreJacksonModule from the security modules:

List<JacksonModule> securityModules = SecurityJacksonModules.getModules(loader, validatorBuilder);

// Filter out CoreJacksonModule to prevent WRITE_DATES_AS_TIMESTAMPS override
List<JacksonModule> filteredModules = securityModules.stream()
    .filter(m -> !(m instanceof CoreJacksonModule))
    .toList();

GenericJacksonJsonRedisSerializer.builder()
    .customize(mapperBuilder -> {
        filteredModules.forEach(mapperBuilder::addModule);
        mapperBuilder.disable(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS);
    })
    .build();

This works but loses the mixins registered by CoreJacksonModule (though they may be available through other modules).


제출 방법

방법 1: GitHub 웹사이트

https://github.com/spring-projects/spring-security/issues/new 에서 직접 제출

방법 2: gh CLI 사용

# 먼저 인증
gh auth login

# 이슈 생성
gh issue create --repo spring-projects/spring-security \
  --title "CoreJacksonModule forces WRITE_DATES_AS_TIMESTAMPS=true, overriding user configuration" \
  --body-file spring-security-issue.md

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions