Я разрабатываю подход на основе 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;
}
}
@ Махмуд Бен Хассин - Обратитесь к EDIT-1
Эта ошибка возникает, когда контекст выполнения вашего задания сериализуется с версией 3 (с использованием XStream по умолчанию), а затем десериализуется с версией 4 (с использованием Джексона по умолчанию). Поэтому либо понизьте версию Spring Batch до версии 3, либо настройте репозиторий заданий для использования XStreamExecutionContextStringSerializer (см. jobRepositoryFactoryBean.setSerializer(new XStreamExecutionContextStringSerializer());).
Да, я знаю это, но ваш ответ не подсказывает, какой именно код нужно добавить. Мне это нужно в ответ
Я добавил ответ с образцом кода.
Эта ошибка возникает, когда контекст выполнения вашего задания сериализуется с версией 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.
@Hassine - Большое спасибо! Обратитесь к Edit-2 и подскажите, где настроить код? -
MapJobRepositoryFactoryBean не предоставляет метод настройки сериализатора, поскольку этот репозиторий заданий не сериализует и не сохраняет данные в постоянном хранилище. Итак, я смущен вашим EDIT-2 о том, как вы можете получить это исключение с репозиторием заданий в памяти.
@MahmoudBenHassine Я добавил код, который вы предложили исправить проблему десериализации localDateTime, и он сработал, но я получаю исключение при десериализации карты со значением объекта как ExecutionContext (добавлено анализатором), есть ли способ исправить это?. Вызвано: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Отсутствует идентификатор типа при попытке разрешить подтип [тип карты; класс java.util.HashMap, [простой тип, класс java.lang.String] -> [простой тип, класс java.lang.Object]]: отсутствует свойство идентификатора типа '@class' в [Источник: (ByteArrayInputStream); строка: 1, столбец: 1274]
@gzp___ Это еще одна (не связанная) проблема, см. stackoverflow.com/questions/62718203/…
@MahmoudBenHassine, спасибо, что указал мне на поток, я обнаружил, что при использовании jobExplorer, как в моем случае, тот же сериализатор (с использованием javaTimeModule) должен быть добавлен также в jobExplorer, поэтому класс конфигурации клиента должен переопределить метод createJobExplorer и установить то же самое. сериализатор там
Попробуйте очистить таблицы весеннего дозирования. Используйте следующую ссылку: - очистка пружинных столиков замеса ---- http://forum.spring.io/forum/spring-projects/batch/122103-clean-spring-batch-metadata-tables
Хотя эта ссылка может дать ответ на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если ссылка на страницу изменится.
На Prod вы не можете очистить данные. Принятый ответ выглядит правильным подходом
Поскольку XStreamExecutionContextStringSerializer устарел в последней версии Spring BATCH.
Если вы добавляете сложный объект в Execution Context, проверьте, является ли объект, который вы пытаетесь добавить, Serializable.
Например, если ваш класс выглядит так:
class Sample{
String data;
List<DataItem> dataItems;
}
Убедитесь, что DataItem, который присутствует внутри объекта, также является Serializable.
Это помогло мне решить мою проблему.
В дополнение к этому вам, возможно, придется очистить все предыдущие метаданные контекста выполнения пакета, которые были добавлены из-за несериализуемого объекта.
В какой версии был сериализован контекст выполнения? Если он был сериализован с версией 3 (возможно, это было старое исполнение, которое у вас было в вашей базе данных перед миграцией, например), и теперь вы работаете с версией 4, эта ошибка может произойти (из-за изменения библиотеки сериализации с XStream на Jackson на default, который указан в ответе Майкла, на который вы ссылаетесь). Итак, знаете ли вы, с какой версией был сериализован контекст выполнения?