2

In Java JDK 14.0.1,

When I try to serialize:

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.

It is using https://www.formdev.com/flatlaf/ being stored as a maven dependency.

Using com.fasterxml.jackson.dataformat.xml that I have in my pom.xml along with com.fasterxml.woodstox-core as I have heard that can prevent certain errors:

    <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>

with the following serializing function:

    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();
            
        }
    }

which is using a settings object (The one I will be providing is not the full object and only a small as possible representation of what variable is causing the issue, keep in mind I have deleted or shortened most of the java doc to make it a little shorter to read):

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;
    }

}

I get the following error:

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)

I understand that "CheckBoxMenuItem.border" probably does not have a public getter and setter due to research I have done on this error, but I do not think I can change this.

I have tried a solution from: Serializing with Jackson (JSON) - getting "No serializer found"?

putting: xmlMapper.setVisibility(javax.swing.UIDefaults.CheckBoxMenuItem.border.FIELD, Visibility.ANY); Straight after initialising xmlMapper.

However this produces an error saying that CheckBoxMenuItem attribute does not exist.

Why is the No serializer found error occurring?

How do I fix it?

EDIT: As suggested I tried xmlMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); inside of my serializeSettings() method however I got the following warnings:

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

Also, when I tried to deserialize them I got a plethora of more errors, so I do not think that this is working.

Eno Gerguri
  • 639
  • 5
  • 22
  • 1
    challenging!!! Could you share us a minimal reproducible source code in github? – JRichardsz Jun 27 '20 at 23:15
  • @JRichardsz Here is the link to the full github repository it is slightly bigger than I have shown in the question: https://github.com/Eno-Gerguri/Pygame-Studio – Eno Gerguri Jun 27 '20 at 23:16
  • Please try xmlMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); on serializationSetting method – Ashish Karn Jun 28 '20 at 02:01
  • @AshishKarn I edited my answer explaining what happened if I tried to use that, and it unfortunately did not work. – Eno Gerguri Jun 28 '20 at 09:05
  • 1
    Are you using Java 9+? Maybe this could give you a clue https://stackoverflow.com/questions/50251798/what-is-an-illegal-reflective-access. You could start the JVM with --illegal-access=permit option: http://openjdk.java.net/jeps/261#Relaxed-strong-encapsulation – wizardofOz Jun 28 '20 at 09:41

1 Answers1

3

Do not try to serialize class FlatLightLaf (or any other LookAndFeel class). It is not designed to be serializable and it makes no sense to do so. I'm the author of FlatLaf.

Instead use the class name (as String) of the look and feel.

For searialization use:

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

For deserialization use:

String className = ... // read look and feel class name
UIManager.setLookAndFeel( className );
DevCharly
  • 166
  • 2
  • Thank you! Just to be absolutely clear, if I wanted to use the `FlatLightLaf` would I do: `String myLookAndFeel = "FlatLightLaf";` or would I use the following: `String myLookAndFeel = FlatLightLaf.getClass().getName();` of course for the second example I would import it. However, I am trying to save it directly so which line would it be? – Eno Gerguri Jun 28 '20 at 15:49
  • 1
    `UIManager.setLookAndFeel(String className)` requires the full qualified class name. Either use `FlatLightLaf.getClass().getName()` or the String `"com.formdev.flatlaf.FlatLightLaf"`. Hope it works :) – DevCharly Jun 28 '20 at 15:56
  • It worked perfectly! Just like you said: `private String lookAndFeel = new FlatLightLaf().getClass().getName();` got it to serialize and then deserialize. Thank you. I will give you your +50 reputation in six hours when I am allowed to. – Eno Gerguri Jun 28 '20 at 16:07