As a follow-up to this question that I posted earlier, I am wondering about the cause of the issue I had.
The problem was that I was getting this error when updating a JLabel with a lot of HTML text.
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.text.html.StyleSheet$ListPainter.paint(Unknown Source)
at javax.swing.text.html.ListView.paintChild(Unknown Source)
at javax.swing.text.BoxView.paint(Unknown Source)
at javax.swing.text.html.BlockView.paint(Unknown Source)
at javax.swing.text.html.ListView.paint(Unknown Source)
at javax.swing.text.BoxView.paintChild(Unknown Source)
at javax.swing.text.BoxView.paint(Unknown Source)
at javax.swing.text.html.BlockView.paint(Unknown Source)
at javax.swing.text.BoxView.paintChild(Unknown Source)
at javax.swing.text.BoxView.paint(Unknown Source)
at javax.swing.text.html.BlockView.paint(Unknown Source)
at javax.swing.text.BoxView.paintChild(Unknown Source)
at javax.swing.text.BoxView.paint(Unknown Source)
at javax.swing.text.html.BlockView.paint(Unknown Source)
at javax.swing.plaf.basic.BasicHTML$Renderer.paint(Unknown Source)
at javax.swing.plaf.basic.BasicLabelUI.paint(Unknown Source)
at javax.swing.plaf.ComponentUI.update(Unknown Source)
at javax.swing.JComponent.paintComponent(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent._paintImmediately(Unknown Source)
at javax.swing.JComponent.paintImmediately(Unknown Source)
at javax.swing.RepaintManager$4.run(Unknown Source)
at javax.swing.RepaintManager$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.access$1200(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
The HTML that's being set is generated by a StringBuilder and the converted .toString
. Something like this, but more extensive:
public static String entityOverviewHTML() {
StringBuilder sb = new StringBuilder();
List<Entity> entities = Entity.getEntities();
sb.append("<html><div style='padding: 12px;'>");
sb.append("<h1>People: alive</h1>");
// A lot of appending: also loop through getEntities (dynamic, can change)
// and get contents from each entity in #getEntityInfo below
if (entities.size() > 0) {
sb.append("<ul>");
for (Entity e: entities) {
getEntityInfo(e);
}
sb.append("</ul>");
}
sb.append("</div></html>");
return sb.toString();
}
private static StringBuilder getEntityInfo(Entity e) {
StringBuilder sbInfo = new StringBuilder();
// A lot of appending: append info of Entity e such as e.getFirstName()
sbInfo.append("<li>");
sbInfo.append(e.getFirstName())
sbInfo.append("</li>");
return sbInfo;
}
After some events, the HTML will change after which I call a custom refresh method:
public static void bringToFront() {
getInstance().setVisible(true);
getInstance().setExtendedState(JFrame.ICONIFIED);
getInstance().setExtendedState(JFrame.NORMAL);
}
public static void refresh() {
// text is a JLabel
text.setText(entityOverviewHTML());
bringToFront();
}
And it's then that the errors at the top of this post happen, however not always! I haven't figured out why this happens, but I did find that when resetting the text to an empty string and then calling entityOverviewHTML solves the issue.
public static void refresh() {
text.setText(""); // Here we go
text.setText(entityOverviewHTML());
bringToFront();
}
text is defined as a Class variable:
private static JLabel text = new JLabel();
What I like to know is: why? How can this single line of seemingly obsolete code solve the problem? Exactly what is the problem?