Вызвано: java.lang.IllegalArgumentException: невозможно десериализовать контекст выполнения в Spring Batch

Я разрабатываю подход на основе Spring Boot + Batch XML. В этом примере я создал следующие классы. Когда я просто загружаю или классифицирую Spring Batch Job. Я получаю ошибку ниже.

Я поискал в Интернете такие ссылки, как: Переход на Spring Boot 2 и использование Spring Batch 4, но это не решило мою проблему.

Может ли кто-нибудь указать, какое точное решение необходимо применить здесь?

Ошибка:

Caused by: java.lang.IllegalArgumentException: Unable to deserialize the execution context
    at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao$ExecutionContextRowMapper.mapRow(JdbcExecutionContextDao.java:325) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao$ExecutionContextRowMapper.mapRow(JdbcExecutionContextDao.java:309) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:93) ~[spring-jdbc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:60) ~[spring-jdbc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:667) ~[spring-jdbc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:605) ~[spring-jdbc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:657) ~[spring-jdbc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:688) ~[spring-jdbc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:700) ~[spring-jdbc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:756) ~[spring-jdbc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao.getExecutionContext(JdbcExecutionContextDao.java:112) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.core.explore.support.SimpleJobExplorer.getJobExecutionDependencies(SimpleJobExplorer.java:202) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.core.explore.support.SimpleJobExplorer.getJobExecutions(SimpleJobExplorer.java:83) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_162]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_162]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_162]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_162]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:197) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at com.sun.proxy.$Proxy70.getJobExecutions(Unknown Source) ~[na:na]
    at org.springframework.batch.core.JobParametersBuilder.getNextJobParameters(JobParametersBuilder.java:264) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.execute(JobLauncherCommandLineRunner.java:162) ~[spring-boot-autoconfigure-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.executeLocalJobs(JobLauncherCommandLineRunner.java:179) ~[spring-boot-autoconfigure-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.launchJobFromProperties(JobLauncherCommandLineRunner.java:134) ~[spring-boot-autoconfigure-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.run(JobLauncherCommandLineRunner.java:128) ~[spring-boot-autoconfigure-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800) [spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]
    ... 5 common frames omitted
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: 9] (through reference chain: java.util.HashMap["map"])
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59) ~[jackson-databind-2.9.6.jar:2.9.6]
    at com.fasterxml.jackson.databind.DeserializationContext.wrongTokenException(DeserializationContext.java:1498) ~[jackson-databind-2.9.6.jar:2.9.6]
    at com.fasterxml.jackson.databind.DeserializationContext.reportWrongTokenException(DeserializationContext.java:1273) ~[jackson-databind-2.9.6.jar:2.9.6]
    at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._locateTypeId(AsArrayTypeDeserializer.java:151) ~[jackson-databind-2.9.6.jar:2.9.6]
    at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:96) ~[jackson-databind-2.9.6.jar:2.9.6]
    at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromAny(AsArrayTypeDeserializer.java:71) ~[jackson-databind-2.9.6.jar:2.9.6]
    at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserializeWithType(UntypedObjectDeserializer.java:712) ~[jackson-databind-2.9.6.jar:2.9.6]
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:529) ~[jackson-databind-2.9.6.jar:2.9.6]
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:364) ~[jackson-databind-2.9.6.jar:2.9.6]
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:29) ~[jackson-databind-2.9.6.jar:2.9.6]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013) ~[jackson-databind-2.9.6.jar:2.9.6]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3077) ~[jackson-databind-2.9.6.jar:2.9.6]
    at org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer.deserialize(Jackson2ExecutionContextStringSerializer.java:70) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer.deserialize(Jackson2ExecutionContextStringSerializer.java:50) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao$ExecutionContextRowMapper.mapRow(JdbcExecutionContextDao.java:322) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE]
    ... 34 common frames omitted

CommonConfig.java

@Configuration
@ComponentScan("com.XXXX")
@EnableBatchProcessing
@EnableScheduling
@PropertySource("classpath:database.properties")
@ImportResource({ "classpath:jobs/XYZ.xml"})
public class CommonConfig {
    @Bean
    BatchConfigurer configurer(@Qualifier("dataSource") DataSource dataSource) {
        return new DefaultBatchConfigurer(dataSource);
    }
}

XYZ.xml

<bean id = "databaseConfig" class = "com.XX.config.DatabaseConfig" />

    <bean id = "transactionManager" class = "org.springframework.batch.support.transaction.ResourcelessTransactionManager" />

    <bean id = "job_Repository" class = "org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
        <property name = "transactionManager" ref = "transactionManager" />
    </bean>

    <bean id = "jobLauncher" class = "org.springframework.batch.core.launch.support.SimpleJobLauncher">
        <property name = "jobRepository" ref = "job_Repository" />
    </bean>

    <bean id = "stepScope" class = "org.springframework.batch.core.scope.StepScope">
        <property name = "autoProxy" value = "true"/>
    </bean>

    <batch:job id = "myXYZBatchJob">
        <batch:step id = "XYZContextStep" >
            <batch:tasklet ref=XYZContextTasklet" />
        </batch:step>
    </batch:job>
    ......
    ........
</bean>

DatabaseConfig.java

@Configuration
@EnableTransactionManagement
@ComponentScan({ "com.XXX" })
@EnableJpaRepositories(basePackages = {"com.XX.repository", "com.XX.custom.repository"}, 
                        entityManagerFactoryRef = "entityManagerFactory", 
                        transactionManagerRef = "transactionManager")
public class DatabaseConfig {
    @Bean
    @Primary
    @ConfigurationProperties("abc.datasource")
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

    @Primary
    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "abc.datasource")
    public DataSource dataSource() {
        return dataSourceProperties().initializeDataSourceBuilder().build();
    }

    @Primary
    @Bean(name = "entityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("dataSource") DataSource dataSource) {

        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource);
        em.setPackagesToScan(new String[] { "com.XX.Entity" });
        em.setPersistenceUnitName("devcloud");

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        return em;
    }

    @Primary
    @Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager(@Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

РЕДАКТИРОВАТЬ-1: Я использую последнюю версию Spring Boot Parent 2.0.4.RELEASE. Он извлекает все версии Spring, включая контекстную версию 5.0.8.RELEASE.

Попросите вас опубликовать фрагмент кода и подробное описание в поддержку вашего ответа.

Редактировать-2:

public class BillingConfig implements BatchConfigurer{

    private PlatformTransactionManager transactionManager;
    private JobRepository jobRepository;
    private JobLauncher jobLauncher;
    private JobExplorer jobExplorer;

    @Override
    public JobRepository getJobRepository() {
        return jobRepository;
    }

    @Override
    public PlatformTransactionManager getTransactionManager() {
        return transactionManager;
    }

    @Override
    public JobLauncher getJobLauncher() throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {
        return jobLauncher;
    }

    @Override
    public JobExplorer getJobExplorer() {
        return jobExplorer;
    }

    @PostConstruct
    void initialize() throws Exception {
        if (this.transactionManager == null) {
            this.transactionManager = new ResourcelessTransactionManager();
        }

        // A FactoryBean that automates the creation of a SimpleJobRepository using non-persistent in-memory DAO implementations. 
        MapJobRepositoryFactoryBean jobRepositoryFactory = new MapJobRepositoryFactoryBean(this.transactionManager);
        jobRepositoryFactory.afterPropertiesSet();
        this.jobRepository = jobRepositoryFactory.getObject();

        // A FactoryBean that automates the creation of a SimpleJobRepository using non-persistent in-memory DAO implementations. 
        MapJobExplorerFactoryBean jobExplorerFactory = new MapJobExplorerFactoryBean(jobRepositoryFactory);
        jobExplorerFactory.afterPropertiesSet();
        this.jobExplorer = jobExplorerFactory.getObject();
        this.jobLauncher = createJobLauncher();
    }

    private JobLauncher createJobLauncher() throws Exception {
        SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
        simpleJobLauncher.setJobRepository(jobRepository);
        simpleJobLauncher.afterPropertiesSet();
        return simpleJobLauncher;
    }
}

В какой версии был сериализован контекст выполнения? Если он был сериализован с версией 3 (возможно, это было старое исполнение, которое у вас было в вашей базе данных перед миграцией, например), и теперь вы работаете с версией 4, эта ошибка может произойти (из-за изменения библиотеки сериализации с XStream на Jackson на default, который указан в ответе Майкла, на который вы ссылаетесь). Итак, знаете ли вы, с какой версией был сериализован контекст выполнения?

Mahmoud Ben Hassine 26.08.2018 18:33

@ Махмуд Бен Хассин - Обратитесь к EDIT-1

Jeff Cook 27.08.2018 07:17

Эта ошибка возникает, когда контекст выполнения вашего задания сериализуется с версией 3 (с использованием XStream по умолчанию), а затем десериализуется с версией 4 (с использованием Джексона по умолчанию). Поэтому либо понизьте версию Spring Batch до версии 3, либо настройте репозиторий заданий для использования XStreamExecutionContextStringSerializer (см. jobRepositoryFactoryBean.setSerializer(new XStreamExecutionContextStringSerializer());).

Mahmoud Ben Hassine 27.08.2018 10:09

Да, я знаю это, но ваш ответ не подсказывает, какой именно код нужно добавить. Мне это нужно в ответ

Jeff Cook 27.08.2018 11:05

Я добавил ответ с образцом кода.

Mahmoud Ben Hassine 27.08.2018 12:29
4
5
8 043
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Эта ошибка возникает, когда контекст выполнения вашего задания сериализуется с версией 3 (с использованием XStream по умолчанию), а затем десериализуется с версией 4 (с использованием Jackson по умолчанию). Поэтому либо понизьте версию Spring Batch до версии 3, либо настройте репозиторий заданий для использования XStreamExecutionContextStringSerializer.

В вашем случае вы уже определили bean-компонент типа BatchConfigurer, поэтому вы можете переопределить метод createJobRepository и настроить сериализатор XStream. Например:

@Bean
BatchConfigurer configurer(@Qualifier("dataSource") DataSource dataSource, PlatformTransactionManager transactionManager) {
    return new DefaultBatchConfigurer(dataSource) {
        @Override
        protected JobRepository createJobRepository() throws Exception {
            JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
            factory.setDataSource(dataSource);
            factory.setTransactionManager(transactionManager);
            factory.setSerializer(new XStreamExecutionContextStringSerializer());
            factory.afterPropertiesSet();
            return factory.getObject();
        }
    };
}

@Hassine - Еще одна вещь: XStreamExecutionContextStringSerializer устарел в 4.0.1.

Jeff Cook 27.08.2018 22:16

@Hassine - Большое спасибо! Обратитесь к Edit-2 и подскажите, где настроить код? -

Jeff Cook 27.08.2018 22:16

MapJobRepositoryFactoryBean не предоставляет метод настройки сериализатора, поскольку этот репозиторий заданий не сериализует и не сохраняет данные в постоянном хранилище. Итак, я смущен вашим EDIT-2 о том, как вы можете получить это исключение с репозиторием заданий в памяти.

Mahmoud Ben Hassine 22.02.2019 20:52

@MahmoudBenHassine Я добавил код, который вы предложили исправить проблему десериализации localDateTime, и он сработал, но я получаю исключение при десериализации карты со значением объекта как ExecutionContext (добавлено анализатором), есть ли способ исправить это?. Вызвано: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Отсутствует идентификатор типа при попытке разрешить подтип [тип карты; класс java.util.HashMap, [простой тип, класс java.lang.String] -> [простой тип, класс java.lang.Object]]: отсутствует свойство идентификатора типа '@class' в [Источник: (ByteArrayInputStream); строка: 1, столбец: 1274]

gzp___ 13.08.2020 12:45

@gzp___ Это еще одна (не связанная) проблема, см. stackoverflow.com/questions/62718203/…

Mahmoud Ben Hassine 13.08.2020 13:21

@MahmoudBenHassine, спасибо, что указал мне на поток, я обнаружил, что при использовании jobExplorer, как в моем случае, тот же сериализатор (с использованием javaTimeModule) должен быть добавлен также в jobExplorer, поэтому класс конфигурации клиента должен переопределить метод createJobExplorer и установить то же самое. сериализатор там

gzp___ 13.08.2020 14:40

Попробуйте очистить таблицы весеннего дозирования. Используйте следующую ссылку: - очистка пружинных столиков замеса ---- http://forum.spring.io/forum/spring-projects/batch/122103-clean-spring-batch-metadata-tables

Хотя эта ссылка может дать ответ на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если ссылка на страницу изменится.

Devendra Singh 21.09.2018 14:41

На Prod вы не можете очистить данные. Принятый ответ выглядит правильным подходом

Jeff Cook 21.09.2018 17:59

Поскольку XStreamExecutionContextStringSerializer устарел в последней версии Spring BATCH.

Если вы добавляете сложный объект в Execution Context, проверьте, является ли объект, который вы пытаетесь добавить, Serializable.

Например, если ваш класс выглядит так:

class Sample{
String data;
List<DataItem> dataItems;

}

Убедитесь, что DataItem, который присутствует внутри объекта, также является Serializable.

Это помогло мне решить мою проблему.

В дополнение к этому вам, возможно, придется очистить все предыдущие метаданные контекста выполнения пакета, которые были добавлены из-за несериализуемого объекта.

Nirmal Kumar 02.07.2019 21:25

Другие вопросы по теме