Spring Boot 无法反序列化ExecutionContext:具有[... Class]且名称为[... Class]的类不受信任

nom7f22z  于 2023-01-05  发布在  Spring
关注(0)|答案(4)|浏览(326)

我使用的是SpringBoot 2.4.2和SpringBatch,反序列化失败,堆栈跟踪如下:

2021-03-29 15:51:28.529 ERROR 30308 --- [           main] o.s.boot.SpringApplication               : Application run failed
java.lang.IllegalArgumentException: Unable to deserialize the execution context
    at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao$ExecutionContextRowMapper.mapRow(JdbcExecutionContextDao.java:328) ~[spring-batch-core-4.3.1.jar:4.3.1]
    at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao$ExecutionContextRowMapper.mapRow(JdbcExecutionContextDao.java:312) ~[spring-batch-core-4.3.1.jar:4.3.1]
    at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94) ~[spring-jdbc-5.3.3.jar:5.3.3]
    at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61) ~[spring-jdbc-5.3.3.jar:5.3.3]
    at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:723) ~[spring-jdbc-5.3.3.jar:5.3.3]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:651) ~[spring-jdbc-5.3.3.jar:5.3.3]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:713) ~[spring-jdbc-5.3.3.jar:5.3.3]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:744) ~[spring-jdbc-5.3.3.jar:5.3.3]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:757) ~[spring-jdbc-5.3.3.jar:5.3.3]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:815) ~[spring-jdbc-5.3.3.jar:5.3.3]
    at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao.getExecutionContext(JdbcExecutionContextDao.java:129) ~[spring-batch-core-4.3.1.jar:4.3.1]
    at org.springframework.batch.core.explore.support.SimpleJobExplorer.getStepExecutionDependencies(SimpleJobExplorer.java:238) ~[spring-batch-core-4.3.1.jar:4.3.1]
    at org.springframework.batch.core.explore.support.SimpleJobExplorer.findRunningJobExecutions(SimpleJobExplorer.java:118) ~[spring-batch-core-4.3.1.jar:4.3.1]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:128) ~[spring-batch-core-4.3.1.jar:4.3.1]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.3.jar:5.3.3]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.3.jar:5.3.3]
    at com.sun.proxy.$Proxy222.findRunningJobExecutions(Unknown Source) ~[na:na]
    at com.xyz.onApplicationEvent(HandleJobsOnAppReady.java:50) ~[classes/:na]
    at com.xyz.onApplicationEvent(HandleJobsOnAppReady.java:24) ~[classes/:na]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176) ~[spring-context-5.3.3.jar:5.3.3]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169) ~[spring-context-5.3.3.jar:5.3.3]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143) ~[spring-context-5.3.3.jar:5.3.3]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:426) ~[spring-context-5.3.3.jar:5.3.3]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:383) ~[spring-context-5.3.3.jar:5.3.3]
    at org.springframework.boot.context.event.EventPublishingRunListener.running(EventPublishingRunListener.java:111) ~[spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplicationRunListeners.lambda$running$6(SpringApplicationRunListeners.java:79) ~[spring-boot-2.4.2.jar:2.4.2]
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) ~[na:na]
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:117) ~[spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:111) ~[spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplicationRunListeners.running(SpringApplicationRunListeners.java:79) ~[spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:341) ~[spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311) ~[spring-boot-2.4.2.jar:2.4.2]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) ~[spring-boot-2.4.2.jar:2.4.2]
    at com.xyz.Application.main(XYZApplication.java:18) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:578) ~[na:na]
    at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Caused by: com.fasterxml.jackson.databind.JsonMappingException: The class with [xyz.Class; and name of [xyz.Class; is not trusted. If you believe this class is safe to deserialize, you can add it to the base set of trusted classes at construction time or provide an explicit mapping using Jackson annotations or a custom ObjectMapper. If the serialization is only done by a trusted source, you can also enable default typing. (through reference chain: java.util.HashMap["partition"])
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:397) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:356) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.deser.std.ContainerDeserializerBase.wrapAndThrow(ContainerDeserializerBase.java:181) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:552) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:377) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:29) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:132) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:99) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserializeWithType(MapDeserializer.java:413) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:68) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4526) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3513) ~[jackson-databind-2.11.4.jar:2.11.4]
    at org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer.deserialize(Jackson2ExecutionContextStringSerializer.java:133) ~[spring-batch-core-4.3.1.jar:4.3.1]
    at org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer.deserialize(Jackson2ExecutionContextStringSerializer.java:104) ~[spring-batch-core-4.3.1.jar:4.3.1]
    at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao$ExecutionContextRowMapper.mapRow(JdbcExecutionContextDao.java:325) ~[spring-batch-core-4.3.1.jar:4.3.1]
    ... 46 common frames omitted
Caused by: java.lang.IllegalArgumentException: The class with [xyz.Class; and name of [xyz.Class; is not trusted. If you believe this class is safe to deserialize, you can add it to the base set of trusted classes at construction time or provide an explicit mapping using Jackson annotations or a custom ObjectMapper. If the serialization is only done by a trusted source, you can also enable default typing.
    at org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer$TrustedTypeIdResolver.typeFromId(Jackson2ExecutionContextStringSerializer.java:349) ~[spring-batch-core-4.3.1.jar:4.3.1]
    at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._findDeserializer(TypeDeserializerBase.java:154) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:97) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromArray(AsArrayTypeDeserializer.java:53) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromAny(AsPropertyTypeDeserializer.java:193) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserializeWithType(UntypedObjectDeserializer.java:710) ~[jackson-databind-2.11.4.jar:2.11.4]
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:542) ~[jackson-databind-2.11.4.jar:2.11.4]
    ... 57 common frames omitted

这个错误很明显,我读了很多关于它的书,但是我不能解决它。
我在BatchConfiguration中添加了一个类型为ExecutionContextSerializer的bean,但它似乎不起作用:

@Bean
public ExecutionContextSerializer customSerializer(){
    return new Jackson2ExecutionContextStringSerializer(ClassToBeTrusted.class.getName());
}

@Bean
public JobRepository createJobRepository(DataSource dataSource,ExecutionContextSerializer executionContextSerializer) throws Exception {
    JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
    factory.setDataSource(dataSource);
    factory.setTransactionManager(getTransactionManager());
    factory.setSerializer(executionContextSerializer);
    factory.afterPropertiesSet();
    return factory.getObject();
}

出现错误的情况如下:

@Override
    public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {

        Set<JobExecution> runningJobExecutions = jobExplorer.findRunningJobExecutions(job.getName());

被执行。

    • 更新:**BatchConfiguration类现在实现DefaultBatchConfigurer类,并覆盖getJobRepository和getJobExplorer(不确定是否有必要?),如下所示:
@Override
    public JobRepository getJobRepository() {
        try {
            JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
            factory.setDataSource(datasource);
            factory.setTransactionManager(getTransactionManager());
            factory.setSerializer(customSerializer());
            factory.afterPropertiesSet();
            return factory.getObject();
        }

        catch(Exception e){
            throw new BatchConfigurationException(e);
        }
    }

    @Override
    public JobExplorer getJobExplorer(){
        try{
            JobExplorerFactoryBean factory = new JobExplorerFactoryBean();
            factory.setSerializer(customSerializer());
            factory.setDataSource(datasource);
            factory.afterPropertiesSet();
            return factory.getObject();
        }
        catch(Exception e ){
            throw new BatchConfigurationException(e);
        }
    }

不幸的是,我仍然看到反序列化错误:Myclass不受信任...如上所述。

kcrjzv8t

kcrjzv8t1#

根据Christian的回答,下面是如何重写默认串行化器。

package com.my.path.to.config;

import com.my.path.to.entity.MyEntity;
import org.springframework.batch.core.configuration.annotation.BatchConfigurer;
import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.ExecutionContextSerializer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

@Configuration
public class BatchConfiguration {

    @Bean
    public ExecutionContextSerializer customSerializer() {
        return new Jackson2ExecutionContextStringSerializer(MyEntity.class.getName());
    }

    @Bean
    BatchConfigurer myBatchConfigurer(@Qualifier("batchDataSource") DataSource dataSource,
                                      ExecutionContextSerializer executionContextSerializer,
                                      PlatformTransactionManager transactionManager) {
        return new DefaultBatchConfigurer(dataSource) {
            @Override
            protected JobExplorer createJobExplorer() throws Exception {
                JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
                jobExplorerFactoryBean.setDataSource(dataSource);
                jobExplorerFactoryBean
                                .setSerializer(executionContextSerializer);
                jobExplorerFactoryBean.afterPropertiesSet();
                return jobExplorerFactoryBean.getObject();
            }

            @Override
            protected JobRepository createJobRepository() throws Exception {
                JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
                jobRepositoryFactoryBean.setDataSource(dataSource);
                jobRepositoryFactoryBean
                                .setSerializer(executionContextSerializer);
                jobRepositoryFactoryBean.setTransactionManager(transactionManager);
                jobRepositoryFactoryBean.afterPropertiesSet();
                return jobRepositoryFactoryBean.getObject();
            }
        };
    }
}
bbuxkriu

bbuxkriu2#

要注册自定义JobRepository,您需要提供Batchconfigurer并覆盖getJobRepository。配置和运行作业部分对此进行了说明:

You can customize any of these beans by creating a custom implementation
of the BatchConfigurer interface. Typically, extending the DefaultBatchConfigurer 
(which is provided if a BatchConfigurer is not found) and overriding
the required getter is sufficient.

在您的例子中,您声明了一个JobRepository类型的bean,并期望Spring Batch将其考虑在内,这是不够的,您需要使您的批处理配置类实现BatchConfigurer或扩展DefaultBatchConfigurer

t9aqgxwy

t9aqgxwy3#

我可以通过调试Jackson2ExecutionContextStringSerializer和它的isTrusted逻辑来解决这个问题,最后我不得不将类型化数组和类添加到受信任类列表中,如下所示:

public ExecutionContextSerializer customSerializer() {
    return new Jackson2ExecutionContextStringSerializer(new MyClass[0].getClass().getName(), MyClass.class.getName());
}

当我看到将[L<fullyQualifiedClassName>fullyQualifiedClassName进行比较时,我意识到了这个问题

cgh8pdjw

cgh8pdjw4#

我得到了同样的错误,因为一个类,从另一个类的扩展。我添加了Jackson注解,并添加了所有字段和空构造函数的getter和setter,现在它是工作良好。你可以得到下面的代码的想法

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
class A{
    private String name;

    public A() {
    }

    public A(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

class B extends A{
    private String param;

    public B() {
    }

    public B(String name, String param) {
        super(name);
        this.param = param;
    }

    public String getParam() {
        return param;
    }

    public void setParam(String param) {
        this.param = param;
    }
}sssssssssssssssssssssssss

相关问题