title: Spring Batch 4.2.4: Unable to deserialize the execution context
body: <p>I was using <code>spring-batch:4.2.2.RELEASE</code> as part of <code>spring-boot-starter-batch:2.2.4.RELEASE</code>.
  After upgrading the latter to version <code>2.3.1.RELEASE</code>, I get the following exception when starting a job:</p>
  <pre><code>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] -&gt; [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
  
  
  </code></pre>
  <p>I understand that the new version has a restricted handling of JSON deserialization and attempted to implement the suggested fix from the <code>Jackson2ExecutionContextStringSerializer</code> javadoc, however the problem persists:</p>
  <pre><code>@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? -&gt; factory.setDataSource(dataSource!!) }
          map.from { determineIsolationLevel() }.whenNonNull().to { isolationLevelForCreate: String? -&gt; factory.setIsolationLevelForCreate(isolationLevelForCreate!!) }
          map.from { properties.tablePrefix }.whenHasText().to { tablePrefix: String? -&gt; factory.setTablePrefix(tablePrefix!!) }
          map.from { transactionManager }.to { transactionManager: PlatformTransactionManager? -&gt; 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
      }
  </code></pre>
  <p>The craziest part is that the execution context is actually empty, the database value is always <code>&quot;{}&quot;</code>. I even tried changing all values in the DB to <code>&quot;{&quot;@class&quot;:&quot;java.util.HashMap&quot;}&quot;</code>, but I still get the same exception.</p>
  <p>Does anyone have an idea how to fix this? Is the configuration from my fix attempt wrong?</p>