1

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.

2
  • The child nodes of <gridbag> are Text (whitespaces), Element (for <row>), Text (whitespaces), Element (for <row>), ... Element (for <row>), Text (whitespaces). You're blindly assuming they are all Element, so you unconditionally cast to Element, and get exception saying that a Text node cannot be cast to Element. Commented Apr 18, 2020 at 6:38
  • Thank you, Andreas. That's a very good reminding. Actually, the program has done "factory.setIgnoringElementContentWhitespace(true);", which ignores all whitespaces in the XML file while parsing. The problem now is solved. The XML file parsed by the program has spaces encoded c2a0, which are not normal spaces. So, the parser cannot identify those "unknown" spaces. Hence the problem. Commented Apr 18, 2020 at 8:01

1 Answer 1

1

before doing this and force the casting -> Element row = (Element) rows.item(i);

You have to check if it is really an Element

if(rows.item(i).getNodeType() == Node.ELEMENT_NODE){
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your suggestion. It's necessary to make sure that the item is an Element first before further processing. The problem with the program seems to be the specially-encoded spaces in the XML file, which confused the parser. I've replaced the special spaces with normal spaces. Now the problem runs without a hitch.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.