Java class loader bug: Caused by: java.io.IOException: Stream closed

≡放荡痞女 提交于 2020-03-19 08:07:53

问题


I'm getting a strange bug regarding I believe class loader issues when I deploy my webapp to Tomcat. The bug doesn't appear when I run my webapp locally using Jetty. It seems like my input streams for my .yml resource files are being closed for some reason when they shouldn't be. This bug first appeared when I tried to convert my single module project into a multi module project. Before that, it was working fine on Tomcat using the exact same code:

Caused by: org.yaml.snakeyaml.error.YAMLException: java.io.IOException: Stream closed
    at org.yaml.snakeyaml.reader.StreamReader.update(StreamReader.java:200)
    at org.yaml.snakeyaml.reader.StreamReader.<init>(StreamReader.java:60)
    at org.yaml.snakeyaml.Yaml.load(Yaml.java:412)
    at com.config.ConfigProvider.<init>(ConfigProvider.java:20)
    ... 49 more
Caused by: java.io.IOException: Stream closed
    at java.io.PushbackInputStream.ensureOpen(PushbackInputStream.java:57)
    at java.io.PushbackInputStream.read(PushbackInputStream.java:149)
    at org.yaml.snakeyaml.reader.UnicodeReader.init(UnicodeReader.java:90)
    at org.yaml.snakeyaml.reader.UnicodeReader.read(UnicodeReader.java:122)
    at java.io.Reader.read(Reader.java:123)
    at org.yaml.snakeyaml.reader.StreamReader.update(StreamReader.java:184)
    ... 55 more

Here's the line that causes the bug:

String s = ConfigProvider.getConfig().getString("test");

Here's the ConfigProvider class. It basically scans for all resource files of regex ^.*\\.config\\.yml$, converts it into a Map<String, Object>, and combines all the obtained Map<String, Object> into a single Map<String, Object>:

1 public class ConfigProvider {
2     protected static final String CONFIG_PACKAGE = ConfigProvider.class.getPackage().getName();
3     protected static final Pattern CONFIG_PATH_REGEX = Pattern.compile("^.*\\.config\\.yml$");
4 
5     private static final ConfigProvider INSTANCE = new ConfigProvider();
6     private Map<String, Object> configMap;
7 
8     protected ConfigProvider() {
9         configMap = new HashMap<String, Object>();
10 
11        Set<String> configPaths = new Reflections(CONFIG_PACKAGE,
12            new ResourcesScanner()).getResources(CONFIG_PATH_REGEX);
13
14        if (configPaths.isEmpty()) {
15            throw new RuntimeException("no config paths found");
16        }
17
18        for (String path : configPaths) {
19            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
20            Map<String, Object> fullConfig = new Map<String, Object>((Map) new Yaml().load(inputStream));
21        
22            try {
23                inputStream.close();
24            } catch (IOException e) {
25                throw new RuntimeException("error closing stream");
26            }
27
28            MapUtils.merge(configMap, fullConfig);
29        }
30    }
31
32    public static ConfigMap getConfig() {
33        return INSTANCE.configMap;
34    }
35 }

Here's my project structure, titled Foo:

- Foo (this is a module)
    - .idea
    - application (this is a module)
        - src
            - main
                - java
                - resources
                    - application.config.yml
                - webapp
            - test
        - pom.xml
    - client (this is a module)
        - src
            - main
                - java
                - resources
                    - client.config.yml
                - webapp
            - test
        - pom.xml
    - pom.xml

ConfigProvider is a class I get from my parent pom file (Foo/pom.xml). I package a WAR file from the application module (Foo/application/target/application.war), and deploy it with Tomcat. Previously, my project was a single module project with just a Foo module being identical to application module. Then I added a client module and converted the project into a multi module project, and the problem has showed up. I think it's because my class loader is getting messed up due to the multiple modules. I've spent a lot of time trying to debug this and still haven't gotten anywhere. Anyone know what could be the cause, or can think of possible things to try?

Please let me know if you need more info.


回答1:


According to this post, that exception could mean that the .yml file is simply not found. Since you changed your project structure, it is possible that the logic used to build the configPaths needs to be modified for the new structure. Did you try to log the content of configPaths to see if the paths are correct for the new structure?

Also make sure that the .yml files are included in the .war file. Some build systems handle resources differently than java class files.




回答2:


Bean class member variable should match with .yml file keys and second option is there might be chances that you might be giving wrong file path.



来源:https://stackoverflow.com/questions/21567374/java-class-loader-bug-caused-by-java-io-ioexception-stream-closed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!