从 XSD 解组 XML 失败,JAR 执行时显示“java.io.IOException:缓冲区已关闭”

Unmarshal XML from XSD failed with JAR Execution with "java.io.IOException: Buffer already closed"

提问人:Broshet 提问时间:11/2/2023 更新时间:11/2/2023 访问量:40

问:

我有一个 java 代码,可以从 PDF (Apache PDFBox) 中提取 Xml 部分并将其解组到 java 类中。

在使用 IntelliJ 进行本地执行时,一切正常,但是当我在 openshift 集群上部署 jar 时,unmarshal 是 ko with “java.io.IOException: Buffer already closed”

从我的 PDF 中提取了一个列表

然后,我创建一个像这样的 unmarshal:

try {
      JAXBContext context = JAXBContext.newInstance(typeClasse.getClass());
      Unmarshaller unmarshaller = context.createUnmarshaller();
      SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
      String xsdFilePath = getXSD();
      Schema schema = factory.newSchema(this.getClass().getResource("/" + xsdFilePath));
      unmarshaller.setSchema(schema);
      unmarshaller.setEventHandler(event -> false);
      return unmarshaller;
    } catch (JAXBException | SAXException e) {
      throw new UnmarshallException(e);
    }

typeClasse 是我的输出 unmarshall 类,getXSD() 为我提供根 XSD 定义的路径,我所有的 XSD 都在资源 java 文件夹上的同一目录“xsd”上,getXSD() 返回的一个包含所有其他。路径类似于“xsd/myparentXSD.xsd”

然后,使用我的 List (myList) 执行此代码,返回一个 List,其中 T 是 typeClasse。

myList.stream()
        .map(myObject -> unmarshallFichier(myObject, unmarshaller))
        .collect(Collectors.toList());

unmarshaller 是下面的一个细节,unmarshallFichier 是:

try {
  StreamSource stream = new StreamSource(myObject);
  JAXBElement<?> jaxbElement = unmarshaller.unmarshal(stream, typeClasse.getClass());
  return (T) jaxbElement.getValue();
} catch (JAXBException e) {
  throw new UnmarshallException(e);
}

但是在 openshift 上,这段代码是错误的,并产生 java.io.IOException: Buffer already closed (but not inc local)

这是怎么回事?

Java XML XSD 解组

评论

0赞 JCompetence 11/2/2023
这可能不是 openshift 问题,而是您的 docker 映像的外观。尝试从 docker 内部运行它,例如 docker run -it yourimage sh。 然后在终端内运行您的 java 类并实际查看包含 XSD 的文件夹
0赞 Broshet 11/2/2023
我有在 openshift 上部署的提取 jar 文件,XSD 正确位于 myJar.jar\BOOT-INF\classes\xsd\ 文件夹中

答:

1赞 lance-java 11/2/2023 #1
StreamSource stream = new StreamSource(myObject);

在这种情况下是什么?是 InputStream 还是 ReadermyObject

从例外情况来看,我感觉您正在尝试从一个或多个次中阅读。ReaderInputStream

请注意,您只能从 InputStream / Reader 读取一次。

也许您想执行以下操作,以便在每次迭代列表时创建一个新列表?InputStream

public interface InputStreamSource {
   InputStream get() throws IOException;
}

public class MyClass {
   // myList is a long-lived object and can be iterated multiple times
   // since we create a new InputStream each time we call InputStreamSource.get() 
   private final List<InputStreamSource> myList = List.of(
      () -> new FileInputStream("path/to/file1.xml"),
      () -> new FileInputStream("path/to/file2.xml")
   );

   public List<Object> doIt() {
      return myList.stream()
         .map(myObject -> unmarshallFichier(myObject, unmarshaller))
         .collect(Collectors.toList());
   }

   private Object unmarshallFichier(InputStreamSource streamSource, Unmarshaller unmarshaller) {
      try (InputStream in = streamSource.get()) {
         StreamSource stream = new StreamSource(in);
         JAXBElement<?> jaxbElement = unmarshaller.unmarshal(stream, typeClasse.getClass());
         return (T) jaxbElement.getValue();
      } catch (JAXBException e) {
         throw new UnmarshallException(e);
      }
   }
}  

评论

0赞 Broshet 11/2/2023
myObject 是一个 InputStream。但是为什么本地执行是可以的,而 jar 执行是 KO ?
0赞 Broshet 11/2/2023
为什么使用 List<InputStreamSource> ?我的 XML 位于 List<InputStream 中>
0赞 lance-java 11/2/2023
List<InputStream>如果要多次迭代列表,则会出现问题。每个只能从一次读取。在你读完之后,它应该被丢弃,因为它在这一点上是无用的InputStreamInputStream
0赞 Broshet 11/2/2023
好的,但我在 InputStream 上只有 InputStream 要阅读,不多。myObject 必须只包含一个要取消封送的 xml。我不明白我的 Inpustream 在哪里被读取了两次......
0赞 lance-java 11/2/2023
也许当你在 intellij 中运行时,你只从一次读取。但是在 openshift 上,进程运行的时间更长,并且代码在同一实例上执行第二次/第三次?InputStreamInputStream