【问题标题】:How to resolve ClassCastException in MultiResourceItemReader Spring Batch如何解决 MultiResourceItemReader Spring Batch 中的 ClassCastException
【发布时间】:2022-01-17 04:12:46
【问题描述】:

我正在使用 MultiResourceItemReader 从 S3 存储桶中读取多个文件,在执行 myReader() 方法之前我得到了 ClassCastException MultiResourceItemReader 有问题,不确定这里出了什么问题。

请在下面找到我的代码:

                @Bean
                public MultiResourceItemReader<String> multiResourceReader()
                {
                    String bucket = "mybucket;
                    String key = "/myfiles";
                
                    List<InputStream> resourceList = s3Client.getFiles(bucket, key);
                    List<InputStreamResource> inputStreamResourceList = new ArrayList<>();
                    for (InputStream s: resourceList) {
                        inputStreamResourceList.add(new InputStreamResource(s));
                    }
            
            Resource[] resources = inputStreamResourceList.toArray(new InputStreamResource[inputStreamResourceList.size()]);
        //InputStreamResource[] resources = inputStreamResourceList.toArray(new InputStreamResource[inputStreamResourceList.size()]);
            
            // I'm getting all the stream content - I verified my stream is not null
                    for (int i = 0; i < resources.length; i++) {
                        try {
                            InputStream s  = resources[i].getInputStream();
                            String result = IOUtils.toString(s, StandardCharsets.UTF_8);
                            System.out.println(result);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
            
                    MultiResourceItemReader<String> resourceItemReader = new MultiResourceItemReader<>();
                    resourceItemReader.setResources(resources);
                    resourceItemReader.setDelegate(myReader());
                    
    resourceItemReader.setDelegate((ResourceAwareItemReaderItemStream<? extends String>) new CustomComparator()); 
                    return resourceItemReader;
                }
        
        
          

例外:

Caused by: java.lang.ClassCastException: class CustomComparator cannot be cast to class org.springframework.batch.item.file.ResourceAwareItemReaderItemStream (CustomComparator and org.springframework.batch.item.file.ResourceAwareItemReaderItemStream are in unnamed module of loader org.springframework.boot.loader.LaunchedURLClassLoader @cc285f4)
        at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
        at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
        ... 65 common frames omitted

谁能帮我解决这个问题。提前感谢您的帮助。谢谢。

【问题讨论】:

    标签: spring spring-batch spring-batch-tasklet spring-batch-stream


    【解决方案1】:

    您看到 NullPointerException 的原因是 MultiResourceItemReader 使用默认比较器在加载资源后对资源进行排序。

    默认比较行为调用 InputStreamResource 的getFilename() 方法。

    参考 - https://github.com/spring-projects/spring-batch/blob/115c3022147692155d45e23cdd5cef84895bf9f5/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemReader.java#L82

    但是 InputStreamResource 只是从其父 AbstractResource 继承了 getFileName() 方法,它只返回 null。 https://github.com/spring-projects/spring-framework/blob/316e84f04f3dbec3ea5ab8563cc920fb21f49749/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java#L220

    解决方案是为 MultiResourceItemReader 提供自定义比较器。这是一个简单的示例,假设您不想在处理之前以特定方式对资源进行排序:

    public class CustomComparator implements Comparator<InputStream>{
    
            @Override
            public int compare(InputStream is1, InputStream is2) {
           //comparing based on last modified time
                return Long.compare(is1.hashCode(),is2.hashCode());
       }
    }
    
    MultiResourceItemReader<String> resourceItemReader = new MultiResourceItemReader<>();
    resourceItemReader.setResources(resources);
    resourceItemReader.setDelegate(myReader());
    //UPDATED with correction - set custom Comparator
    resourceItemReader.setComparator(new CustomComparator());
    

    请参阅此答案以了解 Spring Batch MultiResourceItemReader 如何使用 Comparator。

    File processing order with Spring Batch

    【讨论】:

    • 感谢@Shankar P S。我添加了 CustomComparator 类并像这样添加了resourceItemReader.setDelegate((ResourceAwareItemReaderItemStream&lt;? extends String&gt;) new CustomComparator()); - 但我收到了ClassCastException Caused by: java.lang.ClassCastException: class CustomComparator cannot be cast to class org.springframework.batch.item.file.ResourceAwareItemReaderItemStream (CustomComparator and org.springframework.batch.item.file.ResourceAwareItemReaderItemStream - 请帮我解决这个问题。用新代码和异常更新了我原来的帖子
    • @MikeMarsh 我的回答有误。它应该是 resourceItemReader.setDelegate()。我已经纠正了。请立即尝试。
    • 嗨@Shankar P S 我添加了这一行resourceItemReader.setComparator(new CustomComparator());,但得到了编译错误Required type: Comparator &lt;org.springframework.core.io.Resource&gt;在CustomComparator类中,如果我更改为Comparator&lt;Resource&gt;,我们给出了Comparator&lt;InputStream&gt;编译错误消失但得到这个运行时异常IllegalStateException: InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times 如何解决这个问题?任何帮助将非常感激。谢谢!
    • 这是因为您的调试代码,您正在读取输入流列表以验证它们是否有效。删除您在评论“我验证我的流不为空”后添加的 for 循环。 Spring Batch 无法再次读取它,因为它假定它已被读取。
    • 非常感谢 - 它奏效了。我想在这里澄清一件事 - 如果我有 100 个文件,在一个目录中 - MultiResourceItemReader 会读取所有这些文件并按顺序处理它们吗?如果是,我们如何配置它以读取前 50 个文件,然后读取剩余的 50 个文件?因为如果我们一起读取所有 100 个文件并进行处理 - 不确定是否会出现内存不足的问题。请建议您的方法?
    猜你喜欢
    • 1970-01-01
    • 2015-10-27
    • 2016-07-10
    • 1970-01-01
    • 1970-01-01
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多