Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

JVM Languages

J.A.D.E.: The Java Addition to the Default Environment


Feb01: J.A.D.E.: The Java Addition to the Default Environment

An open-source library for Java developers

Jean-Marie is a senior software engineer at Raytheon. He can be contacted at [email protected].


The Java Addition to the Default Environment (J.A.D.E. for short) is an open-source library (available at http://jade.dautelle.com/) that fills gaps in the JDK core library. Among the extensions J.A.D.E. 1.0 includes are XML support for all Java classes, generic matrix classes, automatic error calculation on all operations (including numeric errors), more than 400 measurement units for almost 40 different quantities, automatic unit simplification and verification, and support for enumerated types.

The reasons I developed the J.A.D.E. package include:

  • To eliminate more interface errors. If a method expects a Length, it gets a Length — not some float type that is supposed to be in inches. (This is the kind of problem that led to the 1999 Mars Climate Orbiter fiasco.)
  • Quantities for which precision is unknown are not very useful (especially if they are the solutions of a possibly singular system of linear equations).

  • To eliminate conversion errors. The U.K. gallon is different from the U.S. gallon, which is also different for liquid or dry products.

  • To introduce a Matrix class generic enough to resolve systems of linear equations involving any element: Real, Complex, Big Numbers, Quantities, and the like.

In this article, I'll focus on one of J.A.D.E.'s most useful components — XML support.

XML and Java

In Java and XML (O'Reilly & Associates, 2000), Brett McLaughlin wrote: "Java revolutionized the programming world by providing a platform-independent programming language. XML takes the revolution a step further with a platform-independent language for interchanging data." The question programmers are faced with is how to put the two together.

There are already many open-source libraries available to parse XML documents. For example, using JDOM (http://www.jdom.org/) you can represent XML documents as Java objects. Plus, Sun is currently leading a project that is code-named "Adelard" to generate Java classes from XML Schema.

Unfortunately, the starting point for all of these tools is the XML document. More often than not, it is the other way around — you have Java classes and you want to provide persistency to your existing classes using XML. Here's how J.A.D.E. addresses this particular issue.

Creating Objects from XML

Say you wrote a package to represent two-dimensional areas. Your package possibly includes classes such as Point, Ellipse, Polygon, and Area. As an enhancement, you decide to add the capability to load an area from an XML file.

Using J.A.D.E., all you need to do is to provide an XML constructor for all XML elements involved in the construction process (in this case the geometrical objects). An XML constructor is nothing more than a Java constructor with two parameters--one for the attributes and the other for the child elements. When the XML document is parsed, your constructor is called with the parameters set according to the element's attributes and content. The attributes are simple properties of the object being created (represented by a String), whereas the content is the list of all nested elements that have been created recursively.

Once you have written the XML constructors (see Listing One), this code lets you create an area from a file.

Constructor constructor = new Constructor("org.apache.xerces.parsers.SAXParser");
Area area = (Area) constructor.create(file);

As you can see, you need a SAX 2.0 parser at run time. The binary distribution of J.A.D.E. includes a subset of the Xerces 1.2.0 parser developed by the Apache Software Foundation, but any SAX 2.0 parser will do (for a list of SAX 2.0 parsers go to http://www.megginson.com/SAX/). SAX 1.0 parsers will not work because J.A.D.E. supports namespaces and SAX 1.0 does not. Namespaces map directly to Java packages. Listing Two shows the XML representation of an area without a namespace and Listing Three shows the same area represented using a default namespace; both can be used interchangeably. Also, you may notice that because the class Area may contain instances of itself, the XML representation of an area may include nested area elements.

How Does it Work?

Under the hood, the document handler uses the Reflection API to dynamically create instances of the elements being parsed. How this API works is beyond the scope of this article (for more information read the Reflection API Tutorial at http://web2.java.sun.com/docs/books/tutorial/reflect/index.html).

It is interesting to note that the constructive approach used by J.A.D.E. works even on immutable objects. Another approach using interface (factory method pattern) has been studied but rejected because of its lack of support for these immutable objects.

Saving Objects in XML

In addition to converting XML documents to Java objects, you can also do the reverse. Using J.A.D.E., the instances of a class can be saved in XML format if the class implements the interface com.dautelle .xml.Representable. Basically, the class has to provide two methods: getAttributes() and getContent().

It is up to you to decide what is going to be an XML attribute and what is going to be a child element. Don't forget, however, that if the XML representation of your class is consistent with its XML constructor, then you will be able to save and retrieve any of your Java objects. Listing Four shows the implementation of com.dautelle .xml.Representable for geometrical objects.

Writing a representable object is a two-step process. First, you will need to create an ObjectWriter. This can be done via:

ObjectWriter ow = new ObjectWriter();

Or if you want to use namespaces, you may pass the mapping between the package names and the namespace prefix as argument:

Properties namespaces = new Properties();
namespaces.setProperty("com.dautelle.geom2d", "geom2d");
ObjectWriter ow = new ObjectWriter(namespaces);

The second step is to perform the actual writing. The XML encoding to be used depends on the output type:

  • UTF-8 encoding (1 byte per character) for java.io.OutputStream:

    FileOutputStream out = new FileOutputStream(file);
    ow.write(area, out); // UTF-8 encoding.

  • UTF-16 (2 bytes per character) for java.io.Writer:

    StringWriter sw = new StringWriter();
    ow.write(area, sw); // UTF-16 encoding.

Conclusion

While Java has an excellent API, you cannot always count upon Sun to offer everything you need (or you may wait a very long time). The J.A.D.E. library aims to complement the core JDK. It is open source and will hopefully grow with the contribution of all of you who want to continue to make Java a better platform.

DDJ

Listing One

package com.dautelle.geom2d;
public class Point {
  double x;
  double y;
  // XML constructor.
  public Point(Attributes attributes, Elements content) {
    x = attributes.getDouble("x");
    y = attributes.getDouble("y");
  }
}
public abstract class Surface {}

public class Ellipse extends Surface {
Point center;
  double width;
  double height; 
  // XML constructor.
  public Ellipse(Attributes attributes, Elements content) {
    center = (Point) content.get(0);
    width = attributes.getDouble("width");
    height = attributes.getDouble("height");
  }
}
public class Polygon extends Surface {
  Point [] vertices;
  // XML constructor.
  public Polygon(Attributes attributes, Elements content) {
    vertices = new Point[content.size()];
    content.toArray(vertices);
  }
}
public class Area extends Surface {
  Surface [] surfaces;
  // XML constructor.
  public Area(Attributes attributes, Elements content) {
    surfaces = new Surface[content.size()];
    content.toArray(surfaces);
  }
}

Back to Article

Listing Two

<?xml version='1.0'?>
<com.dautelle.geom2d.Area>
  <com.dautelle.geom2d.Ellipse width="1.0" height="20.0">
    <com.dautelle.geom2d.Point x= "0.0" y="0.0"/>
  </com.dautelle.geom2d.Ellipse>
  <com.dautelle.geom2d.Polygon>
    <com.dautelle.geom2d.Point x= "-1.0" y="-1.0"/>
    <com.dautelle.geom2d.Point x= "0.0" y="1.0"/>
    <com.dautelle.geom2d.Point x= "1.0" y="-1.0"/>
  </com.dautelle.geom2d.Polygon>
  <com.dautelle.geom2d.Area>
    <com.dautelle.geom2d.Ellipse width="1.0" height="20.0">
       <com.dautelle.geom2d.Point x= "0.0" y="0.0"/>
    </com.dautelle.geom2d.Ellipse>
  </com.dautelle.geom2d.Area>
</com.dautelle.geom2d.Area>

Back to Article

Listing Three

<?xml version='1.0'?>
<Area xmlns="java:com.dautelle.geom2d">
  <Ellipse width="1.0" height="20.0">
    <Point x= "0.0" y="0.0"/>
  </Ellipse>
  <Polygon>
    <Point x= "-1.0" y="-1.0"/>
    <Point x= "0.0" y="1.0"/>
    <Point x= "1.0" y="-1.0"/>
  </Polygon>
  <Area>
    <Ellipse width="1.0" height="20.0">
       <Point x= "0.0" y="0.0"/>
    </Ellipse>
  </Area>
</Area>

Back to Article

Listing Four

package com.dautelle.geom2d;
import com.dautelle.xml.*;
public class Point extends Representable {
  double x;
  double y;
  public Attributes getAttributes() {
    Attributes attributes = new Attributes();
    attributes.add("x", x);
    attributes.add("y", y);
    return attributes;
  }
  public Representable[] getContent() {
    return null;
  }
}
public abstract class Surface extends Representable {}

public class Ellipse extends Surface {
  Point center;
  double width;
  double height; 
  public Attributes getAttributes() {
    Attributes attributes = new Attributes();
    attributes.add("width", width);
    attributes.add("height", height);
    return attributes;
  }
  public Representable[] getContent() {
    return new Representable[] { center };
  }
}
public class Polygon extends Surface {
  Point [] vertices;
  public Attributes getAttributes() {
    return null;
  }
  public Representable[] getContent() {
    return vertices;
  }
}
public class Area extends Surface {
  Surface [] surfaces;
  public Attributes getAttributes() {
    return null;
  }
  public Representable[] getContent() {
    return surfaces;
  }
}

Back to Article


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.