【发布时间】:2020-10-24 08:14:03
【问题描述】:
我使用spring-batch:4.2.2.RELEASE 作为spring-boot-starter-batch:2.2.4.RELEASE 的一部分。
将后者升级到版本2.3.1.RELEASE后,开始工作时出现以下异常:
java.lang.IllegalArgumentException: Unable to deserialize the execution context
at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao$ExecutionContextRowMapper.mapRow(JdbcExecutionContextDao.java:328)
at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao$ExecutionContextRowMapper.mapRow(JdbcExecutionContextDao.java:312)
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94)
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61)
at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:679)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:617)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:669)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:700)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:712)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:768)
at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao.getExecutionContext(JdbcExecutionContextDao.java:129)
at org.springframework.batch.core.explore.support.SimpleJobExplorer.getStepExecutionDependencies(SimpleJobExplorer.java:238)
at org.springframework.batch.core.explore.support.SimpleJobExplorer.getJobExecutions(SimpleJobExplorer.java:87)
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:566)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy145.getJobExecutions(Unknown Source)
...
Caused by: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [map type; class java.util.HashMap, [simple type, class java.lang.String] -> [simple type, class java.lang.Object]]: missing type id property '@class'
at [Source: (ByteArrayInputStream); line: 1, column: 192]
at com.fasterxml.jackson.databind.exc.InvalidTypeIdException.from(InvalidTypeIdException.java:43)
at com.fasterxml.jackson.databind.DeserializationContext.missingTypeIdException(DeserializationContext.java:1790)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingTypeId(DeserializationContext.java:1319)
at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._handleMissingTypeId(TypeDeserializerBase.java:303)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedUsingDefaultImpl(AsPropertyTypeDeserializer.java:166)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:107)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserializeWithType(MapDeserializer.java:400)
at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:68)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4482)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3479)
at org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer.deserialize(Jackson2ExecutionContextStringSerializer.java:123)
at org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer.deserialize(Jackson2ExecutionContextStringSerializer.java:102)
at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao$ExecutionContextRowMapper.mapRow(JdbcExecutionContextDao.java:325)
... 45 common frames omitted
我了解新版本对 JSON 反序列化的处理受到限制,并尝试实施来自 Jackson2ExecutionContextStringSerializer javadoc 的建议修复,但问题仍然存在:
@EnableBatchProcessing
@Configuration
class BatchConfig(
val properties: BatchProperties,
val dataSource: DataSource,
val transactionManagerCustomizers: TransactionManagerCustomizers,
val entityManagerFactory: EntityManagerFactory
) : JpaBatchConfigurer(properties, dataSource, transactionManagerCustomizers, entityManagerFactory) {
override fun createJobRepository(): JobRepository {
val factory = JobRepositoryFactoryBean()
val map = PropertyMapper.get()
map.from(dataSource).to { dataSource: DataSource? -> factory.setDataSource(dataSource!!) }
map.from { determineIsolationLevel() }.whenNonNull().to { isolationLevelForCreate: String? -> factory.setIsolationLevelForCreate(isolationLevelForCreate!!) }
map.from { properties.tablePrefix }.whenHasText().to { tablePrefix: String? -> factory.setTablePrefix(tablePrefix!!) }
map.from { transactionManager }.to { transactionManager: PlatformTransactionManager? -> factory.transactionManager = transactionManager!! }
factory.afterPropertiesSet()
val serializer = configureContextSerializer()
factory.setSerializer(serializer)
return factory.getObject()
}
private fun configureContextSerializer(): Jackson2ExecutionContextStringSerializer {
val polymorphicTypeValidator = LaissezFaireSubTypeValidator()
objectMapper.activateDefaultTyping(polymorphicTypeValidator)
val serializer = Jackson2ExecutionContextStringSerializer()
serializer.setObjectMapper(objectMapper)
return serializer
}
最疯狂的部分是执行上下文实际上是空的,数据库值总是"{}"。我什至尝试将数据库中的所有值都更改为"{"@class":"java.util.HashMap"}",但仍然遇到同样的异常。
有人知道如何解决这个问题吗?我的修复尝试中的配置是否错误?
【问题讨论】:
-
您是在尝试运行新的作业实例还是重新启动失败的作业实例?使用 4.2.2 序列化的执行上下文不包含使用 4.2.4 反序列化所需的类型信息(
@class、@property等)。如果您使用 4.2.4 运行新作业并启用默认类型,jackson 会将类型信息添加到序列化执行上下文中。 -
@MahmoudBenHassine 我正在运行一个新实例,但我想读取先前成功实例的最后执行时间。我是否正确理解使用 4.2.2 运行过去的作业是不可能的?
-
您需要添加类型信息(正如您尝试的那样)才能反序列化先前的上下文(使用 4.2.2 序列化的上下文)。我认为您在
"{"@class":"java.util.HashMap"}"中添加@class的尝试是不正确的。尝试看看 jackson 如何序列化一个新的执行上下文并使用类似的内容更新您现有的执行上下文。 -
@MahmoudBenHassine 实际上,
{"@class":"java.util.HashMap"}是正确的,我必须将其添加到batch_step_execution_context以及batch_job_execution_context。 -
Spring batch 4.3.1(spring boot 2.4.2)也有同样的问题。我已经将spring batch的版本降级到4.2.2来解决。
标签: java spring spring-boot kotlin spring-batch