-
Bug
-
Resolution: Fixed
-
P4
-
1.4.2
-
beta
-
x86
-
windows_nt
Name: gm110360 Date: 04/06/2004
FULL PRODUCT VERSION :
java version "1.4.2_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_01-b06)
Java HotSpot(TM) Client VM (build 1.4.2_01-b06, mixed mode)
FULL OS VERSION :
Windows NT Version 4.0
sp6a
A DESCRIPTION OF THE PROBLEM :
Supplying JTextArea with a Document implementation in which the defaultRootElement
has no children (getChildElementCount() == 0), causes a NullPointerException
in javax.swing.text.PlainView.
This is caused by a presumption throughout PlainView that the longLine variable
is not null. This assumption is wrong because calculateLongestLine leaves the
variable null if there are not child elements of the root element.
There is no requirement (nor should there be) that a Document's root Element
be non-empty.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run test program included below
java TestDocument
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Should display a small, empty window and no console output should be produced.
ACTUAL -
An NPE is thrown, see below.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.NullPointerException
at javax.swing.text.PlainView.getLineWidth(Unknown Source)
at javax.swing.text.PlainView.getPreferredSpan(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI$RootView.getPreferredSpan(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.getPreferredSize(Unknown Source)
at javax.swing.JComponent.getPreferredSize(Unknown Source)
at javax.swing.JTextArea.getPreferredSize(Unknown Source)
at javax.swing.text.JTextComponent.getPreferredScrollableViewportSize(Unknown Source)
at javax.swing.JTextArea.getPreferredScrollableViewportSize(Unknown Source)
at javax.swing.ViewportLayout.preferredLayoutSize(Unknown Source)
at java.awt.Container.preferredSize(Unknown Source)
at java.awt.Container.getPreferredSize(Unknown Source)
at javax.swing.JComponent.getPreferredSize(Unknown Source)
at javax.swing.ScrollPaneLayout.preferredLayoutSize(Unknown Source)
at java.awt.Container.preferredSize(Unknown Source)
at java.awt.Container.getPreferredSize(Unknown Source)
at javax.swing.JComponent.getPreferredSize(Unknown Source)
at java.awt.BorderLayout.preferredLayoutSize(Unknown Source)
at java.awt.Container.preferredSize(Unknown Source)
at java.awt.Container.getPreferredSize(Unknown Source)
at javax.swing.JComponent.getPreferredSize(Unknown Source)
at javax.swing.JRootPane$RootLayout.preferredLayoutSize(Unknown Source)
at java.awt.Container.preferredSize(Unknown Source)
at java.awt.Container.getPreferredSize(Unknown Source)
at javax.swing.JComponent.getPreferredSize(Unknown Source)
at java.awt.BorderLayout.preferredLayoutSize(Unknown Source)
at java.awt.Container.preferredSize(Unknown Source)
at java.awt.Container.getPreferredSize(Unknown Source)
at java.awt.Window.pack(Unknown Source)
at TestDocument.main(TestDocument.java:24)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
/*
* A minimal Document implementation provokes a bug or undocumented
* restriction on Document implementations. The problem occurs when a
* Document's default root Element has no children and the Document is
* the model for a JTextArea (and perhaps other text components as
* well).
* Examining PlainView, we see the longLine variable is initialized by
* calculateLongestLine only if the root Element is not empty; else it
* is left null. Later, it is presumed to be non-null producing the
* following exception (among others):
<repeated exception removed>
*/
public class TestDocument implements Document {
public static void main(String[] args) {
try {
TestDocument doc = new TestDocument();
JTextArea text = new JTextArea(doc);
JScrollPane pane = new JScrollPane(text);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(3);
frame.getContentPane().add(pane);
frame.pack();
frame.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public void addDocumentListener(DocumentListener listener) {listeners.add(listener);}
public void addUndoableEditListener(UndoableEditListener listener) {}
public Position createPosition(int offs) {return new TestPosition(offs);}
public Element getDefaultRootElement() {return rootElements[0];}
public Position getEndPosition() {return createPosition(getLength());}
public int getLength() {return 0;}
public Object getProperty(Object key) {return null;}
public Element[] getRootElements() {return rootElements;}
public Position getStartPosition() {return new TestPosition(0);}
public String getText(int offset, int length) throws BadLocationException {return "";}
public void getText(int offset, int length, Segment txt)
throws BadLocationException
{
txt.array = new char[0];
txt.count = 0;
txt.offset = 0;
}
public void insertString(int offset, String str, AttributeSet a) {}
public void putProperty(Object key, Object value) {}
public void remove(int offs, int len) {}
public void removeDocumentListener(DocumentListener listener) {listeners.remove(listener);}
public void removeUndoableEditListener(UndoableEditListener listener) {}
public synchronized void render(Runnable r) {r.run();}
private Element[] rootElements = {new TestElement()};
private List listeners = new ArrayList(2);
private class TestElement implements Element {
public AttributeSet getAttributes() {return null;}
public Document getDocument() {return TestDocument.this;}
public Element getElement(int index) {return null;} // There are no children
public int getElementCount() {return 0;} // There are no children
public int getElementIndex(int offset) {return -1;} // There are no children
public int getEndOffset() {return 0;}
public Element getParentElement() {return null;}
public int getStartOffset() {return 0;}
public boolean isLeaf() {return false;}
public String getName() {return "test";}
}
static class TestPosition implements Position {
public TestPosition(int offset) {this.offset = offset;}
public int getOffset() {return offset;}
private int offset;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
An ugly work-around is to try to insure that the root Element always has at least
one child.
(Incident Review ID: 206860)
======================================================================
###@###.### 10/13/04 17:58 GMT
FULL PRODUCT VERSION :
java version "1.4.2_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_01-b06)
Java HotSpot(TM) Client VM (build 1.4.2_01-b06, mixed mode)
FULL OS VERSION :
Windows NT Version 4.0
sp6a
A DESCRIPTION OF THE PROBLEM :
Supplying JTextArea with a Document implementation in which the defaultRootElement
has no children (getChildElementCount() == 0), causes a NullPointerException
in javax.swing.text.PlainView.
This is caused by a presumption throughout PlainView that the longLine variable
is not null. This assumption is wrong because calculateLongestLine leaves the
variable null if there are not child elements of the root element.
There is no requirement (nor should there be) that a Document's root Element
be non-empty.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run test program included below
java TestDocument
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Should display a small, empty window and no console output should be produced.
ACTUAL -
An NPE is thrown, see below.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.NullPointerException
at javax.swing.text.PlainView.getLineWidth(Unknown Source)
at javax.swing.text.PlainView.getPreferredSpan(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI$RootView.getPreferredSpan(Unknown Source)
at javax.swing.plaf.basic.BasicTextUI.getPreferredSize(Unknown Source)
at javax.swing.JComponent.getPreferredSize(Unknown Source)
at javax.swing.JTextArea.getPreferredSize(Unknown Source)
at javax.swing.text.JTextComponent.getPreferredScrollableViewportSize(Unknown Source)
at javax.swing.JTextArea.getPreferredScrollableViewportSize(Unknown Source)
at javax.swing.ViewportLayout.preferredLayoutSize(Unknown Source)
at java.awt.Container.preferredSize(Unknown Source)
at java.awt.Container.getPreferredSize(Unknown Source)
at javax.swing.JComponent.getPreferredSize(Unknown Source)
at javax.swing.ScrollPaneLayout.preferredLayoutSize(Unknown Source)
at java.awt.Container.preferredSize(Unknown Source)
at java.awt.Container.getPreferredSize(Unknown Source)
at javax.swing.JComponent.getPreferredSize(Unknown Source)
at java.awt.BorderLayout.preferredLayoutSize(Unknown Source)
at java.awt.Container.preferredSize(Unknown Source)
at java.awt.Container.getPreferredSize(Unknown Source)
at javax.swing.JComponent.getPreferredSize(Unknown Source)
at javax.swing.JRootPane$RootLayout.preferredLayoutSize(Unknown Source)
at java.awt.Container.preferredSize(Unknown Source)
at java.awt.Container.getPreferredSize(Unknown Source)
at javax.swing.JComponent.getPreferredSize(Unknown Source)
at java.awt.BorderLayout.preferredLayoutSize(Unknown Source)
at java.awt.Container.preferredSize(Unknown Source)
at java.awt.Container.getPreferredSize(Unknown Source)
at java.awt.Window.pack(Unknown Source)
at TestDocument.main(TestDocument.java:24)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
/*
* A minimal Document implementation provokes a bug or undocumented
* restriction on Document implementations. The problem occurs when a
* Document's default root Element has no children and the Document is
* the model for a JTextArea (and perhaps other text components as
* well).
* Examining PlainView, we see the longLine variable is initialized by
* calculateLongestLine only if the root Element is not empty; else it
* is left null. Later, it is presumed to be non-null producing the
* following exception (among others):
<repeated exception removed>
*/
public class TestDocument implements Document {
public static void main(String[] args) {
try {
TestDocument doc = new TestDocument();
JTextArea text = new JTextArea(doc);
JScrollPane pane = new JScrollPane(text);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(3);
frame.getContentPane().add(pane);
frame.pack();
frame.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public void addDocumentListener(DocumentListener listener) {listeners.add(listener);}
public void addUndoableEditListener(UndoableEditListener listener) {}
public Position createPosition(int offs) {return new TestPosition(offs);}
public Element getDefaultRootElement() {return rootElements[0];}
public Position getEndPosition() {return createPosition(getLength());}
public int getLength() {return 0;}
public Object getProperty(Object key) {return null;}
public Element[] getRootElements() {return rootElements;}
public Position getStartPosition() {return new TestPosition(0);}
public String getText(int offset, int length) throws BadLocationException {return "";}
public void getText(int offset, int length, Segment txt)
throws BadLocationException
{
txt.array = new char[0];
txt.count = 0;
txt.offset = 0;
}
public void insertString(int offset, String str, AttributeSet a) {}
public void putProperty(Object key, Object value) {}
public void remove(int offs, int len) {}
public void removeDocumentListener(DocumentListener listener) {listeners.remove(listener);}
public void removeUndoableEditListener(UndoableEditListener listener) {}
public synchronized void render(Runnable r) {r.run();}
private Element[] rootElements = {new TestElement()};
private List listeners = new ArrayList(2);
private class TestElement implements Element {
public AttributeSet getAttributes() {return null;}
public Document getDocument() {return TestDocument.this;}
public Element getElement(int index) {return null;} // There are no children
public int getElementCount() {return 0;} // There are no children
public int getElementIndex(int offset) {return -1;} // There are no children
public int getEndOffset() {return 0;}
public Element getParentElement() {return null;}
public int getStartOffset() {return 0;}
public boolean isLeaf() {return false;}
public String getName() {return "test";}
}
static class TestPosition implements Position {
public TestPosition(int offset) {this.offset = offset;}
public int getOffset() {return offset;}
private int offset;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
An ugly work-around is to try to insure that the root Element always has at least
one child.
(Incident Review ID: 206860)
======================================================================
###@###.### 10/13/04 17:58 GMT