title: Migration from Spring Batch 3 to 4
body: <p>I'm trying to migrate from Spring Batch 3.0.6 to 4.1.1.</p>
  
  <p>I'm stuck handling Spring Batch's execution context data as explained <a href="https://stackoverflow.com/questions/52010399/caused-by-java-lang-illegalargumentexception-unable-to-deserialize-the-executi/52036602#52036602">here</a>.</p>
  
  <p>What I would like is update tables <code>batch_step_execution_context</code> and <code>batch_step_execution_context</code> as follows, for each record :</p>
  
  <ul>
  <li>unserialize context data using the deprecated <code>XStreamExecutionContextStringSerializer</code></li>
  <li>serialize the java object obtained using a jackson <code>ObjectMapper</code></li>
  <li>update the table using this new string</li>
  </ul>
  
  <p>It has worked for some records and I could run Spring Batch 4. But for some jobs, the new string is not deserializable as a <code>ExecutionContext</code>.</p>
  
  <p>Here is an example of such a string :</p>
  
  <pre><code>{
     "setMoisAffaires":[
        {
           "premierJourDuMois":{
              "date":1257030000000,
              "stringFromDatePatternAmericain":"2009-11-01",
              "hour":0,
              "year":2009,
              "dayOfMonth":1,
              "dayOfWeek":7,
              "dateString":"20091101",
              "monthOfYear":11,
              "minuteOfHour":0,
              "secondOfMinute":0
           },
           "date":1257030000000,
           "stringFromDatePatternAmericain":"2009-11-01",
           "hour":0,
           "year":2009,
           "dayOfMonth":1,
           "dayOfWeek":7,
           "dateString":"200911",
           "monthOfYear":11,
           "minuteOfHour":0,
           "secondOfMinute":0
        },
        //a lot of records like the previous...
     ],
     "batch.taskletType":"com.sun.proxy.$Proxy57",
     "batch.stepType":"org.springframework.batch.core.step.tasklet.TaskletStep"
  }
  </code></pre>
  
  <p>Here is the trace when I try to do : <code>ExecutionContext a = objectMapper.readValue(objectMapper.writeValueAsString(javaObject),ExecutionContext.class);</code></p>
  
  <pre><code>Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "setMoisAffaires" (class org.springframework.batch.item.ExecutionContext), not marked as ignorable (one known property: "dirty"])
   at [Source: (String)"{"setMoisAffaires":[{"prem...[truncated 15163 chars]; line: 1, column: 21] (through reference chain: org.springframework.batch.item.ExecutionContext["setMoisAffaires"])
   at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:61)
   at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:823)
   at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1153)
   at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1589)
   at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1567)
   at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:294)
   at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
   at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
   at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
  </code></pre>
  
  <p>Here is a unit test to reproduce the problem :</p>
  
  <pre><code>package springBatch4Migration;
  
  import static org.junit.Assert.assertNotNull;
  
  import java.io.ByteArrayInputStream;
  
  import org.junit.Test;
  import org.springframework.batch.core.repository.dao.XStreamExecutionContextStringSerializer;
  import org.springframework.batch.item.ExecutionContext;
  
  import com.fasterxml.jackson.databind.ObjectMapper;
  
  public class SerializeTest {
  
      @Test
      public void test() throws Exception {
          String oldJson = "{\"map\":[{\"entry\":[{\"string\":[\"batch.stepType\",\"org.springframework.batch.core.step.tasklet.TaskletStep\"]},{\"string\":[\"batch.taskletType\",\"com.sun.proxy.$Proxy56\"]},{\"string\":\"setMoisAffaires\",\"set\":[{\"tools.date.dates.Mois\":[{\"dateLocale\":{\"iLocalMillis\":1264982400000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@resolves-to\":\"org.joda.time.chrono.ISOChronology$Stub\",\"@serialization\":\"custom\",\"org.joda.time.chrono.ISOChronology$Stub\":{\"org.joda.time.UTCDateTimeZone\":{\"@resolves-to\":\"org.joda.time.DateTimeZone$Stub\",\"@serialization\":\"custom\",\"org.joda.time.DateTimeZone$Stub\":{\"string\":\"UTC\"}}}}},\"categorie\":\"MOIS\",\"dateAsString\":201002},{\"dateLocale\":{\"iLocalMillis\":1312156800000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201108},{\"dateLocale\":{\"iLocalMillis\":1288569600000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201011},{\"dateLocale\":{\"iLocalMillis\":1285891200000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201010},{\"dateLocale\":{\"iLocalMillis\":1243814400000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":200906},{\"dateLocale\":{\"iLocalMillis\":1257033600000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":200911},{\"dateLocale\":{\"iLocalMillis\":1277942400000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201007},{\"dateLocale\":{\"iLocalMillis\":1249084800000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":200908},{\"dateLocale\":{\"iLocalMillis\":1320105600000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201111},{\"dateLocale\":{\"iLocalMillis\":1283299200000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201009},{\"dateLocale\":{\"iLocalMillis\":1328054400000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201202},{\"dateLocale\":{\"iLocalMillis\":1325376000000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201201},{\"dateLocale\":{\"iLocalMillis\":1296518400000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201102},{\"dateLocale\":{\"iLocalMillis\":1306886400000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201106},{\"dateLocale\":{\"iLocalMillis\":1267401600000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201003},{\"dateLocale\":{\"iLocalMillis\":1251763200000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":200909},{\"dateLocale\":{\"iLocalMillis\":1262304000000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201001},{\"dateLocale\":{\"iLocalMillis\":1280620800000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201008},{\"dateLocale\":{\"iLocalMillis\":1270080000000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201004},{\"dateLocale\":{\"iLocalMillis\":1317427200000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201110},{\"dateLocale\":{\"iLocalMillis\":1272672000000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201005},{\"dateLocale\":{\"iLocalMillis\":1304208000000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201105},{\"dateLocale\":{\"iLocalMillis\":1233446400000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":200902},{\"dateLocale\":{\"iLocalMillis\":1254355200000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":200910},{\"dateLocale\":{\"iLocalMillis\":1246406400000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":200907},{\"dateLocale\":{\"iLocalMillis\":1309478400000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201107},{\"dateLocale\":{\"iLocalMillis\":1259625600000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":200912},{\"dateLocale\":{\"iLocalMillis\":1238544000000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":200904},{\"dateLocale\":{\"iLocalMillis\":1314835200000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201109},{\"dateLocale\":{\"iLocalMillis\":1330560000000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201203},{\"dateLocale\":{\"iLocalMillis\":1241136000000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":200905},{\"dateLocale\":{\"iLocalMillis\":1322697600000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201112},{\"dateLocale\":{\"iLocalMillis\":1301616000000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201104},{\"dateLocale\":{\"iLocalMillis\":1275350400000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201006},{\"dateLocale\":{\"iLocalMillis\":1293840000000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201101},{\"dateLocale\":{\"iLocalMillis\":1235865600000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":200903},{\"dateLocale\":{\"iLocalMillis\":1291161600000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201012},{\"dateLocale\":{\"iLocalMillis\":1298937600000,\"iChronology\":{\"@class\":\"org.joda.time.chrono.ISOChronology\",\"@reference\":\"..\\/..\\/..\\/tools.date.dates.Mois\\/dateLocale\\/iChronology\"}},\"categorie\":\"MOIS\",\"dateAsString\":201103}]}]}]}]}";
  
          /*
           * Unserializing oldJson to a Java object...
           */
          XStreamExecutionContextStringSerializer oldSerializer = new XStreamExecutionContextStringSerializer();
          oldSerializer.init();
  
          ByteArrayInputStream oldInputStream = new ByteArrayInputStream(oldJson.getBytes());
          Object javaObject = oldSerializer.deserialize(oldInputStream);
  
          /*
           * Serializing back to a new Json string using Jackson...
           */
          ObjectMapper newSerializer = new ObjectMapper();
          ExecutionContext a = newSerializer.readValue(newSerializer.writeValueAsString(javaObject),ExecutionContext.class);
  
          assertNotNull(a);
      }
  
  }
  </code></pre>
  
  <p>And here is what I get if I try to run a job using such data :</p>
  
  <pre><code>ERROR - CommandLineJobRunner:367  - Job Terminated in error: Unable to deserialize the execution context
  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:210)
      at org.springframework.batch.core.explore.support.SimpleJobExplorer.getJobExecutions(SimpleJobExplorer.java:87)
      at org.springframework.batch.core.JobParametersBuilder.getNextJobParameters(JobParametersBuilder.java:266)
      at org.springframework.batch.core.launch.support.CommandLineJobRunner.start(CommandLineJobRunner.java:357)
      at org.springframework.batch.core.launch.support.CommandLineJobRunner.main(CommandLineJobRunner.java:564)
      at fr.mycompany.myapp.commun.batch.CommandLineJobRunnerTest.runJob(CommandLineJobRunnerTest.java:180)
      at fr.mycompany.myapp.commun.batch.CommandLineJobRunnerTest.execute(CommandLineJobRunnerTest.java:496)
      at fr.mycompany.myapp.commun.batch.CommandLineJobRunnerTest.main(CommandLineJobRunnerTest.java:529)
  Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (START_OBJECT), expected VALUE_STRING: need JSON String that contains type id (for subtype of java.lang.Object)
   at [Source: (ByteArrayInputStream); line: 1, column: 21] (through reference chain: java.util.HashMap["setMoisAffaires"])
      at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
      at com.fasterxml.jackson.databind.DeserializationContext.wrongTokenException(DeserializationContext.java:1499)
      at com.fasterxml.jackson.databind.DeserializationContext.reportWrongTokenException(DeserializationContext.java:1274)
      at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._locateTypeId(AsArrayTypeDeserializer.java:151)
      at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:96)
      at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromAny(AsArrayTypeDeserializer.java:71)
      at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserializeWithType(UntypedObjectDeserializer.java:712)
      at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:529)
      at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:364)
      at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:29)
      at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
      at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3077)
      at org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer.deserialize(Jackson2ExecutionContextStringSerializer.java:70)
      at org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer.deserialize(Jackson2ExecutionContextStringSerializer.java:50)
      at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao$ExecutionContextRowMapper.mapRow(JdbcExecutionContextDao.java:325)
      ... 18 more
  </code></pre>
  
  <p>Here is an example of a step using such <code>setMoisAffaires</code> :</p>
  
  <pre><code>&lt;bean id="jobname.jobstep" parent="jobItemParent"
      class="fr.mycompany.myapp.collecte.batch.jobname.jobstep" scope="step"&gt;
      &lt;property name="setMoisAffaires" value="#{stepExecutionContext['setMoisAffaires']}" /&gt;
  &lt;/bean&gt;
  </code></pre>