【问题标题】:How to use Jackson dataformat.xml to serialize a LookAndFeel object in java?如何使用 Jackson dataformat.xml 在 java 中序列化 LookAndFeel 对象?
【发布时间】:2020-10-16 09:00:09
【问题描述】:

在 Java JDK 14.0.1 中,

当我尝试序列化时:

private LookAndFeel lookAndFeel = new FlatLightLaf();
// I am obviously creating this in a working object as the serializing in xml with jackson has been successful until this specific object was added.

它使用 https://www.formdev.com/flatlaf/ 被存储为 maven 依赖项。

使用我在 pom.xml 中的com.fasterxml.jackson.dataformat.xml 以及我听说的com.fasterxml.woodstox-core 可以防止某些错误:

    <dependency>
      <groupId>com.formdev</groupId>
      <artifactId>flatlaf</artifactId>
      <version>0.36</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-xml</artifactId>
      <version>2.11.1</version>
    </dependency>
    <dependency>
       <groupId>com.fasterxml.woodstox</groupId>
       <artifactId>woodstox-core</artifactId>
       <version>5.1.0</version>
    </dependency>

具有以下序列化功能:

    public void serializeSettings(Settings settings, File directoryToStore) {
        XmlMapper xmlMapper = new XmlMapper();
        try {
            xmlMapper.writeValue(directoryToStore, settings);
            
        } catch (JsonGenerationException e) {
            e.printStackTrace();
            
        } catch (JsonMappingException e) {
            e.printStackTrace();
            
        } catch (IOException e) {
            e.printStackTrace();
            
        }
    }

它正在使用一个设置对象(我将提供的不是完整的对象,而是导致问题的变量的尽可能小的表示,请记住我已经删除或缩短了大部分 java 文档让它读起来更短一些):

Settings.java

package com.pygame_studio.settings;

import java.io.File;

import javax.swing.LookAndFeel;

import com.pygame_studio.settings.appearance_and_behavior.AppearanceAndBehavior;

public class Settings {
    private File storedSettingsFile;  // Where the settings .xml file is stored.
    
    private AppearanceAndBehavior appearanceAndBehavior;  // Stores all the settings to do with the appearance and behavior of Pygame Studio.

    public Settings() {
        super();
    }
    
    public Settings(File storedSettingsFile,
                    /*Appearance And Behavior settings*/
                    LookAndFeel lookAndFeel) {
        this.setStoredSettingsFile(storedSettingsFile);
        
        this.setAppearanceAndBehavior(new AppearanceAndBehavior(lookAndFeel));
    }
    
    public Settings(File storedSettingsFile,
                    AppearanceAndBehavior appearanceAndBehavior) {
        this.setStoredSettingsFile(storedSettingsFile);
        
        this.setAppearanceAndBehavior(appearanceAndBehavior);
    }
    
    /**
     * @return storedSettingsFile
     */
    public File getStoredSettingsFile() {
        return storedSettingsFile;
    }

    /**
     * @param storedSettingsFile - storedSettingsFile to set.
     */
    public void setStoredSettingsFile(File storedSettingsFile) {
        this.storedSettingsFile = storedSettingsFile;
    }

    /**
     * @return appearanceAndBehavior
     */
    public AppearanceAndBehavior getAppearanceAndBehavior() {
        return appearanceAndBehavior;
    }

    /**
     * @param appearanceAndBehavior - appearanceAndBehavior to set.
     */
    public void setAppearanceAndBehavior(AppearanceAndBehavior appearanceAndBehavior) {
        this.appearanceAndBehavior = appearanceAndBehavior;
    }

}

AppearanceAndAppearance.java

package com.pygame_studio.settings.appearance_and_behavior;

import java.io.File;

import javax.swing.LookAndFeel;

public class AppearanceAndBehavior {
    private LookAndFeel lookAndFeel;  // Stores the look and feel of the program.

    public AppearanceAndBehavior() {
        super();
    }
    
    public AppearanceAndBehavior(LookAndFeel lookAndFeel) {
        this.setLookAndFeel(lookAndFeel);
    }
    
    /**
     * @return - lookAndFeel
     */
    public LookAndFeel getLookAndFeel() {
        return this.lookAndFeel;
    }

    /**
     * @param lookAndFeel - lookAndFeel to set
     */
    public void setLookAndFeel(LookAndFeel lookAndFeel) {
        this.lookAndFeel = lookAndFeel;
    }

}

我收到以下错误:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.formdev.flatlaf.UIDefaultsLoader$$Lambda$93/0x0000000800c2f040 and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.pygame_studio.settings.Settings["appearanceAndBehavior"]->com.pygame_studio.settings.appearance_and_behavior.AppearanceAndBehavior["lookAndFeel"]->com.formdev.flatlaf.FlatLightLaf["defaults"]->javax.swing.UIDefaults["CheckBoxMenuItem.border"])
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
    at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1277)
    at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:71)
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:33)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:726)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithoutTypeInfo(MapSerializer.java:681)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:637)
    at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:33)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializerBase.serializeFields(XmlBeanSerializerBase.java:212)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializer.serialize(XmlBeanSerializer.java:129)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializerBase.serializeFields(XmlBeanSerializerBase.java:212)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializer.serialize(XmlBeanSerializer.java:129)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializerBase.serializeFields(XmlBeanSerializerBase.java:212)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializer.serialize(XmlBeanSerializer.java:129)
    at com.fasterxml.jackson.dataformat.xml.ser.XmlSerializerProvider.serializeValue(XmlSerializerProvider.java:109)
    at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:4374)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:3570)
    at com.pygame_studio.settings.SettingsManager.serializeSettings(SettingsManager.java:41)
    at com.pygame_studio.PygameStudio.<init>(PygameStudio.java:24)
    at com.pygame_studio.PygameStudio.main(PygameStudio.java:31)

我了解“CheckBoxMenuItem.border”可能没有公共 getter 和 setter,因为我对此错误进行了研究,但我认为我无法更改。

我尝试了来自Serializing with Jackson (JSON) - getting "No serializer found"?的解决方案

输入:xmlMapper.setVisibility(javax.swing.UIDefaults.CheckBoxMenuItem.border.FIELD, Visibility.ANY); 初始化 xmlMapper 之后。

但是这会产生一个错误,指出CheckBoxMenuItem 属性不存在。

为什么会出现No serializer found 错误?

我该如何解决?

编辑:按照建议,我在 serializeSettings() 方法中尝试了 xmlMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);,但收到以下警告:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.fasterxml.jackson.databind.util.ClassUtil (file:/C:/Users/Eno/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.11.1/jackson-databind-2.11.1.jar) to method sun.awt.SunHints$Value.getIndex()
WARNING: Please consider reporting this to the maintainers of com.fasterxml.jackson.databind.util.ClassUtil
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

另外,当我尝试反序列化它们时,我遇到了很多错误,所以我认为这不起作用。

【问题讨论】:

  • 挑战!!!你能在 github 上分享一个最小的可重现源代码吗?
  • @JRichardsz 这是完整 github 存储库的链接,它比我在问题中显示的略大:github.com/Eno-Gerguri/Pygame-Studio
  • 请尝试 xmlMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);关于序列化设置方法
  • @AshishKarn 我编辑了我的答案,解释了如果我尝试使用它会发生什么,但不幸的是它不起作用。
  • 您使用的是 Java 9+ 吗?也许这可以给你一个线索stackoverflow.com/questions/50251798/…。您可以使用 --illegal-access=permit 选项启动 JVM:openjdk.java.net/jeps/261#Relaxed-strong-encapsulation

标签: java jackson-dataformat-xml


【解决方案1】:

不要尝试序列化 FlatLightLaf 类(或任何其他 LookAndFeel 类)。它不是为可序列化而设计的,这样做没有任何意义。我是 FlatLaf 的作者。

改为使用外观的类名(作为字符串)。

用于序列化:

String className = UIManager.getLookAndFeel().getClass().getName();
// write look and feel class name

反序列化使用:

String className = ... // read look and feel class name
UIManager.setLookAndFeel( className );

【讨论】:

  • 谢谢!绝对清楚,如果我想使用FlatLightLaf,我会这样做:String myLookAndFeel = "FlatLightLaf"; 还是使用以下内容:String myLookAndFeel = FlatLightLaf.getClass().getName(); 当然对于第二个示例我会导入它。但是,我试图直接保存它,它会是哪一行?
  • UIManager.setLookAndFeel(String className) 需要完整的限定类名。使用FlatLightLaf.getClass().getName() 或字符串"com.formdev.flatlaf.FlatLightLaf"。希望它有效:)
  • 效果很好!就像你说的:private String lookAndFeel = new FlatLightLaf().getClass().getName(); 让它序列化然后反序列化。谢谢你。如果允许的话,我会在六个小时内给你 +50 的声望。
猜你喜欢
  • 2019-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-20
  • 2019-10-25
  • 1970-01-01
相关资源
最近更新 更多