Java 使用 jackson 反序列化 xml 时静态变量未被初始化

Java static variables not being initialised when deserialising xml using jackson

我在尝试使用 jackson 反序列化 xml 时遇到问题。

我正在使用以下函数从文件中反序列化我的 xml。

Xml 文件为-:

https://github.com/Eno-Gerguri/Pygame-Studio/blob/master/Settings/defaultSettings.xml

这是我用来反序列化对象的函数:

    public Settings deserializeSettings(File settingsFile) {
        XmlMapper xmlMapper = new XmlMapper();
        String xml = null;
        Settings settings = null;
        
        try {
            xml = inputStreamToString(new FileInputStream(settingsFile));
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            
        } catch (IOException e) {
            e.printStackTrace();
            
        }
        try {
            settings = xmlMapper.readValue(xml, Settings.class);
            
        } catch (JsonMappingException e) {
            e.printStackTrace();
            
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            
        }
        
        return settings;
    }
    
    private String inputStreamToString(InputStream inputStream) throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        String line;
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        while ((line = bufferedReader.readLine()) != null) {
            stringBuilder.append(line);
        }
        bufferedReader.close();
        return stringBuilder.toString();
    }

我正在使用的设置对象,我正在反序列化为:-

https://github.com/Eno-Gerguri/Pygame-Studio/blob/master/src/com/pygame_studio/settings/Settings.java

Settings对象使用的子class:

https://github.com/Eno-Gerguri/Pygame-Studio/blob/master/src/com/pygame_studio/settings/appearance_and_behavior/AppearanceAndBehavior.java

Settings对象使用的sub-class:

https://github.com/Eno-Gerguri/Pygame-Studio/blob/master/src/com/pygame_studio/settings/appearance_and_behavior/Font.java

当我尝试在单独的文件中反序列化对象时:

private Settings defaultSettings = settingsManager.deserializeSettings(DefaultSettings.DEFAULT_SETTINGS_FILE_DIRECTORY);

错误日志如下

com.fasterxml.jackson.databind.JsonMappingException: N/A
 at [Source: (StringReader); line: 1, column: 356] (through reference chain: com.pygame_studio.settings.Settings["appearanceAndBehavior"]->com.pygame_studio.settings.appearance_and_behavior.AppearanceAndBehavior["font"]->com.pygame_studio.settings.appearance_and_behavior.Font["fontDirectory"])
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:278)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:611)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:599)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:143)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4202)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3205)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3173)
    at com.pygame_studio.settings.SettingsManager.deserializeSettings(SettingsManager.java:75)
    at com.pygame_studio.start_menu.StartMenu.<init>(StartMenu.java:24)
    at com.pygame_studio.PygameStudio.<init>(PygameStudio.java:18)
    at com.pygame_studio.PygameStudio.main(PygameStudio.java:25)
Caused by: java.lang.NullPointerException
    at com.pygame_studio.settings.appearance_and_behavior.Font.setFontDirectory(Font.java:115)
    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:564)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:141)
    ... 15 more

我知道在函数中: com.pygame_studio.settings.appearance_and_behavior.Font.setFontDirectory

public void setFontDirectory(String fontDirectory) {
        if (externalFonts.containsKey(fontDirectory)) {
            this.fontDirectory = externalFonts.get(fontDirectory);
        } else if (localFonts.contains(fontDirectory)) {
            this.fontDirectory = fontDirectory;
        } else {
            this.fontDirectory = this.getFallbackFont();
        }
    }

externalFonts Hashtable 是空的,因为它还没有被初始化但是,它应该和构造函数中一样:

    public Font() {
        super();
    }
    
    public Font(File externalFontDirectory, String fontName, int fontStyle, int fontSize, String fallbackFont) {
        this.setExternalFontDirectory(externalFontDirectory);
        
        this.setExternalFonts();  // External fonts is set before the font directory.
        this.setLocalFonts();
        
        this.setFontDirectory(fontName);  // Font directory being set after externalFonts.
        
        this.setFontStyle(fontStyle);
        
        this.setFontSize(fontSize);
        
        this.setFallbackFont(fallbackFont);
    }

设置外部字体方法:

    public void setExternalFonts() {
        externalFonts = getExternalFonts(this.externalFontDirectory);
    }

getExternalFonts 方法:

    public static Hashtable<String, String> getExternalFonts(File externalFontDirectory) {
        Hashtable<String, String> externalFonts = new Hashtable<>();
        
        final File[] directoryFiles = externalFontDirectory.listFiles();
        
        if (directoryFiles != null) {
            for (File file : directoryFiles) {
                if (file.isDirectory()) {  // If the file is a sub-directory.
                    externalFonts.putAll(getExternalFonts(file));  // Calls itself onto the directory.
                } else if (file.getName().contains(".ttf")) {  // If the file is a font.
                    String fontName = file.getName().replace(".ttf", "");  // Gets the name of the font.
                    externalFonts.put(fontName, file.getPath());  // Puts the, name of the font : font's directory, into the Hashtable.
                }
            }
        }
        return externalFonts;
    }

但是,我的 IDE Eclipse 告诉我,这段代码从未到达,而应该初始化外部字体。

为什么这个方法没有被调用? 我该如何解决这个问题,以便我可以成功地将 xml 反序列化为“设置”对象?

提前致谢!

具体问题在Fontclass这里:

public static Hashtable<String, String> externalFonts;

首先,我建议将其从 Hashtable 更改为 HashMap - 现在(根据我的经验)没有理由使用 Hashtable 而不是任何更现代的 collection classes。您可以阅读社区意见 here

其次,该字段需要初始化,因此它不为空 - 就像您对 localFonts 列表所做的那样。

所以这给了我们这个:

public static Map<String, String> externalFonts = new HashMap();

当然,您随后需要替换对 Hashtable 的其余引用。

当我进行更改时,它解决了您报告的具体问题。