Skip to content

JsonObjectReader fails to read JSON array format due to Jackson 3.0 FAIL_ON_TRAILING_TOKENS default change #5047

@KILL9-NO-MERCY

Description

@KILL9-NO-MERCY

Hi Spring Batch team!
First of all, thank you for your amazing work on Spring Batch 6.0

I've encountered an issue when reading JSON array files with JsonItemReader in Spring Batch 6.0 with Spring Boot 4(use jackson 3.0), and I wanted to report it in case it affects other users migrating to this version.

Bug description
JacksonJsonObjectReader(used by JsonItemReader) cannot read JSON array format [{...}, {...}] when using the default constructor in Spring Batch 6.0 with Jackson 3.0.

This appears to be caused by Jackson 3.0's change where DeserializationFeature.FAIL_ON_TRAILING_TOKENS default was changed from false to true (Jackson JSTEP-2).

When reading a JSON array, after parsing the first object, the second object's start token { is detected as a "trailing token", causing a MismatchedInputException.

Environment

  • Spring Boot: 4.0.0-SNAPSHOT / spring-boot-starter-json 4.0.0-SNAPSHOT
  • Spring Batch: 6.0.0-RC1
  • Jackson: 3.0.1
  • Java: 21

Steps to reproduce

  1. Create a JSON array file:
echo '[
{"command": "destroy", "cpu": 99, "status": "memory overflow"},
{"command": "explode", "cpu": 100, "status": "cpu meltdown"},
{"command": "collapse", "cpu": 95, "status": "disk burnout"}
]' > system_death.json
  1. Configure JsonItemReader with default JacksonJsonObjectReader:
@Bean
@StepScope
public JsonItemReader systemFailureItemReader(
        @Value("#{jobParameters['inputFile']}") String inputFile) {
    return new JsonItemReaderBuilder()
            .name("systemFailureItemReader")
            .jsonObjectReader(new JacksonJsonObjectReader<>(SystemFailure.class))
            .resource(new FileSystemResource(inputFile))
            .build();
}

public record SystemFailure(String command, int cpu, String status) {}
  1. Run the job with the JSON array file

Expected behavior

JsonItemReader should successfully read all objects from the JSON array [{...}, {...}, {...}] without requiring manual Jackson configuration, as JSON arrays are a common input format for batch processing.

Actual behavior

Job fails with:

tools.jackson.databind.exc.MismatchedInputException: Trailing token (JsonToken.START_OBJECT) found after value (bound as SystemFailure): not allowed as per DeserializationFeature.FAIL_ON_TRAILING_TOKENS

Minimal Complete Reproducible example

Here's the complete configuration that reproduces the issue:

@Bean
public Job systemFailureJob(Step systemFailureStep) {
    return new JobBuilder("systemFailureJob", jobRepository)
            .start(systemFailureStep)
            .build();
}

@Bean
public Step systemFailureStep(JsonItemReader systemFailureItemReader) {
    return new StepBuilder("systemFailureStep", jobRepository)
            .chunk(10)
            .reader(systemFailureItemReader)
            .writer(items -> items.forEach(item -> log.info("{}", item)))
            .build();
}

@Bean
@StepScope
public JsonItemReader systemFailureItemReader(
        @Value("#{jobParameters['inputFile']}") String inputFile) {
    return new JsonItemReaderBuilder()
            .name("systemFailureItemReader")
            .jsonObjectReader(new JacksonJsonObjectReader<>(SystemFailure.class))
            .resource(new FileSystemResource(inputFile))
            .build();
}

public record SystemFailure(String command, int cpu, String status) {}

Current Workaround

manually creating a JsonMapper with FAIL_ON_TRAILING_TOKENS disabled resolves the issue:

@Bean
@StepScope
public JsonItemReader systemFailureItemReader(
        @Value("#{jobParameters['inputFile']}") String inputFile) {
    
    JsonMapper jsonMapper = JsonMapper.builder()
            .disable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)
            .build();
    
    JacksonJsonObjectReader jsonReader =
            new JacksonJsonObjectReader<>(jsonMapper, SystemFailure.class);
    
    return new JsonItemReaderBuilder()
            .name("systemFailureItemReader")
            .jsonObjectReader(jsonReader)
            .resource(new FileSystemResource(inputFile))
            .build();
}

Suggested Solutions

I'd like to humbly suggest two possible approaches:

  1. Update JacksonJsonObjectReader default constructor to create a JsonMapper with FAIL_ON_TRAILING_TOKENS disabled by default, since JSON array reading is a fundamental use case for JsonItemReader

  2. Update the documentation to clearly guide users that manual JsonMapper configuration with FAIL_ON_TRAILING_TOKENS disabled is required when reading JSON arrays in Spring Batch 6.0+

Thank you again for maintaining Spring Batch! Please let me know if you need any additional information or clarification.

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