Spring Batch No serializer found for class java.io.ByteArrayInputStream for oracle.sql.TIMESTAMP

Posted

技术标签:

【中文标题】Spring Batch No serializer found for class java.io.ByteArrayInputStream for oracle.sql.TIMESTAMP【英文标题】: 【发布时间】:2021-10-21 10:44:51 【问题描述】:

我使用 Spring Batch 并且有一个作业定义。我可以成功地从 db 中获取数据,但是在尝试处理第一个块后我的工作失败了。

我有一个JdbcPagingItemReader 并且有一个日期字段的排序定义:

    Map<String, Order> sortKeys = new HashMap<>();
    sortKeys.put("MY_DT", Order.ASCENDING);

    OraclePagingQueryProvider queryProvider = new OraclePagingQueryProvider();
    queryProvider.setSelectClause("---");
    queryProvider.setFromClause("FROM ---");
    queryProvider.setWhereClause("WHERE MY_DT >= :myDt");

但是我得到了这个错误:

Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.HashMap["JdbcPagingItemReader.start.after"]->java.util.LinkedHashMap["MY_DT"]->oracle.sql.TIMESTAMP["stream"])
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
    at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1277)
    at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:71)
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serializeWithType(UnknownSerializer.java:45)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:730)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeWithType(BeanSerializerBase.java:640)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeTypedFields(MapSerializer.java:941)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:696)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithoutTypeInfo(MapSerializer.java:681)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithType(MapSerializer.java:650)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithType(MapSerializer.java:33)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeTypedFields(MapSerializer.java:941)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:696)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithoutTypeInfo(MapSerializer.java:681)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithType(MapSerializer.java:650)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithType(MapSerializer.java:33)
    at com.fasterxml.jackson.databind.ser.impl.TypeWrappedSerializer.serialize(TypeWrappedSerializer.java:32)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
    at com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4409)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:3621)
    at org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer.serialize(Jackson2ExecutionContextStringSerializer.java:141)
    at org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer.serialize(Jackson2ExecutionContextStringSerializer.java:104)
    at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao.serializeContext(JdbcExecutionContextDao.java:302)

我认为这个问题与oracle.sql.TIMESTAMP 没有公共构造函数有关。因此,如果我将排序参数更改为非日期类型,一切都会像魅力一样。但是,即使我尝试自定义对象映射器,我也无法使其与日期排序一起使用。

有什么想法吗?

PS:作为一种解决方法,我尝试了这个但没有用:

@Configuration
public class JacksonObjectMapperConfiguration 

    @Bean
    @Primary
    public ObjectMapper objectMapper() 
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(TIMESTAMP.class, new OracleTimestampSerializer());
        mapper.registerModule(simpleModule);
        mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker()
                .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
                .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
        return mapper;
    

    private static class OracleTimestampSerializer extends JsonSerializer<TIMESTAMP> 
        @Override
        public void serializeWithType(oracle.sql.TIMESTAMP timestamp, JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSerializer) throws IOException 
            WritableTypeId typeId = typeSerializer.writeTypePrefix(gen, typeSerializer.typeId(timestamp, JsonToken.VALUE_EMBEDDED_OBJECT));
            serialize(timestamp, gen, serializers);
            gen.writeTypeSuffix(typeId);
            throw new RuntimeException("Error!");
        

        @Override
        public void serialize(oracle.sql.TIMESTAMP timestamp, JsonGenerator gen, SerializerProvider serializers) 
            try 
                gen.writeBinary(timestamp.getBytes());
                throw new RuntimeException("Error!");
             catch (IOException e) 
                System.out.println("serialize oracle.sql.Timestamp error :" + e.getMessage());
            
        
    

但是,也不会抛出运行时异常。

【问题讨论】:

这有帮助吗? ***.com/questions/60381349/… 很遗憾没有。我将使用与该问题相关的解决方法代码更新该问题。 【参考方案1】:

从您共享的堆栈跟踪中,我看到问题发生在执行上下文被序列化时。事实上,这是由于默认的 Jackson 映射器不知道如何(反)序列化时间戳。提供自定义映射器是要走的路。但是,为此,您需要在自定义实现中提供自定义 JobRepositoryJobRepositoryFactoryBean#setSerializer。仅在应用程序上下文中将序列化程序声明为 bean 是不够的(我们计划改进此 here,如果您有兴趣,请对该问题进行投票或评论)。您可以在Configuring a JobRepository 部分找到有关如何自定义作业存储库的更多详细信息。

在您的情况下,您需要提供自定义BatchConfigurer(或扩展DefaultBatchConfigurer)并实现getJobRepository(或覆盖createJobRepository),例如:

@Configuration
@EnableBatchProcessing
public class MyJobConfigWithCustomSerializer 

    @Bean
    public BatchConfigurer batchConfigurer(ObjectMapper objectMapper) 
        return new DefaultBatchConfigurer() 
            @Override
            public JobRepository createJobRepository() throws Exception 
                Jackson2ExecutionContextStringSerializer serializer = new Jackson2ExecutionContextStringSerializer();
                // customize serializer
                serializer.setObjectMapper(objectMapper);
                JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
                factory.setSerializer(serializer);
                // set other properties on the factory bean
                factory.afterPropertiesSet();
                return factory.getObject();
            
        
    


【讨论】:

以上是关于Spring Batch No serializer found for class java.io.ByteArrayInputStream for oracle.sql.TIMESTAMP的主要内容,如果未能解决你的问题,请参考以下文章

Spring Batch ORA-08177: 运行单个作业时无法序列化此事务的访问,SERIALIZED 隔离级别

Spring Batch 解决 Could not autowire. No beans of ‘StepBuilderFactory‘ type found.

萤石-module 'serial' has no attribute 'Serial'

解决AttributeError: module ‘serial‘ has no attribute ‘Serial‘

Batch - 忽略FORFILES “no files found” error

AttributeError:‘module‘ object has no attribute ‘Serial‘