jackson Spring 批次不确定日期

8aqjt8rx  于 2023-10-20  发布在  Spring
关注(0)|答案(4)|浏览(121)

我在spring batch的JobExecution上下文中添加了一个对象,它包含一个Instant字段。
它的序列化如下:

{
  "startFrom": {
    "nano": 0,
    "epochSecond": 1541116800
   }
 }

然而,Spring Batch似乎无法实现它。

Caused by: java.lang.IllegalArgumentException: Unable to deserialize the execution context
    at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao$ExecutionContextRowMapper.mapRow(JdbcExecutionContextDao.java:325)
    at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao$ExecutionContextRowMapper.mapRow(JdbcExecutionContextDao.java:309)
    at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:93)
    at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:60)
    at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:667)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:605)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:657)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:688)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:700)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:756)
    at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao.getExecutionContext(JdbcExecutionContextDao.java:112)
    at org.springframework.batch.core.explore.support.SimpleJobExplorer.getJobExecutionDependencies(SimpleJobExplorer.java:202)
    at org.springframework.batch.core.explore.support.SimpleJobExplorer.getJobExecutions(SimpleJobExplorer.java:83)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
    at org.springframework.aop.framework.ReflectiveMethod

在做一些研究时,我看到Jackson有一个JavaTimeModule来序列化/重新序列化Instant和其他日期类。但是,在Jackson2ExecutionContextStringSerializer类中,它创建了ObjectMapper,如下所示,没有注册正确的模块:

public Jackson2ExecutionContextStringSerializer() {
    this.objectMapper = new ObjectMapper();
    this.objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
    this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
    this.objectMapper.enableDefaultTyping();
    this.objectMapper.registerModule(new JobParametersModule());
}

Spring Batch不使用自动连接的ObjectMapper有什么原因吗?或者是他们不注册JavaTimeModule的原因?是否有解决此问题的方法?
谢谢你,谢谢
编辑:
我发现了如何覆盖这个对象Map器:

@Bean
  public JobRepository createJobRepository() throws Exception {
    ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule()).findAndRegisterModules();

    Jackson2ExecutionContextStringSerializer defaultSerializer = new Jackson2ExecutionContextStringSerializer();
    defaultSerializer.setObjectMapper(objectMapper);

    JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
    factory.setDataSource(dataSource);
    factory.setTransactionManager(transactionManager);
    factory.setSerializer(defaultSerializer);
    factory.afterPropertiesSet();
    return factory.getObject();
  }

然而,即使这样,问题仍然存在。

gcxthw6b

gcxthw6b1#

以下为我工作。我在扩展马哈茂德·本·哈辛的回答,上面的回答对尼古拉斯·维达特不起作用。(我没有足够的声誉来评论)。

@Bean
public BatchConfigurer configurer(DataSource dataSource, PlatformTransactionManager transactionManager,
  ObjectMapper objectMapper) {

    return new DefaultBatchConfigurer(dataSource) {
        final Jackson2ExecutionContextStringSerializer serializer = new Jackson2ExecutionContextStringSerializer();

        @Override
        protected JobRepository createJobRepository() throws Exception {
            serializer.setObjectMapper(objectMapper);

            JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
            factory.setDataSource(dataSource);
            factory.setTransactionManager(transactionManager);
            factory.setSerializer(serializer);
            factory.afterPropertiesSet();
            return factory.getObject();
        }

        @Override
        protected JobExplorer createJobExplorer() throws Exception {
            serializer.setObjectMapper(objectMapper);

            JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
            jobExplorerFactoryBean.setSerializer(serializer);
            jobExplorerFactoryBean.setDataSource(dataSource);
            jobExplorerFactoryBean.afterPropertiesSet();
            return jobExplorerFactoryBean.getObject();
        }
    };
}

(我在另一个@Configuration类中定义了一个ObjectMapper bean。)这里重要的是覆盖createJobExplorer()方法并在那里设置正确的ExecutionContextSerializer,因为这个方法将在JobExplorerFactoryBean上调用getTarget(),如果没有设置,它将设置一个vanilla ExecutionContextSerializer,这将导致您所描述的错误。

8tntrjer

8tntrjer2#

您显示的代码是序列化程序的默认初始化。您可以通过提供一个自定义的对象Map器来覆盖它,该Map器是用所需的模块预先配置的。下面是一个示例:

@Bean
public JobRepository jobRepository() throws Exception {
    ObjectMapper objectMapper = null; // configure the object mapper as required
    Jackson2ExecutionContextStringSerializer serializer = new Jackson2ExecutionContextStringSerializer();
    serializer.setObjectMapper(objectMapper);

    JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
    jobRepositoryFactoryBean.setSerializer(serializer);
    // set other properties on the jobRepositoryFactoryBean
    jobRepositoryFactoryBean.afterPropertiesSet();
    return jobRepositoryFactoryBean.getObject();
}

希望这对你有帮助。

w8rqjzmb

w8rqjzmb3#

更新

Spring batch现在有一个修复程序,允许您自定义您的ObjectMapper,同时还可以获得Jackson2ExecutionContextStringSerialier在解决此问题后在内部执行的所有默认设置:https://jira.spring.io/browse/BATCH-2828
修复在4.2.0中,在撰写本文时,它目前位于RC1

原始答案

我注意到类似的问题。我需要自定义ObjectMapper以添加KotlinModule来处理Kotlin数据类。不幸的是,目前编写Jackson2ExecutionContextStringSerializer的方式扩展性不强。正如您从创建的默认ObjectMapper中看到的那样,添加了一些默认值,包括对作业参数的重复问题的修复:https://jira.spring.io/browse/BATCH-2680
他们设置的JobParametersModule是一个private类,因此我们不能设置ObjectMapper具有相同的功能并添加到它。
我在Jira提出了一个问题:https://jira.spring.io/browse/BATCH-2828
在此问题得到解决之前,最简单的解决方法是复制并粘贴JobParmetersModule的源代码,以便您可以在覆盖中注册相同的代码。

mpgws1up

mpgws1up4#

通过使用上述所有答案,
对我来说,为了使用Jackson示例,
jackson-datatype-jsr310 : support for Java 8 Date & Time API type

@Bean
    public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
        return new Jackson2ObjectMapperBuilder().findModulesViaServiceLoader(true);
    }

如下所示
请注意,我还必须覆盖getTransactionManager(),并且由于我使用的是JPA,我还必须将创建的隔离级别设置为ISOLATION_DEFAULT

factory.setIsolationLevelForCreate("ISOLATION_DEFAULT");

@Bean
    public BatchConfigurer batchConfigurer(DataSource dataSource, EntityManagerFactory entityManagerFactory, ObjectMapper objectMapper) {
        return new DefaultBatchConfigurer(dataSource) {

            final Jackson2ExecutionContextStringSerializer serializer = new Jackson2ExecutionContextStringSerializer();

            @Override
            public PlatformTransactionManager getTransactionManager() {
                JpaTransactionManager transactionManager = new JpaTransactionManager();
                transactionManager.setDataSource(dataSource);
                transactionManager.setEntityManagerFactory(entityManagerFactory);
                return transactionManager;
            }

            @Override
            public JobRepository createJobRepository() throws Exception {

                // customize serializer
                serializer.setObjectMapper(objectMapper);
                JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
                factory.setDataSource(dataSource);
                factory.setTransactionManager(getTransactionManager());
                factory.setIsolationLevelForCreate("ISOLATION_DEFAULT");
                factory.setSerializer(serializer);
                // set other properties on the factory bean
                factory.afterPropertiesSet();
                return factory.getObject();
            }

           @Override
            protected JobExplorer createJobExplorer() throws Exception {
                serializer.setObjectMapper(objectMapper);

                JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
                jobExplorerFactoryBean.setSerializer(serializer);
                jobExplorerFactoryBean.setDataSource(dataSource);
                jobExplorerFactoryBean.afterPropertiesSet();
                return jobExplorerFactoryBean.getObject();
            }
        };
    }

相关问题