Spring Boot单元测试中ImageIO找不到阅读器问题求助
解决Spring Boot单元测试中ImageIO "No reader found" 问题
首先,我注意到你的测试失败有两个核心原因,咱们一步步来拆解解决:
1. 首要问题:InputStream被重复读取导致数据为空
在resizeJpgTest方法里,你把同一个InputStream先传给getExifData(is)读取原始EXIF,接着又传给adapter.resize(is, 800)做缩放——这时候流的指针已经走到末尾了,resize拿到的是空流,生成的结果自然是无效的JPEG数据,ImageIO根本没法识别,所以抛出"No reader found"。
修复方法:复制流数据,避免重复使用
先把图片资源读入字节数组,再分别生成新的InputStream供EXIF读取和缩放使用,确保每次操作都有完整的数据流:
@Test public void resizeJpgTest() throws IOException, ResizeException { Resource resource = new ClassPathResource("img/test2.jpg"); Assert.assertNotNull("image to check resize exists", resource); Assert.assertTrue("image to check resize exists", resource.exists()); // 先把图片读入字节数组,避免流重复使用导致数据为空 byte[] imageBytes = Files.readAllBytes(resource.getFile().toPath()); // 读取原始EXIF数据 try (ByteArrayInputStream exifIs = new ByteArrayInputStream(imageBytes)) { CompoundDirectory sourceExif = getExifData(exifIs); Assert.assertNotNull("Source exif have been read", sourceExif); } // 执行缩放操作 try (ByteArrayInputStream resizeIs = new ByteArrayInputStream(imageBytes)) { var result = adapter.resize(resizeIs, 800); // 验证缩放结果 try (var resultIs = new ByteArrayInputStream(result)) { ImageInputStream imageIs = ImageIO.createImageInputStream(resultIs); Iterator<ImageReader> readers = ImageIO.getImageReaders(imageIs); if (!readers.hasNext()) { throw new IllegalArgumentException("No reader found"); } ImageReader reader = readers.next(); reader.setInput(imageIs); Assert.assertEquals("JPEG", reader.getFormatName()); // 重置结果流指针,重新读取EXIF数据 resultIs.reset(); CompoundDirectory exif = getExifData(resultIs); Assert.assertNotNull(exif); Assert.assertTrue("width should be <= 800 now", reader.getWidth(0) <= 800); Assert.assertTrue("height should be <= 800 now", reader.getHeight(0) <= 800); Assert.assertEquals("Orientation has not changed", 5, exif.getEntryByFieldName("orientation").getValue()); } } catch (Exception e) { throw new RuntimeException("error while reading result", e); } }
2. 确保TwelveMonkeys ImageIO插件在测试环境正确注册
虽然你在init方法里调用了插件扫描,但Spring Boot测试的类加载器可能有特殊处理,导致SPI没有被正确发现。可以显式注册TwelveMonkeys的SPI实现,确保测试环境能加载到阅读器:
@Before public void init() { IIORegistry registry = IIORegistry.getDefaultInstance(); // 显式注册TwelveMonkeys的JPEG/TIFF读写SPI registry.registerServiceProvider(new JPEGImageReaderSpi()); registry.registerServiceProvider(new JPEGImageWriterSpi()); registry.registerServiceProvider(new TIFFImageReaderSpi()); registry.registerServiceProvider(new TIFFImageWriterSpi()); // 再执行一次插件扫描,确保没有遗漏 ImageIO.scanForPlugins(); }
3. 优化EXIF读取方法的流处理
你的getExifData方法里,流的生命周期管理可以更严谨,避免潜在的流泄漏或指针偏移问题:
private CompoundDirectory getExifData(InputStream inputStream) throws IOException { try (ImageInputStream imageIs = ImageIO.createImageInputStream(inputStream)) { List<JPEGSegment> exifSegments = JPEGSegmentUtil.readSegments(imageIs, JPEG.APP1, "Exif"); if (!exifSegments.isEmpty()) { InputStream exifData = exifSegments.get(0).data(); exifData.read(); // Skip 0-pad for Exif in JFIF try (ImageInputStream exifStream = ImageIO.createImageInputStream(exifData)) { return (CompoundDirectory) new TIFFReader().read(exifStream); } } } return null; }
额外建议
- 确保项目依赖中TwelveMonkeys的库是
compile/runtime范围,不是仅provided,测试环境需要能加载到这些类。 - 如果使用Spring Boot 2.4+,可以检查测试的类加载器配置,避免插件被类加载器隔离。
按照这些修改后,你的单元测试应该能正常运行,既可以正确读取EXIF数据,又能验证缩放后的图片尺寸和EXIF完整性。
内容的提问来源于stack exchange,提问作者mcfly
相关产品推荐
相关产品推荐

