javaswinguser-interfacelook-and-feelsynth

Why does Synth keeps throwing NullPointerExceptions when trying to apply a style?


Whenever I try to apply a style to a JMenu or a JMenuItem (via Synth) I get a lot of NullPointerExceptions whenever I hover or click the JMenuItems or the JMenu itself, the stack trace isn't giving me any useful information and doesn't point anywhere at any of my source files.

I am loading the file correctly and it does display the styles (apart from the background colors but that's aside) the problem is that I get a lot of Exceptions while everything is working just fine, the program doesn't crash.

this is the synth LookAndFeel.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<synth>

    <style id="menuBarStyle">
        <state>
            <color value="GRAY" type="BACKGROUND"/>
        </state>
    </style>
    <bind style="menuBarStyle" type="region" key="MenuBar"/>

    <style id="menuStyle">
        <insets top="5" bottom="3" right="10" left="10"/>
        <state>
            <color value="RED" type="BACKGROUND"/>
        </state>
    </style>
    <bind style="menuStyle" type="region" key="Menu"/>

    <style id="menuItemStyle">
        <insets top="5" bottom="5" left="10" right="3"/>
        <state>
            <color value="GREEN" type="BACKGROUND"/>
        </state>
    </style>
    <bind style="menuItemStyle" type="region" key="MenuItem"/>

    <style id="menuItemAcceleratorStyle">
        <state>
            <color value="GRAY" type="BACKGROUND"/>
        </state>
    </style>
    <bind style="menuItemAcceleratorStyle" type="region" key="MenuItem"/>

</synth>

This is how I load the file:

 private void initUI() {
        try {
            SynthLookAndFeel laf = new SynthLookAndFeel();
            laf.load(getClass().getClassLoader().getResourceAsStream("LookAndFeel.xml"), getClass());
            UIManager.setLookAndFeel(laf);
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }
    }

And this is the stack trace (printed repeatedly whenever there is an interaction with the styled components):

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at sun.font.FontDesignMetrics$MetricsKey.init(FontDesignMetrics.java:217)
    at sun.font.FontDesignMetrics.getMetrics(FontDesignMetrics.java:286)
    at sun.swing.SwingUtilities2.getFontMetrics(SwingUtilities2.java:1113)
    at javax.swing.JComponent.getFontMetrics(JComponent.java:1626)
    at sun.swing.MenuItemLayoutHelper.reset(MenuItemLayoutHelper.java:125)
    at javax.swing.plaf.synth.SynthMenuItemLayoutHelper.<init>(SynthMenuItemLayoutHelper.java:119)
    at javax.swing.plaf.synth.SynthGraphicsUtils.paint(SynthGraphicsUtils.java:501)
    at javax.swing.plaf.synth.SynthMenuItemUI.paint(SynthMenuItemUI.java:281)
    at javax.swing.plaf.synth.SynthMenuItemUI.update(SynthMenuItemUI.java:245)
    at javax.swing.JComponent.paintComponent(JComponent.java:780)
    at javax.swing.JComponent.paint(JComponent.java:1056)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JComponent.paintToOffscreen(JComponent.java:5210)
    at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
    at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
    at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
    at javax.swing.JComponent._paintImmediately(JComponent.java:5158)
    at javax.swing.JComponent.paintImmediately(JComponent.java:4969)
    at javax.swing.RepaintManager$4.run(RepaintManager.java:831)
    at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
    at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
    at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
    at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
    at java.awt.EventQueue.access$500(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:709)
    at java.awt.EventQueue$3.run(EventQueue.java:703)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

I suspect that the problem has something to do with Synth itself rather than my code I suppose, I tried looking up on the internet and in the java documentation and tutorials on Synth but couldn't find anything relevant.

P.S: I call this method before I start displaying or creating any swing components.


Solution

  • Update (and a highly probable answer):

    I found a way to solve the problem, however the question remains in tact since I still haven't got any explanation to why is the problem happening but I have a hypothesis.

    Solution:

    Apparently a font style should be applied to all the elements in order for the XML file not to show the errors, this is the bare minimum required to solve the issue I have discovered after some experimentation:

    <style id="defaultElementStyle">
        <font name="Verdana" size="12"/>
    </style>
    <bind style="defaultElementStyle" type="region" key=".*"/>
    


    Hypothesis

    Since:

    I can safely infer that the problem origin was calling some function that tried to read the font property of the changed states *(probably from one of the classes in the stack trace). However, in the case mentioned above the default font for the states was undefined in the XML file (null) which resulted in a NullPointerException, then maybe the class was smart enough to resort to some default font (which is displayed) and that prevented the program from failing completely and crashing. Any thoughts on the subject would be highly appreciated since it seems that the problem isn't common at all and requires further investigation.