here's an example program from Core Java II Advanced Features (9th ed). This program parses an XML file which contains the layout data for a GridBagConstraints object. However, when run, the program crashed and a number of exceptions were thrown. It turned out that those exceptions seemed to have been caused by some errors caught by the parser in the XML file. The setValidating() method sets to true, so the XML is validated against a DTD file. The code of the program, the XML file, the DTD and the error text are as follows. I'm sorry this makes the post a bit long to read. Thank you very much for your help.
package read;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
public class GridBagTest {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable () {
public void run () {
JFileChooser chooser = new JFileChooser("read");
chooser.showOpenDialog(null);
File file = chooser.getSelectedFile();
JFrame frame = new FontFrame(file);
frame.setTitle("GridBagTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
/**
* This frame contains a font selection dialog
* that is described by an XML file.
* @param filename the file containg the user
* interface components for the dialog.
*/
class FontFrame extends JFrame {
private GridBagPane gridbag;
private JComboBox<String> face;
private JComboBox<String> size;
private JCheckBox bold;
private JCheckBox italic;
@SuppressWarnings("unchecked")
public FontFrame (File file) {
gridbag = new GridBagPane(file);
add(gridbag);
face = (JComboBox<String>) gridbag.get("face");
size = (JComboBox<String>) gridbag.get("size");
bold = (JCheckBox) gridbag.get("bold");
italic = (JCheckBox) gridbag.get("italic");
face.setModel(new DefaultComboBoxModel<String>(new String[] {"Serif",
"SanSerif", "Monospaced", "Dialog", "DialogInput"}));
size.setModel(new DefaultComboBoxModel<String>(new String[] {"8", "10",
"12", "15", "18", "24", "36", "48"}));
ActionListener listener = new ActionListener() {
public void actionPerformed (ActionEvent event) {
setSample();
}
};
face.addActionListener(listener);
size.addActionListener(listener);
bold.addActionListener(listener);
italic.addActionListener(listener);
setSample();
pack();
}
/**
* This method sets the text sample to the selected font.
*/
public void setSample () {
String fontFace = face.getItemAt(face.getSelectedIndex());
int fontSize = Integer.parseInt(size.getItemAt(size.getSelectedIndex()));
JTextArea sample = (JTextArea) gridbag.get("sample");
int fontStyle = (bold.isSelected() ? Font.BOLD : 0) + (italic.isSelected() ? Font.ITALIC : 0);
sample.setFont(new Font(fontFace, fontStyle, fontSize));
sample.repaint();
}
}
package read;
import java.awt.*;
import java.beans.*;
import java.io.*;
import java.lang.reflect.*;
import javax.swing.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
/**
* This panel users an XML file to describe its
* components and their grid bag layout positions.
*/
public class GridBagPane extends JPanel {
private GridBagConstraints constraints;
/**
* Construct a grid bag pane.
* @param filename the name of the XML file that
* desribes the pane's components and their positions
*/
public GridBagPane (File file) {
setLayout(new GridBagLayout());
constraints = new GridBagConstraints();
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
if (file.toString().contains("-schema")) {
factory.setNamespaceAware(true);
final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
}
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(file);
parseGridbag(doc.getDocumentElement());
}
catch (Exception e) {
e.printStackTrace();
}
}
/**
* Gets a component with a given name.
* @param name a component name
* @return the component with the given name, or null
* if no component in this grid bag pane has the given name
*/
public Component get(String name) {
Component[] components = getComponents();
for (int i = 0; i < components.length; i++) {
if (components[i].getName().equals(name))
return components[i];
}
return null;
}
/**
* Parse a gridbag element.
* @param e a gridbag element
*/
private void parseGridbag(Element e) {
NodeList rows = e.getChildNodes();
for (int i = 0; i < rows.getLength(); i++) {
Element row = (Element) rows.item(i);
NodeList cells = row.getChildNodes();
for (int j = 0; j < cells.getLength(); j++) {
Element cell = (Element) cells.item(j);
parseCell(cell, i, j);
}
}
}
/**
* Parse a cell element.
* @param e a cell element
* @param r the row of the cell
* @param c the column of the cell
*/
private void parseCell(Element e, int r, int c) {
// get attributes
String value = e.getAttribute("gridx");
if (value.length() == 0) // use default
{
if (c == 0)
constraints.gridx = 0;
else
constraints.gridx += constraints.gridwidth;
}
else
constraints.gridx = Integer.parseInt(value);
value = e.getAttribute("gridy");
if (value.length() == 0) // use default
constraints.gridy = r;
else
constraints.gridy = Integer.parseInt(value);
constraints.gridwidth = Integer.parseInt(e.getAttribute("gridwidth"));
constraints.gridheight = Integer.parseInt(e.getAttribute("gridheight"));
constraints.weightx = Integer.parseInt(e.getAttribute("weightx"));
constraints.weighty = Integer.parseInt(e.getAttribute("weighty"));
constraints.ipadx = Integer.parseInt(e.getAttribute("ipadx"));
constraints.ipady = Integer.parseInt(e.getAttribute("ipady"));
// use reflection to get integer values of static fields
Class<GridBagConstraints> cl = GridBagConstraints.class;
try {
String name = e.getAttribute("fill");
Field f = cl.getField(name);
constraints.fill = f.getInt(cl);
name = e.getAttribute("anchor");
f = cl.getField(name);
constraints.anchor = f.getInt(cl);
}
catch (Exception ex) // the reflection methods can throw various exceptions
{
ex.printStackTrace();
}
Component comp = (Component) parseBean((Element) e.getFirstChild());
add(comp, constraints);
}
/**
* Parse a bean element.
* @param e a bean element
*/
private Object parseBean(Element e) {
try {
NodeList children = e.getChildNodes();
Element classElement = (Element) children.item(0);
String className = ((Text) classElement.getFirstChild()).getData();
Class<?> cl = Class.forName(className);
Object obj = cl.newInstance();
if (obj instanceof Component)
((Component) obj).setName(e.getAttribute("id"));
for (int i = 1; i < children.getLength(); i++) {
Node propertyElement = children.item(i);
Element nameElement = (Element) propertyElement.getFirstChild();
String propertyName = ((Text) nameElement.getFirstChild()).getData();
Element valueElement = (Element) propertyElement.getLastChild();
Object value = parseValue(valueElement);
BeanInfo beanInfo = Introspector.getBeanInfo(cl);
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
boolean done = false;
for (int j = 0; !done && j < descriptors.length; j++) {
if (descriptors[j].getName().equals(propertyName)) {
descriptors[j].getWriteMethod().invoke(obj, value);
done = true;
}
}
}
return obj;
}
catch (Exception ex) // the relflection methods can throw various exceptions
{
ex.printStackTrace();
return null;
}
}
/**
* Parses a value element.
* @param e a value element
*/
private Object parseValue (Element e) {
Element child = (Element) e.getFirstChild();
if (child.getTagName().equals("bean"))
return parseBean(child);
String text = ((Text) child.getFirstChild()).getData();
if (child.getTagName().equals("int"))
return new Integer(text);
else if (child.getTagName().equals("boolean"))
return new Boolean(text);
else if (child.getTagName().equals("string"))
return text;
else
return null;
}
}
XML file:
<?xml version="1.0"?>
<!DOCTYPE gridbag SYSTEM "gridbag.dtd">
<gridbag>
<row>
<cell anchor="EAST">
<bean>
<class>javax.swing.JLabel</class>
<property>
<name>text</name>
<value>
<string>Face: </string>
</value>
</property>
</bean>
</cell>
<cell fill="HORIZONTAL" weightx="100">
<bean id="face">
<class>javax.swing.JComboBox</class>
</bean>
</cell>
<cell gridheight="4" fill="BOTH" weightx="100" weighty="100">
<bean id="sample">
<class>javax.swing.JTextArea</class>
<property>
<name>text</name>
<value>
<string>The quick brown fox jumps over the lazy dog</string>
</value>
</property>
<property>
<name>editable</name>
<value>
<boolean>false</boolean>
</value>
</property>
<property>
<name>lineWrap</name>
<value>
<boolean>true</boolean>
</value>
</property>
<property>
<name>border</name>
<value>
<bean>
<class>javax.swing.border.EtchedBorder</class>
</bean>
</value>
</property>
</bean>
</cell>
</row>
<row>
<cell anchor="EAST">
<bean>
<class>javax.swing.JLabel</class>
<property>
<name>text</name>
<value>
<string>Size: </string>
</value>
</property>
</bean>
</cell>
<cell fill="HORIZONTAL" weightx="100">
<bean id="size">
<class>javax.swing.JComboBox</class>
</bean>
</cell>
</row>
<row>
<cell gridwidth="2" weighty="100">
<bean id="bold">
<class>javax.swing.JCheckBox</class>
<property>
<name>text</name>
<value>
<string>Bold</string>
</value>
</property>
</bean>
</cell>
</row>
<row>
<cell gridwidth="2" weighty="100">
<bean id="italic">
<class>javax.swing.JCheckBox</class>
<property>
<name>text</name>
<value>
<string>Italic</string>
</value>
</property>
</bean>
</cell>
</row>
</gridbag>
DTD File:
<!ELEMENT gridbag (row)*>
<!ELEMENT row (cell)*>
<!ELEMENT cell (bean)>
<!ATTLIST cell gridx CDATA #IMPLIED>
<!ATTLIST cell gridy CDATA #IMPLIED>
<!ATTLIST cell gridwidth CDATA "1">
<!ATTLIST cell gridheight CDATA "1">
<!ATTLIST cell weightx CDATA "0">
<!ATTLIST cell weighty CDATA "0">
<!ATTLIST cell fill (NONE|BOTH|HORIZONTAL|VERTICAL) "NONE">
<!ATTLIST cell anchor (CENTER|NORTH|NORTHEAST|EAST|SOUTHEAST|SOUTH|SOUTHWEST|WEST|NORTHWEST) "CENTER">
<!ATTLIST cell ipadx CDATA "0">
<!ATTLIST cell ipady CDATA "0">
<!ELEMENT bean (class, property*)>
<!ATTLIST bean id ID #IMPLIED>
<!ELEMENT class (#PCDATA)>
<!ELEMENT property (name, value)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT value (int|string|boolean|bean)>
<!ELEMENT int (#PCDATA)>
<!ELEMENT string (#PCDATA)>
<!ELEMENT boolean (#PCDATA)>
Error output:
Warning: validation was turned on but an org.xml.sax.ErrorHandler was not set, which is probably not what is desired. Parser will use a default ErrorHandler to print the first 0 errors. Please call the setErrorHandler method to fix this.
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=13: The content of element type "property" must match "(name,value)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=14: The content of element type "bean" must match "(class,property*)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=15: The content of element type "cell" must match "(bean)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=19: The content of element type "bean" must match "(class,property*)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=20: The content of element type "cell" must match "(bean)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=29: The content of element type "property" must match "(name,value)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=35: The content of element type "property" must match "(name,value)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=41: The content of element type "property" must match "(name,value)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=47: The content of element type "bean" must match "(class,property*)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=48: The content of element type "value" must match "(int|string|boolean|bean)".
java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.DeferredTextImpl cannot be cast to org.w3c.dom.Element
at read.GridBagPane.parseGridbag(GridBagPane.java:76)
at read.GridBagPane.<init>(GridBagPane.java:45)
at read.FontFrame.<init>(GridBagTest.java:48)
at read.GridBagTest$1.run(GridBagTest.java:24)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
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:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
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)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at read.FontFrame.<init>(GridBagTest.java:55)
at read.GridBagTest$1.run(GridBagTest.java:24)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
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:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
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)
Thank you for taking the trouble to read all the above and explaining any problem.
<gridbag>areText(whitespaces),Element(for<row>),Text(whitespaces),Element(for<row>), ...Element(for<row>),Text(whitespaces). You're blindly assuming they are allElement, so you unconditionally cast toElement, and get exception saying that aTextnode cannot be cast toElement.