Implementation

"There was a sculptor and he found a stone, a special stone. He dragged it home and he worked on it for months, until he finally finished. When he was ready, he showed it to his friends, and they said he had created a great statue. The sculptor said he had not created anything. The statue was always there. He just cleared away to small pieces."

TRAUTMAN, 1988

Abstract

Annotation
This chapter is not essential in understanding the usage of the Java API for KML.

JAK is automatically generated by OGC's KML schema specification file ogckml22.xsd [KML22] and Google's Gx extensions file kml22gx.xsd [KML22GX]. Every time the KML schema evolves, an build cycle is initiated and JAK reflects all changes automatically. This chapter is about the implementation details, why things were done as they are, and how a JAXB plugin does all the automatic API creation.

The build cycle of JAK

To initiate the JAK's automatic build process, an Ant build target is defined. This build target configures JAXB's build options and invokes the XJC schema compiler.

Annotation
Strictly speaking this Ant build target is embedded into a Maven pom.xml and invoked by Maven's maven-antrun-plugin.

Listing 1: Part of Maven's pom.xml script that invokes JAXB's schema compiler and runs a Perl script via Maven's ant-run-plugin. The Perl script cleans all occurrences of the JAXBElement.
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
      <id>xjc-invocation</id>
      <phase>generate-sources</phase>
      <configuration>
        <tasks>
          <property name="src.dir" location="src/main" />
          <property name="src.dir.gen" location="${src.dir}/java" />
          <property name="schema.dir" value="${src.dir}/resources/schema" />
          <property name="schema.dir.kml" location="${schema.dir}/ogckml/ogckml22.xsd" />
          <property name="schema.dir.kml.binding" value="${schema.dir}/ogckml/JAK_binding.xjb" />
          <taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask" classpathref="maven.compile.classpath" />
          <description>generate JAK from OGC's KML schema</description>
          <mkdir dir="${src.dir.gen}/de/micromata/opengis/kml/" />
          <delete>
            <fileset dir="${src.dir.gen}/de/micromata/opengis/kml/" includes="**" />
          </delete>
          <xjc extension="true" binding="${schema.dir.kml.binding}" destdir="${src.dir.gen}" removeOldOutput="yes"
            schema="${schema.dir}/ogckml/kml22gx.xsd">
            <arg value="-XJavaForKmlApi" /> <!-- the XJC plugins that creates JAK -->
          </xjc>
          <exec executable="perl" dir="${basedir}"> <!-- remove the damn JAXBElements -->
            <arg file="scripts/CleanUpGeneratedJAXBSourceFolder.pl" /> 
            <arg file="${src.dir.gen}/de/micromata/opengis/kml" />
          </exec>
        </tasks>
      </configuration>
      <goals>
        <goal>run</goal>
      </goals>
    </execution>
  </executions>
</plugin>

With the invocation of the build target shown, Listing 1 in the build cycle is started (a graphical presentation of the build cycle can be found in Figure 2). It can be called with the command mvn install. This invokes JAXB's schema compiler (XJC) and generates the Java API for KML. JAXB binds Google's Gx extensions schema kml22gx.xsd to automatically generated classes, which are annotated with an implicit schema definition by the schema compiler. In Listing 1 only the kml22gx.xsd is mentioned. Due to an internal link defined in Google's Gx extensions schema OGC's KML schema is implicitly considered by the build process.

As to be expected, JAXB's schema compiler is not able to determine the desired result of the generated Java code from the XML schema by itself. The creation process of Java's data-model has to be tweaked with JAXB's binding customizations, as many name clash errors occur. The binding customizations needed for compiling both KML schemas can be found in the file JAK_binding.xjb. The XJC plugin used is explained below at JAK's XJC Plugins.

A Perl script using regular expression is invoked (seen in Figure 2 and in Listing 1) after the POJOs are generated as Java source files. It removes all JAXBElement occurrences in the generated files. XJC creates 132 Java source files from the KML schema with 632 fields encapsulated into JAXBElement. A complete reference of which elements are affected can be found at Figure 1. It is similar to the one shown as KML in the Java world#Figure 1. It shows the KML reference of all types defined in the KML schema which need to be mapped to a Java class. The difference is that the types that could not be resolved correctly are marked in amber. Thus, each time they are referred to in a POJO as a field, they are encapsulated into a JAXBElement. XJC creates 132 classes from the KML schema. With the default binding mode as defined in the JAXB's specification, 632 fields are encapsulated into JAXBElements; even with the simpler and better binding mode, XJC is not able to resolve all types correctly and encapsulates 635 fields into JAXBElements (three more!).


Figure 1: Elements/classes marked in amber are not correctly resolved during the code generation process and, as a result, are encapsulated into JAXBElements.

Maven automatically compiles the generated POJOS and tests them using predefined use-cases. The use-cases are composed of JUnit and XMLUnit defined in the ATC and the KML reference. The ATC defines 77 use-cases considered to make an OGC conform KML implementation [OGC07D], whereas 73 examples were taken from the KML reference and implemented as use-case [KML09]. These points were modeled as JUnit tests. They serve to check that the API fulfills all requirements.

The next three listings show such a use-case. It is an example taken from [KML09] and shows the creation of a Placemark element that contains a Point element:

Listing 2: Example taken from KML09. It shows the creation of a Placemark element containing a Point element.
<Placemark>
  <name>Google Earth - New Placemark</name>
  <description>Some Descriptive text.</description>
  <LookAt>
    <longitude>-90.86879847669974</longitude><latitude>48.25330383601299</latitude>
    <range>440.8</range><tilt>8.3</tilt><heading>2.7</heading>
  </LookAt>
  <Point>
    <coordinates>-90.86948943473118,48.25450093195546,0</coordinates>
  </Point>
</Placemark>

All examples taken from the KML reference were defined as shown in Listing 2. The use-cases, labeled as ATC (Abstract Test Case) defined in the ATS are in a more abstract form:

ATC 67 Placemark
IDENTIFIER http://www.opengis.net/kml/2.2/atc/level-2/Placemark
TEST PURPOSE Check if a kml:Placemark element is not a descendant of kml:Update, it includes a geometry element (any element that substitutes for kml:AbstractGeometryGroup
TEST METHOD Pass if the assertion is satisfied; fail otherwise
REFERENCE OGC-07-147r2: cl. 9.11.2
TEST TYPE Basic
Table 1: Exemplary the 67th test defined in the ATS.

These use-cases are now transformed into Java programs as shown next:

Listing 3: The KML document shown in Listing 2 is done programmatically with JAK. The Check.placemarkExample() method is called twice.
Placemark placemark = new Placemark()
    .withName("Google Earth - New Placemark")
    .withDescription("Some Descriptive text.");

placemark.createAndSetLookAt()
    .withLongitude(-90.86879847669974).withLatitude(48.25330383601299)
    .withRange(440.8).withTilt(8.3).withHeading(2.7);

placemark.createAndSetPoint()
    .addToCoordinates("-90.86948943473118,48.25450093195546,0");

Check.placemarkExample(placemark);
Placemark marshalledAndBackAgain = TestUtil.marshalAndUnmarshall(placemark);
Check.placemarkExample(marshalledAndBackAgain);

The code of Listing 3 should be self-explanatory as its structure is similar to the listings in Usage and KML in the Java world. As before, 1) it creates a Java object model (line 01 to 10), which 2) is marshalled and unmarshalled again with the marshalAndUnmarshall method (line 13). This method is a help-method which does the same as KML in the Java world#Listing 6.

Before the data structure is marshalled into a file, a method with several JUnit asserts is invoked. They ensure that the actual result matches the expected results as defined in the use-case.

Listing 4: This method defines JUnit asserts for every element in Listing 2.
public static void placemarkExample(final Placemark placemark) {
  Assert.assertEquals("Google Earth - New Placemark", placemark.getName());
  Assert.assertEquals("Some Descriptive text.", placemark.getDescription());

  LookAt lookat = (LookAt) placemark.getAbstractView();
  Assert.assertEquals(-90.86879847669974, lookat.getLongitude(), 0.0001);
  Assert.assertEquals(48.25330383601299, lookat.getLatitude(), 0.0001);
  Assert.assertEquals(440.8, lookat.getRange(), 0.0001);
  Assert.assertEquals(8.3, lookat.getTilt(), 0.0001);
  Assert.assertEquals(2.7, lookat.getHeading(), 0.0001);

  Assert.assertEquals(new Coordinate(-90.86948943473118, 48.25450093195546, 0.0), 
                      ((Point) placemark.getGeometry()).getCoordinates().get(0));
}

If Listing 4 results in a green-colored bar, the data structure is finally marshalled into a file. This file is then marshalled back into an object graph and the object returned is checked again by the Check.placemarkExample() method.

In each build iteration cycle three things were constantly checked:

  • That the output java code is complete and correct. Signifies, that no syntax or compile errors at the tests are present, e.g. in the Placemark test shown in Listing 3.
  • That the tests are able to write out KML code. Signifies, that the tests succeed with the display of a green-colored bar, e.g. Listing 3 in line 14.
  • That the tests are able to read in KML code. Signifies, that the tests succeed with the display of a green-colored bar, e.g. Listing 3in line 14.

If all tests pass with a green-colored bar and no syntax errors prevent Maven from compiling the generated source files, the result of a build cycle is the Java API for KML. If not, the code generating XJC plugins are modified and the build cycle is iterated again until the desired result is created and all requirements are fulfilled.

Figure 2 is a graphical representation of this build cycle described above:


Figure 2: The code generation process of JAK. This is a graphical representation of the processes triggered by Listing 1.

XJC Plugins or the "Implementation of the Java API for KML"

JAXB's plugin mechanism allows accessing the semantic information of the XML schema during the code creation process to determine what kind of classes and properties are going to be generated. Thus, it opens up the possibility of generating the semantic application layer rather than coding it by hand. The Java API for KML is not artificially divided into two layers anymore. They are merged together. As a result, the Generation Gap mentioned by Fowler disappears completely. This procedure has the advantage that each plugin only influences a small part of the API, and is build incrementally in small steps.

As mentioned at KML in the Java world the KML standard seems to be stable, but if the KML schema evolves and a new version of the standard is defined, only the schema defining XML files need to be exchanged and a proper semantic model of the KML API is automatically build upon, which reflects all changes. This makes it possible to adapt to changes quickly and in a fully automatic.

This chapter acts as a plugin catalog, similar to Gamma's Pattern catalog [GAM95]. All XJC plugins are described in a common format.

Each XJC plugin justifies itself why it was created, followed by a short description about its purpose, and how it influences the created code. In most cases, a short of the default code generated followed by a short example the improved code is given.

The plugins are released under a BSD license and can be found at: http://code.google.com/p/xjcpluginjavaapiforkml/


Figure 3: Screenshot of the XJC plugins creating the Java API for KML hosted at Google Code.

Alternatively in the official dev.java.net Maven 2 repository:

Listing 5: JAK at maven2-repository.dev.java.net
<dependencies>
    ...
   <!-- The XJC Plugin -->
   <!-- It is able to create the API (only needed if OGC's KML schema changes) -->
   <dependency>
      <groupId>de.micromata.jak</groupId>
      <artifactId>XJCPluginJavaApiforKml</artifactId>
      <version>1.0.1-SNAPSHOT</version>
   </dependency>
    ...
</dependencies>
<repositories>
    ...
   <repository>
      <id>maven2-repository.dev.java.net</id>
      <name>Java.net Maven 2 Repository</name>
      <url>http://download.java.net/maven/2</url>
      <layout>default</layout>
      <snapshots>
         <enabled>true</enabled>
      </snapshots>
      </repository>
</repositories>

Create missing Icon class

WHY:

The schema compiler does not create the Icon class. It is created with a XJC plugin.

DESCRIPTION:

OGC's KML standard defines an Icon element [KML09]. According to the standard, the Icon element has the same child elements as the Link element. As the Link element, it defines a required href child element, too.
Unfortunately, JAXB's schema compiler does not create the Java counterpart of this element. This plugin creates the missing Icon class. This is essential to fulfill the following use-cases defined in the ATC [OGC07A, OGC07D]:

  • ATC 18: Icon - href
    Verify that the Icon/href element refers to an image resource.
  • ATC 35: PhotoOverlay - minimal content
    Check that if a PhotoOverlay element is not a descendant of Update, it must includes all of the following child elements: Icon, ViewVolume, Point, and Camera.
  • ATC 40: Link
    Check that if a Link or an Icon element is not a descendant of Update, then it contains an href child element.
  • ATC 51: Link refresh values
    Check that a Link or an Icon element (of type LinkType) satisfies all of the following constraints: if the refreshInterval element is present, the refreshMode value must be onInterval; if the viewRefreshTime element is present, the refreshMode value must be onStop.
  • ATC 52: PhotoOverlay
    Check that if a PhotoOverlay element includes a Icon/href element containing x, y, and level parameters, it also must include a child ImagePyramid element; the opposite must also be true
  • ATC 56: Overlay
    Check that if any element that substitutes for AbstractOverlayType is not a descendant of Update, it must contain an Icon child element.

A missing Icon class result in compile errors and the tests will not even be able to run, nor can be passed with a green-colored bar.

Add missing @XmlRootElement annotations

WHY:

JAXB's schema compiler is sometimes not able to resolve all elements as desired, hence they are not annotated with the @XmlRootElement annotation and encapsulated into a JAXBElement. These elements are difficult to be used and their KML representation is not as desired. This XJC plugin adds the missing @XmlRootElement annotation. The JAXBElements are removed with a Perl script.

DESCRIPTION:

Every top level class or enum type that is annotated with the @XmlRootElement annotation can be represented as a KML element in an KML document.
If the @XmlRootElement annotation is missing the marshalled KML looks like this:

Listing 6: Shows the faulty KML representation of an Icon element with missing a @XmlRootElement annotation.
<Icon xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LinkType">
   <href>...</href>
</Icon>

This plugin adds all missing @XmlRootElement annotations to all classes that cannot be resolved correctly by the schema compiler and as a result are encapsulated into a JAXBElement (all amber colored elements in Figure).
These classes are: AltitudeMode, PhotoOverlay, ScreenOverlay, GroundOverlay, Folder, Document, NetworkLink, Placemark, GxTour, Point, LineString, LinearRing, Polygon, Link, Icon, MultiGeometry, Model, LatLonBox, LatLonAltBox, Style, StyleMap, TimeSpan, TimeStamp, Camera, and LookAt.

Exemplary for the Icon class:

Listing 7: The @XmlRootElement annotation added to the Icon class.
@XmlRootElement(name = "Icon", namespace = "http://www.opengis.net/kml/2.2")
public class Icon ...

Every top level class or enum type that is annotated with the @XmlRootElement annotation can be represented as KML element in an KML document.

The Icon element is now represented as desired and correct in the resulting KML document:

Listing 8: Shows the correct KML representation of an Icon element with a @XmlRootElement annotation.
<Icon>
   <href>...</href>
</Icon>

Convert boxed primitives to primitive types

WHY:

JAXB uses boxed primitives wherever possible. This plugin converts them back to primitive types only, to prevent autoboxing.

Description:

Java has a two-part type system:

  • Primitives, such as int, float, double, and boolean.
  • Boxed primitives. Each primitive type has a corresponding boxed primitive counterpart, such as Integer (for int), Float (for float), ...

Primitives cannot be put into collections. They had to be put in an appropriate wrapper class (which is Integer in the case of int). Before Java 1.5 the conversion between primitive and boxed primitives had to be done by hand, e.g. in the case of Integer unboxed with the intValue() method. The autoboxing and auto-unboxing feature in the Java 1.5 release automates this process.

In his book Effective Java [BLO08], Bloch gives at Item 49, the advice to prefer primitives types to boxed primitives types wherever possible. He states that primitive types are simpler to use and faster than boxed types.

The code JAXB's schema compiler generates uses boxed primitives by default:

Listing 9: The Coordinate class with boxed primitives.
public class Coordinate {
  private Double longitude = 0.0D;
  private Double latitude = 0.0D;
  private Double altitude = 0.0D;
  ...

This plugin changes all plugins to primitive types again:

Listing 10: The Coordinate class with primitives.
public class Coordinate {
  private double longitude = 0.0D;
  private double latitude = 0.0D;
  private double altitude = 0.0D;
  ...

Create Coordinate class

WHY:

OGC's KML schema specification defines coordinates as a list of strings. A coordinate consists of the three values longitude, latitude, and altitude. This plugin changes the String representation of coordinates to double. They reflect more the real intent of these values. This makes arithmetic operation easier and faster compared to using a String representation. The conversion from String to double is done transparently to the user by JAK.

DESCRIPTION:

This plugin creates a Coordinate class. It was first introduced in KML in the Java world. The plugin changes the internal coordinate representation from String coordinates to List<Coordinate> coordinates and tells JAXB to use a custom XML adapter. The adapter is able to unmarshal the coordinates from String to List<Coordinate> and to marshal them from List<Coordinate> to String.


Figure 4: The coordinate converter.

Clients of the API are able to perform arithmetic operation direct with longitude, latitude, and altitude contained in each coordinate and do not have to parse them from their former String representation to double values. This all happens automatically by JAK.

Create equals() and hashCode() methods

WHY:

The schema compiler does not create equals() and hashCode() methods. They are both needed to compare the semantic comparability between object instances. Hence, they are created with this XJC plugin.

DESCRIPTION:

In his book Effective Java [BLO08], Bloch gives at Item 9 and Item 10 the advice to provide always correct implementations of equals() and hashCode().
There already exist two JAXB Plugins that provide the same functionality, but they where not chosen, since their dependency on the external library org.apache.commons.lang would bloat the Java API for KML unnecessarily (at http://commons.apache.org/lang/).

This XJC plugin generates this method pair to each generate class. They are implemented as recommended by Bloch in [BLO08]. Hence, all object instances can be compared to each other. These methods are implicitly needed, e.g. to compare two different coordinate object instances by JUnit's assert method:

Listing 11: assertEquals will result in green-colored bar if the equals() and hashCode() method are created, otherwise the test will fail.
Coordinate coord1 = new Coordinate("9.444652669565212,51.30473589438118,0");
Coordinate coord2 = new Coordinate("9.444652669565212,51.30473589438118,0");

Assert.assertEquals(coord1, coord2);

Create marshal and unmarshal methods

WHY:

This plugin creates marshal and unmarshal methods for convenience to the Java API for KML. These methods save a lot of boilerplate code the clients would have to implement on their own otherwise and should satisfy most user requirements. As result, JAXB is hidden from the user, the API is clean, and the entry level for new users is lowered.

DESCRIPTION:

The marshal and unmarshal methods described here, were previously introduced in KML in the Java world#Figure6. It is still possible to use JAXB's own methods to marshal and unmarshal if needed (or forced).
The Kml class offers five different methods to marshal:

  • marshal()
    This is a convenience method for kml.marshal(System.out). It marshals the object graph to the console.
  • marshal(File)
    The object graph is marshalled to a File object. The object graph is not saved as a zipped .kmz file.
  • marshal(OutputStream)
    Similar to the method above but with the exception that the object graph is marshalled to an OutputStream object instead. The object graph is not saved as a zipped .kmz file.
  • marshal(Writer)
    Similar to the method above but with the exception that the object graph is marshalled to a Writer object instead. The object graph is not saved as a zipped .kmz file.
  • marshalAsKmz(String, Kml...)
    The object graph is zipped as a .kmz file. A filename for the .kmz file is mandatory. Additional Kml objects can be placed inside the .kmz file. They are saved under their name defined in kmzFile.getFeature().getName() followed by a .kml suffix. If kmzFile.getFeature().getName() is null an automatic incrementing default name is choosen "noFeatureNameSet"+ (missingNameCounter++) +".kml").

Additionally, the Kml class offers five unmarshal methods:

  • unmarshal(File, boolean)
    KML given as a file object is transformed into a graph of Java objects. The boolean value indicates, whether the File object should be validated automatically during unmarshalling and be checked if the object graph meets all constraints defined in OGC's KML schema specification.
  • unmarshal(File)
    Similar to the method above but with the exception that the File object is not validated (boolean is false).
  • unmarshal(String)
    Similar to the method above but with the exception that it transforms a String into a graph of Java objects. The String is not validated (boolean is false)
  • unmarshal(InputStream)
    Similar to the method above but with the exception that it transforms a InputStream into a graph of Java objects. The String is not validated (boolean is false)
  • unmarshalFromKmz(File) : Kml[]
    Similar to the other unmarshal methods with the exception that it transforms a KMZ-file into a graph of Java objects. Since each .kmz file could contain more than one .kml file, the method returns an array of Kml objects.

Create the fluent and convenient side of the Java API for KML

WHY:

The default code created by JAXB seems a bit bumpy and verbose. Additionally it is made easy to forget registering a child element to its parent element. This plugin creates a fluent interface and some convenience methods for the API.

DESCRIPTION:

The fluent interface and the associated convenience methods (createAndSet, createAndAdd, addTo, ...) created by this plugin, were described in detailed in KML in the Java world. They allow method chaining and create a less verbose, more readable, and, as the name implies, a flowing programming style.
The programmatically creation of a Placemark element with a Point while lacking the fluent and convenient methods:

Listing 12: The creation of a Placemark element with a Point programmatically with JAK.
Kml kml = KmlFactory.createKml();
Placemark placemark = KmlFactory.createPlacemark();
placemark.setName("Java User Group Hessen - JUGH!");
placemark.setVisibility(true);
placemark.setOpen(false);
placemark.setDescription("die Java User Group Hessen");
placemark.setStyleUrl("styles.kml#jugh_style");

Point point = KmlFactory.createPoint();
point.setExtrude(false);
point.setAltitudeMode(AltitudeMode.CLAMP_TO_GROUND);
point.getCoordinates().add(new Coordinate("9.444652669565212,51.30473589438118,0"));

placemark.setGeometry(point);      // <-- point is registered at placemark ownership
kml.setFeature(placemark);         // <-- placemark is registered at kml ownership.
kml.marshal(System.out);           // <-- Print the KML structure to the console.

The same example with fluent style and convenient methods:

Listing 13: Utilizes the fluent and convenience methods provided by JAK. Compared to [Listing 7
Kml kml = KmlFactory.createKml();
kml.createAndSetPlacemark()
   .withName("Java User Group Hessen - JUGH!")
   .withVisibility(true)
   .withOpen(false)
   .withDescription("die Java User Group Hessen")
   .withStyleUrl("styles.kml#jugh_style")
   .createAndSetPoint()
      .withExtrude(false)
      .withAltitudeMode(AltitudeMode.CLAMP_TO_GROUND)
      .addToCoordinates("9.444652669565212,51.30473589438118,0");
kml.marshal(System.out);

The fluent and convenience methods peacefully coexist among the other methods created in the POJOs and can be used interchangeable.

Create KMLFactory (and delete JAXB's ObjectFactory)

WHY:

JAXB creates an ObjectFactory in each created package. JAXB's ObjectFactory does not offer any static methods and is the source of many name clash errors during code generation. This plugin deletes JAXB's ObjectFactory and creates a new one, called KmlFactory, with only static factory methods.

DESCRIPTION:

JAXB creates a separate ObjectFactory file for each package. In the case of JAK, it creates four files. The ObjectFactory is created for historically reasons [KOH05C] and to simplify the creation of objects the schema compiler was not able to resolve correctly and which are encapsulated within JAXBElements.

Listing 14: Playlist element returned by JAXB's ObjectFactory. The playlist element is created an immediately returned to the overloaded createPlaylist method, which encapsulates the playlist object into a JAXBElement.
de.micromata.opengis.kml.v_2_2_0.gx.ObjectFactory ob 
             = new de.micromata.opengis.kml.v_2_2_0.gx.ObjectFactory();
JAXBElement<Playlist> p = ob.createPlaylist(ob.createPlaylist());

In his book Effective Java [BLO08], at Item 1 Bloch gives the advice to consider static factory methods instead of constructors. The XJC plugins and the Perl script used to create the Java API for KML remove all JAXBElement occurrences. This makes JAXB's object factories obsolete. They are all deleted and replaced by a single factory class, called KmlFactory. The KmlFactory described here, was previously introduced at KML in the Java world. It assembles static creation methods for all elements defined by OGC's KML standard, Google's GX extensions, xAL.xsd and atom-author-link.xsd. Elements defined in an other package than KML's default package, have its package name put between 'create' an the elements name.

Listing 15: A static creation method of the KmlFactory. No object instance of the factory needs to be created and because all JAXBElements were removed at the build process no overloaded create method are needed to encapsulate elements into JAXBElements.
Playlist p = KmlFactory.createGxPlaylist();

It is still possible to create object instances with the keyword new, e.g. new Placemark().

@Obvious

WHY:

Adam Bien writes in his blog and teaches at his workshops that most of the Javadoc comments in projects are worthless [BIEN07]. Existing information from the method's signature is replicated to the Javadoc. This plugin removes all redundant information and annotates the getters and setters with the @Obvious annotation.

DESCRIPTION:

JAXB's schema compiler generates very verbose and redundant Javadoc comments for each method. Bien states that obvious facts should not be described repeatedly. That it is more important to pick up the 'why' from the obvious 'noise'. This kind of documentation is unnecessary and injures the DRY principle, since every Java developers knows what getters and setters are.
One classic example created by JAXB (that probably can be found in a similar manner in many projects):

Listing 16: Existing information from the method's signature is replicated to the Javadoc.
/**
 * Gets the value of the name property.
 * 
 * @return
 *     possible object is
 *     {@link String}
 *     
 */
public String getName() {
  return name;
}

/**
 * Sets the value of the name property.
 * 
 * @param value
 *     allowed object is
 *     {@link String}
 *     
 */
public void setName(String value) {
  this.name = value;
}

Bien suggests introducing a new Javadoc-tag or annotation to mark such use cases. For example: @Obvious. This plugin removes unnecessary and redundant Javadoc generated by XJC's default implementation as seen in Listing 16 and replaces it through the @Obvious annotation:

Listing 17: Same as Listing 16, but only documented with the @Obvious annotation.
@Obvious 
public String getName() {
  return name;
}

@Obvious 
public void setName(String value) {
  this.name = value;
}

Documenting the Java API for KML

WHY:

Besides the high-level documentation of an API, all exposed API elements need to be documented. This plugin creates the low-level documentation for the Java API for KML.

DESCRIPTION:

Jeff Atwood states, "If It Isn't Documented, It Doesn't Exist" [COD07] and Adam Bien states that most of the documentation hurts the DRY principle, since it only replicates existing information from the method's signature in the Javadoc [BIEN07]. A difficult and time-consuming task is, to keep the code synchronized with the documentation.

The KML reference [KML22] offers a very rich and detailed documentation to every element defined by OGC's KML standard and Google's GX extensions:


Figure 5: The Placemark element documented in the KML reference.

The Java API for KML is a direct representation of the KML specification. Everything that can be expressed in KML can be expressed with the Java API for KML, too. Why should not JAK's documentation be a direct representation of the KML reference?

This plugin parses the KML reference and transform it into Javadoc comments. These comments are automatically attached to all elements generated during the code generation phase. This avoids the previously mentioned difficulties to keep the documentation synchronized with the code, as the documentation is able to build itself. Clients of the API are able to see, the purpose of each element. Further, how and why it is used:


Figure 6: Tooltip text with the automatic generated documentation, exemplary for Placemark.

Bibliography
BIEN07 Adam Bien; How to Javadoc (efficient and maintainable); http://www.adam-bien.com/roller/abien/entry/how_to_javadoc_efficient_and

BLO08 JOSHUA BLOCH; Effective Java: A Programming Language Guide; Addison-Wesley (2008)
COD07 JEFF ATWOOD; Coding Horror - If It Isn't Documented, It Doesn't Exist; http://www.codinghorror.com/blog/archives/000776.html

GAM95 ERICH GAMMA, RICHARD HELM, RALPH E. JOHNSON, JOHN VLISSIDES; Design Patterns. Elements of Reusable Object-Oriented Software. Addison-Wesley Longman, Amsterdam; 1st ed., Reprint. (March, 14th 1995)
KML09 GOOGLE CODE; KML Reference; http://code.google.com/apis/kml/documentation/kmlreference.html

KML22 OGC; OGC KML standard; http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd

KML22GX GOOGLE CODE; Google's Gx extension; http://code.google.com/intl/de/apis/kml/schema/kml22gx.xsd

KOH05C KOHSUKE KAWAGUCHI; A story of migration from JAXB 1.0 to 2.0 http://weblogs.java.net/blog/kohsuke/archive/2005/08/a_story_of_migr.html

OGC07A OGC; OGC KML 2.2 - Abstract Test Suite (1.0.0); 07-147r2_OGC_KML_2.2.pdf; http://www.opengeospatial.org/standards/kml/

OGC07D OGC; Abstract Test Suite; OGC 07-134r2.pdf; http://portal.opengeospatial.org/files/index.php?artifact_id=27811

Searching JAK

Java API for KML | @Google


GWiki
Hibernate History
JAK
Java Templates
Micromata Labs
ProjectForge
Schrödinger
Transec
XML-to-ODT

Labels

coding coding Delete
kml kml Delete
bien bien Delete
ogc ogc Delete
source source Delete
license license Delete
java java Delete
jak jak Delete
plugin plugin Delete
automatic automatic Delete
api api Delete
google google Delete
generated generated Delete
horror horror Delete
open open Delete
maven maven Delete
bsd bsd Delete
obvious obvious Delete
micromata micromata Delete
implementation implementation Delete
hosting hosting Delete
perl perl Delete
xjc xjc Delete
jaxb jaxb Delete
ant ant Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.




PageRank verified www.micromata.de/