Tuesday, August 30, 2011

Java Posts of Interest - 30 August 2011

There has been another flurry of interesting posts related to Java in recent days and weeks that I want to capture brief references to in this post. I narrowed down the list for this post to JVM Language Summit 2011, NetBeans, Scala for the Impatient, Heroku for Java, detecting deadlocks with JCarder, Java NIO versus Java IO, unit testing, and the HotSpot JVM flag PrintCompilation.


JVM Language Summit 2011 Presentations

Video and presentation slides (PDF) from the JVM Language Summit 2011 are now available for download. This event was held July 18-20, 2011, on Oracle's Santa Clara campus.

The list of presentations available for viewing/download include Method Handles and Beyond..., Brian Goetz Java SE 8 topics From Lambdas to Bytecode and Virtual Extension Methods, and JSR 292 Cookbook.


NetBeans

I wasn't the only one blogging about NetBeans in recent days and weeks. NetBeans 7 seems to be generating a lot of buzz online right now.

Geertjan Wielenga posts on NetBeans on a daily basis. In fact, his short biographical paragraph currently states that the focus of his blog " is mostly on NetBeans, with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans." Geertjan has had several particularly interesting posts on NetBeans in recent days including Disable Error Warnings in NetBeans IDE (including editing of netbeans_default_options property in etc/netbeans.conf) and XML Schema Editor in NetBeans IDE 7.0.1 (which I referenced in my own post).

Javin's post How to view javadoc in Netbeans IDE 7.0 lists three ways to view Javadoc documentation in NetBeans and a feedback comment points out use of UMLGraph as well. Robert Hollencamp's post Netbeans Conditional Breakpoints does not list the version of NetBeans as far as I can tell, but does document extremely slow reproducible performance related to a conditional breakpoint in some sample code he provides.

Finally, there is a NetBeans IDE 7 Satisfaction Survey intended for developers who have used or are using NetBeans 7.0 or NetBeans 7.1.


PrintComplilation Flag

Stephen Colebourne has done a nice job of making significant portions Moazam Rajas's Sun post on the HotSpot JVM flag -XX:+PrintCompilation more easily accessible. RĂ©mi Forax, in a response comment, points out the HotSpot Internals Wiki Home Page.

In the early days of the web, links went away all the time and some things were lost for good. It seems as if things have improved over the years in terms of longevity of links and book authors have even referenced links. However, events like the closing down of GeoCities, mergers and acquisitions of companies with their blogs, and developers simply removing their own blogs have made resources like the Internet Archive WayBack Machine invaluable.


Scala for the Impatient

In his post Scala for the Impatient—Free Chapters at typesafe.com, Cay Horstmann describes the book he is writing on Scala (Scala for the Impatient) and provides a link to a free (except for the cost of signing up for the Typesafe newsletter) electronic copy of portions of this book.


Heroku for Java

Heroku for Java has been really big news this week. Not surprisingly, Play! on Heroku has now been announced as well. However, not everyone is ready to throw their Java EE out.


Detecting Java Deadlocks with JCarder

Charith Dhanushka's post Understanding and Terminating the Enemy - Deadlocks describes the conditions under which deadlock can occur in Java. He then introduces use of the open source dynamic analysis tool JCarder to detect deadlocks.


Java NIO versus Java IO

Jakob Jenkov's post Java NIO vs. IO addresses the question, "When should I use IO and when should I use NIO?" There is also a Java NIO: Introduction available at this site.


Java Looking Good for a Dead Language

I have posted before on the exaggerated claims of Java's death and a seeming resurgence of renewed interest in Java in recent months. Several recent posts show this to be a continuing trend. Adam Bien highlights that Java is still the most searched for language (and has increased its month-to-month interest) according Tiobe's August 2011 index. In a separate post, Bien explains reasons that it is important to choose the #1 language for enterprise projects.


Breaking Away From The Unit Test Group Think

The Cedric Beust post Breaking Away From The Unit Test Group Think is excellent. I think that the vast majority of experienced Java developers (or developers in any language) would agree that unit tests are important. I may like Beust's post so well because he articulates precisely my thoughts on unit testing. As he emphasizes, unit testing is important, but it should not preclude other types of testing and TDD is not the only way to make effective use of unit tests. Beust can write these things with some established credibility as the creator of TestNG Java testing framework.


Conclusion

This post has referenced and briefly summarized a few Java-related posts that I have found interesting in recent days and weeks.

Monday, August 29, 2011

Configuring SQE Plugins in NetBeans 7

My last post (NetBeans 7 and Software Quality Environment) focused on using the NetBeans 7 Plugins Manager to acquire Software Quality Environment (SQE) and install its four plugins for four software quality tools (Dependency Finder, PMD, FindBugsTM, and Checkstyle). That post also briefly covered how to use each of these in NetBeans. In this post, the focus shifts to configuring and customizing the quality tools plugins in NetBeans.

Code analysis tools such as PMD, Checkstyle, and FindBugsTM tend to provide methods for configuring and tailoring the types of code issues identified by the tool. This is a welcome feature because not all findings are created equal and some matter more than others. Indeed, some findings are very subjective and a particular individual, team, or project may decide to NOT apply certain recommendations provided by these tools. In these tools' traditional uses, this configuration enables fewer "findings" to be reported and increases the probability that any reported finding is one worth the time to investigate and fix.

When running these code analysis tools in NetBeans, this desire to only see warnings and findings of significance is just as beneficial as it is when running the tools standalone as part of build scripts or when manually run against the source code. I like to have my source code free of any of the yellow or red findings NetBeans produces for hints, warnings, and errors. Similarly, I like my code to be free of the findings identified by the code analysis tools. In most cases, this means fixing the finding, but sometimes I don't agree with the finding. The ability to configure what the tools report is useful for removing reporting of findings that I don't consider to be findings at all.

It is easy to configure the code analysis tools on a per-project basic. To do so, right click on the project of interest in the "Projects" window (accessible using CTRL+1). Right-clicking on the project of interest in the "Projects" window leads to a drop-down menu like that shown in the next screen snapshot. One clicks on the "Properties" at the bottom to configure various project properties, including code analysis tools properties.


The result of clicking on the "Properties" selection after right-clicking on the project of interest is shown in the next screen snapshot. Note that in this case, the "Project Properties" window has "Sources" highlighted under "Categories."


To configure the code analysis tools plugins provided by SQE, the apropos tool name must be selected in the "Project Properties" window's "Categories" area. Selecting the higher-level "Quality" is not very exciting. Instead, one of the specific tools' names should be selected. The next screen snapshot indicates what the Project Properties window looks like when PMD is selected.


As this screen snapshot indicates, disabling any type of finding ("rule") in the PMD plugin is as simple as unchecking the box under "Enabled" for that particular rule. For someone with great familiarity with the PMD tool, it is likely that the names of the rules will make it obvious what rules are represented. For those who lack that familiarity, clicking on the particular rule of interest leads to more details on that rule being displayed. The next screen snapshot demonstrates an example of this for the "SystemPrintln" rule.


As the screen snapshot demonstrates, the two previously empty fields are filled with more details on the PMD rule selected. The middle field provides a brief textual description of the rule and the bottom field shows a code sample of the particular code situation the rule is intended to identify. As with the NetBeans hints, one could learn a lot about what are generally good ideas and generally bad ideas in Java by simply clicking on each rule one-by-one and reading the descriptions and seeing the code examples of those issues.

Configuring the FindBugsTM plugin for the project is similar. The next screen snapshot demonstrates how this appears in NetBeans 7 when "FindBugs" is selected in the "Project Properties" window. Notice that the default tab opened for this is "Configure Detectors" and that, like the PMD "rules," no particular "Bug Detector" is selected initially. Clicking on any rule leads to a description of the detector being placed in the previously empty field. This is shown in the next screen snapshot. Hovering over the description leads to the extra information in the yellow highlighted area shown in the snapshot.


Descriptions and associated Categories for various findings that FindBugsTM identifies are listed in FindBugs Bug Descriptions. Also note that the "Speed" of the various detectors is listed.

Clicking on "Checkstyle" under "Quality" in the NetBeans Project Properties window leads to the screen shown in the next snapshot.


Whether using Checkstyle from the command line or from Ant, a configuration file and a properties file can be provided to customize the applied Checkstyle modules. Given this, it's not surprising that the NetBeans SQE-provided Checkstyle plugin accepts specification of a "Config File" and a "Properties File."


Conclusion

Although some coding practices are almost universally accepted as "good" or "bad," there are some findings identified by code analysis tools that may be unimportant or even disagreeable to a software development organization. Therefore, it is advantageous that these tools allow the findings that are searched for and reported to be customized. Fortunately, the NetBeans SQE plugin passes along this configuration ability to the NetBeans user. The most significant configurations that can be performed with these tools in a command line or Ant environment can be performed similarly in NetBeans 7 thanks to SQE.

More JavaOne 2011 News

A little over three weeks ago, I summarized some JavaOne 2011 news. There have been several new pieces of news related to JavaOne 2011 that I summarize here.


Discover Pass and Discover Plus Pass

The blog post JavaOne Discover Plus and Discover Pass: Move Forward on a Tight Schedule on the JavaOne blog provides details for those who "have more curiosity and ambition than time." The post advertises the $895US Discover Plus Pass and the $75US Discover Pass. Both types of passes (the $75 Discover Pass and the $895 Discover Plus Pass) provide many common benefits outlined in this blog post and including access to "all the JaveOne and Oracle OpenWorld keynotes," access to The Zone at JavaOne, OTN Lounge access, access to the Executive Solution Sessions, access to 20-minute presentations at Scene and Be Heard Theater with Oracle partners, access to the Avaya-sponsored The Game Zone, access to the Fujitsu-sponsored Golf Experience, and the final-day It's a Wrap Event. The Discover Plus Pass adds some benefits to this list including access to three technical solutions (but not any hands-on labs) and access to the Appreciation Event with Tom Petty and the Heartbreakers and Sting.


JavaOne 2011: It's About OpenJDK

In the burek for breakfast blog post JavaOne 2011: OpenJDK Edition, robilad (Dalibor Topic) lists the nine sessions in the JavaOne 2011 Content Catalog "with OpenJDK in their title or abstract." He notes a Moore's Law like trend in number of OpenJDK-related sessions at JavaOne each year.

It's not too surprising that those responsible for selecting presentations at JavaOne look favorably on OpenJDK topics. OpenJDK is something nearly all Java developers can get behind, is an open source giant in the Java world, and has support from Oracle, IBM, and Apple, among others. It also helps fuel OpenJDK enthusiasm when it is used as the vehicle to demonstrate and discuss new JDK 7 features such as Project Coin.


JavaOne 2011: It's About Java EE

Arun Gupta's blog post Java EE and GlassFish sessions at JavaOne 2011 provides "a complete list of Java EE and GlassFish Technical Sessions, Birds-of-Feather, Hands-on Lab, and Community Events at JavaOne 2011." Gupta links to a Wiki page that breaks these down into two groups: those given "by Oracle" presenters and those presented by "the Community." Gupta reproduces the list in his post and adds some pointers to other JavaOne 2011 events as well.


Discounts / Travel in San Francisco

San Francisco Travel has a page devoted to JavaOne 2011 and its participants. JavaOne participants can get discounts at certain local establishments. See Paul Leahy's post Discounts for JavaOne 2011 Attendees for more details.


Conclusion

JavaOne 2011 is five weeks away. It is exciting to think about attending the numerous technical sessions, keynotes, Birds of a Feather sessions, and other activities.

Saturday, August 27, 2011

NetBeans 7 and Software Quality Environment

It is easy to configure NetBeans 7 to use Software Quality Environment (SQE) to integrate popular software quality tools (FindBugs, PMD, CheckStyle, and Dependency Finder) with the NetBeans 7 development environment. The steps to do this are the subject of this post.

The main Software Quality Environment page provides the URI of the NetBeans Update Center (http://deadlock.netbeans.org/hudson/job/sqe/lastStableBuild/artifact/build/full-sqe-updatecenter/updates.xml) to use to access SQE as a NetBeans plugin. This is the same process explained in detail in the blog post XML Schema Editor in NetBeans IDE 7.0.1 and which I used in the related post NetBeans (7.0.1) Has An XML Schema Editor! I will be demonstrating this process using NetBeans 7.0.1.

In NetBeans 7, the Plugins Manager is easily accessed by selecting Tools and then Plugins as depicted in the next screen snapshot.


The next screen snapshot depicts selecting the "Settings" tab of the Plugins popup. The image also depicts the results of clicking on the "Add" button in this "Plugins" window, which is the new popup window with title "Update Center Customizer." The image shows the URL provided by the SQE page and cited above pasted into the "URL:" field. I provided a name for it as well ("NetBeans SQE"). As a side note, the customizer that I added for XML Tools (XSD editor) is shown to still be registered (but now I have it renamed to "NetBeans XML Tools").


With the SQE Update Center added, the next step is to select the "Available Plugins" tab on the same "Plugins" window. The next image shows the results of doing that and clicking on the "Category" filter to get the plugins ordered by alphabetical ordering of categories. The four plugins related to SQE are have a category of "Quality" and these four are checked in the image because I am adding them to my NetBeans installation.


When I click on the "Install" button to install the four "Quality" plugins, the popup that comes up shows which version of each plugin is being installed. This is shown in the next screen snapshot.


After clicking on the "Next" button, applicable licenses must be read and agreed to and then the fact that the plugins are not signed must be acknowledged. A window like the one shown in the next screen snapshot indicates when the process has been successfully completed. The installation of these SQE plugins does not require restarting NetBeans.


It isn't difficult to start seeing the SQE-provided plugins working. For example, the next screen snapshot demonstrates several flagged issues resulting from simply creating a new Java Application Project with a "main" class created automatically as part of the project's creation.


That's a lot of warning yellow for a simple new class! These work similarly to the core NetBeans hints and warnings. The next three screen snapshots shows the details provided when I hover over the respective of the yellow-highlighted areas.




Some of the warnings are really useful. For example, it is desirable to always have a named package for a Java class and the PMD warning alerts me that I don't have one in this case (I forgot to specify the package when creating the class in the new Project wizard). I used NetBeans 7's refactor capability to "Move" this to a new package called "dustin.examples."

Most of us who have used code quality tools know that not all warnings are created equal. For example, I'm not too upset about the warning that my Java source code file doesn't end with a newline because, in fact, it really does.

The next screen snapshot shows the above warnings addressed and a simple "Hello World" application built from that starting point.


In this case, the FindBugs warning "Null pointer dereference of System.out" does not concern me, but it is nice to see PMD's warning "System.out print is used" because that may not be intentional. I am a big fan of statically importing java.lang.System.out when I intentionally am using that functionality with no plans to move to a logger or other output mechanism. The one drawback to doing this when it is only meant to be used temporarily is that then the PMD warning about use of System.out.println is not triggered.


The SQE plugin for NetBeans provides graphics of the source code defects detected as well as other forms of output summarizing the defects found. The next screen snapshot attempts to capture all of these in one image. Note that there is a new window on the left side that can be selected where "Projects", "Files", and "Services" traditionally reside. This one, called "Quality," is where one can click on the upper left icon to run all the quality tools to have the various graphics and output produced. The images to the right zoom in on the window and show "Projects" tab focus and "Quality" tab focus.





It is interesting to see how the SQE-provided plugins interact with each other when finding an issue on the same line of source code. Ignore the nonsense code in the next screen snapshot and instead look at the message when the cursor is pointed on one of the down-pointing black arrows. The black arrow indicates there are multiple annotations and clicking on it allows one to cycle through them. The icon shows which one is in focus with the FindBugs, Checkstyle, and PMD icons all shown in this screen snapshot.




One drawback of using the SQE code quality plugins the first time after installation may be loss of some reporting functionality of NetBeans hints, warnings, and errors. The example in the next screen snapshot demonstrates that although the Projects window "knows" that I have a compilation error (used integer rather than Integer), the source code editor itself does not. There are PMD warnings against using short variable names and for using explicit scoping, but there is no red squiggly line underneath the bad data type of "integer." Related to this, there's no red line on the long vertical margin along the right side of the IDE to indicate an error either.


I similarly don't see core NetBeans warnings and hints, though I'm less worried about loss of these because many are covered by the warnings provided by the quality tools. The good news is that exiting NetBeans and bringing NetBeans up again happened to return my NetBeans core error and warning messages alongside the quality analysis products' warnings. It is probable that it is due to NetBeans truly needing to be restarted after installation of a new version of SQE.

The last portion of this post briefly looks at using Dependency Finder in NetBeans via the SQE plugins. This can be done by selecting the NetBeans Project of interest in the left ("JaxbDemo" in my case) and then clicking on the appropriate icon under "Controls." This is shown in the next screen snapshot.


At this point, the graphic is pretty uninteresting, showing only the packages in the current project, which in this case is the single package "dustin.examples." It gets more interesting when the "JDK" link is clicked and the project's dependencies on the JDK are displayed.


It can be even more interesting to see all external dependencies (outside of the project and outside of the JDK) by clicking on "External" and showing those in addition to the JDK dependencies.


If a developer wants to see external dependencies without seeing JDK dependencies, the JDK button can be toggled so that only non-JDK external dependencies are shown.


A final nice feature of the Dependency Finder in NetBeans that I'll cover here is the ability to manually edit these dependency diagrams. I can drag any of the ovals wherever I please and the links stay attached. This is handy for making the graphic easier to read, smaller or larger is expanse, and grouping dependencies by preferred category or other grouping. The next screen snapshot demonstrates the results of this so that the diagram takes less space and has JDK dependencies grouped together and non-JDK external dependencies grouped together.




Conclusion

The large Java ecosystem includes many powerful tools. Although these tools can be run independently and as parts of continuous integration efforts, it is very convenient to have these issues flagged while working in the code because many of them can be easily and quickly remedied at first sighting. The best way to fix bugs is to never introduce them and these kinds of tools integrated with the IDE make it possible to do just this in more cases than we normally might. The integration of NetBeans with Software Quality Environment provides this benefit.

Additional References

Other potentially useful references related to use of NetBeans with Software Quality Environment include Findbugs, PMD, Checkstyle & Dependency Finder in Netbeans, How to integrate and use Software Quality Environment (SQE) plug-in for NetBeans IDE 6.0, and NetBeans SQE.

Adding Common Methods to JAXB-Generated Classes (Extension)

I introduced the issue of JAXB-generated classes not having explicitly overridden equals(Object), hashCode(), or toString() methods in the blog post Adding Common Methods to JAXB-Generated Java Classes (JAXB2 Basics Plugins). In that post, I solved that problem using JAXB2 Basic Plugins to instruct the JAXB 2 RI xjc binding compiler to create these methods when creating Java classes based on a source XSD file. In two posts that followed, I showed how to solve this issue using a separate and distinct class (including with Groovy Categories) and how to solve this issue using Groovy's method interception. In this post, I look at yet another approach: extending the JAXB-generated classes and providing these common methods at that level.

The JAXB-generated MovieType class defined in my earlier post does not have the desired common methods. However, the next code listing shows how it can be extended to provide these methods in the child class on behalf of the parent class. This new class contains no attributes of its own but instead bases its common methods on the attributes inherited from its parent class.

MovieTypeExtended.java
package dustin.examples;

import java.util.Objects;

/**
 * This class extends {@link dustin.examples.MovieType} to add explicitly
 * overridden <code>toString()</code>, <code>equals(Object)</code>, and
 * <code>hashCode()</code> methods.
 */
public class MovieTypeExtended extends MovieType
{
   public MovieTypeExtended(final MovieType parentSource)
   {
      this.title = parentSource.title;
      this.year = parentSource.year;
      this.genre = parentSource.genre;
   }

   @Override
   public String toString()
   {
      return this.title + " [" + this.year + "/" + this.genre + "]";
   }

   @Override
   public boolean equals(final Object obj)
   {
      if (obj == null)
      {
         return false;
      }
      if (getClass() != obj.getClass())
      {
         return false;
      }
      final MovieTypeExtended other = (MovieTypeExtended) obj;
      return    Objects.equals(this.title, other.title)
             && Objects.equals(this.year, other.year)
             && Objects.equals(this.genre, other.genre);
   }

   @Override
   public int hashCode()
   {
      return Objects.hash(this.title, this.year, this.genre);
   }
}

The above class is fairly simple thanks to use of JDK 7's new Objects class. The client or test code that needs to use the common functionality of MovieType can get this behavior from this extended class. Example code is shown next.

Main3.java
package dustin.examples;

import java.io.File;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

import static java.lang.System.out;
import static java.lang.System.err;

/**
 * Main class for demonstrating use of common methods on JAXB objects via
 * extended classes that provide those common methods for the JAXB-generated
 * parents.
 */
public class Main3
{
   public Movies getContentsOfMoviesFile(final String xmlFileName)
   {
      Movies movies = null;
      try
      {
         final JAXBContext jc = JAXBContext.newInstance("dustin.examples");
         final Unmarshaller u = jc.createUnmarshaller();
         movies = (Movies) u.unmarshal(new File(xmlFileName));
      }
      catch (JAXBException jaxbEx)
      {
         err.println(jaxbEx.toString());
      }
      catch (ClassCastException castEx)
      {
         err.println("Unable to get Movies object out of file " + xmlFileName +
                 " - " + castEx.toString());
      }
      return movies;
   }
 

   /**
    * Simple example of using separate and distinct class to perform common
    * functionality on JAXB-generated classes that cannot provide these functions
    * for themselves.
    * 
    * @param arguments Command line arguments; none expected.
    */
   public static void main(String[] arguments)
   {
      final Main3 me = new Main3();
      final Movies movies1 = me.getContentsOfMoviesFile("movies1.xml");
      final Movies movies2 = me.getContentsOfMoviesFile("movies1.xml");
      for (final MovieType movieSrc : movies1.getMovie())
      {
         final MovieTypeExtended movie = new MovieTypeExtended(movieSrc);
         boolean matchFound = false;
         for (final MovieType otherMovieSrc : movies2.getMovie())
         {
            final MovieTypeExtended otherMovie = new MovieTypeExtended(otherMovieSrc);
            if (movie.equals(otherMovie))
            {
               matchFound = true;
               break;
            }
         }
         if (matchFound)
         {
            out.println("Match FOUND for " + movie);
         }
         else
         {
            out.println("NO match found for " + movie);
         }
      }
   }
}

The extended class does not have to be written in Java. The next example is an class that extends MovieType and is implemented in Groovy.

MovieTypeGroovyExtended.groovy
package dustin.examples

/**
 * Using @Canonical or @EqualsAndHashCode or @ToString does not work here because
 * attributes of interest are not actually declared at this class's level.
 */
class MovieTypeGroovyExtended extends MovieType
{
   public MovieTypeGroovyExtended(MovieType parentSource)
   {
      this.title = parentSource.title
      this.year = parentSource.year
      this.genre = parentSource.genre
   }

   @Override
   public boolean equals(Object object)
   {
      if (object == null)
      {
         return false
      }
      if (this.getClass() != object.getClass())
      {
         return false
      }
      def other = (MovieTypeGroovyExtended) object
      return Objects.equals(this.title, other.title) &&
             Objects.equals(this.year, other.year) &&
             Objects.equals(this.genre, other.genre)
   }

   @Override
   public String toString()
   {
      return "${this.title} [${this.year}/${this.genre}]"
   }
}

The above example is fairly similar to the Java version, but with a little more concise Groovy syntax. It would have been really slick to be able to use the Groovy 1.8 provided annotations @ToString, @EqualsAndHashCode, and @Canonical annotations I covered in my posts (here and here), but these won't work here because they work against the attributes of a particular class rather than the attributes of its parent class. They support calling their parent's version of the same methods, but that is not helpful when the parent class doesn't implement those methods.

This is the fourth approach I have shown for dealing with lack of common methods in JAXB-generated classes. This is also my least favorite approach of the four because it relies on implementation inheritance of a concrete class by an otherwise "empty" class solely providing "common" methods. It seems odd to implement an "empty" class to perform functions on its parent class. It is easier to accept it for tests and simple uses, but I prefer the three other approaches (build JAXB classes with common methods via JAXB2 Plugins, use separate class to perform functionality, and Groovy method interception) over this approach for general use. The other approaches all feel and look "closer" to the actual JAXB-generated classes than this one from client code/script perspective.

Friday, August 26, 2011

Adding Common Methods to JAXB-Generated Classes (Groovy invokeMethod)

In two previous posts [Adding Common Methods to JAXB-Generated Java Classes (JAXB2 Basics Plugins) and Adding Common Methods to JAXB-Generated Classes (Separate Class/Groovy Categories)], I looked at using JAXB2 Basic Plugins and a separate Class (including via Groovy Categories) respectively to deal with the issue of JAXB-generated classes without common methods toString(), equals(Object), and hashCode(). In this post, I look at a third approach to providing functionality of these common methods for JAXB-generated classes. The approach covered in this post is to use Groovy's dynamic method interception via invokeMethod.

Groovy's invokeMethod allows Groovy code to intercept a method call and either do something different than the intercepted method, do something before invoking the intended method, or do something after invoking the intended method. This, of course, sounds a lot like aspect-oriented programming (AOP). This approach works particularly well for adding functionality of toString(), equals(Object), and hashCode() to classes that don't already override these methods (such as the JAXB-generated classes). We can intercept calls to the versions of these methods provided by the super Object class and instead implement versions specific to the JAXB-generated classes.

The next Groovy code listing shows Groovy code that intercepts calls to common methods on the JAXB-generated MovieType class (see the previous post for this class's source code).

compareMovieTypes4.groovy
import dustin.examples.MovieGenre
import dustin.examples.MovieType
import dustin.examples.MovieTypeCommons
import dustin.examples.Movies
import javax.xml.bind.Unmarshaller
import javax.xml.bind.JAXBContext
import javax.xml.bind.JAXBException

MovieType.metaClass.invokeMethod =
{ String name, args ->
   if (name == 'equals')
   {
      return MovieTypeCommons.doEquals(delegate, args[0])
   }
   else if (name == 'hashCode')
   {
      return MovieTypeCommons.doHashCode(delegate)
   }
   else if (name == 'toString')
   {
      return MovieTypeCommons.doToString(delegate)
   }
   else
   {
      def methodHandle = MovieType.metaClass.getMetaMethod(name, args)
      if (methodHandle != null)
      {
         return methodHandle.invoke(delegate, args)
      }
   }
}

def movies1 = getContentsOfMoviesFile("movies1.xml")
def movies2 = getContentsOfMoviesFile("movies1.xml")
movies1.movie.each
{ movie ->
   boolean matchFound = false
   movies2.movie.each
   { otherMovie ->
      if (movie == otherMovie)
      {
         matchFound = true
      }
   }
   if (matchFound)
   {
      println "Match FOUND for ${movie.toString()}"
   }
   else
   {
      println "NO match found for ${movie.toString()}"
   }
} 

def Movies getContentsOfMoviesFile(String xmlFileName)
{
   def jc = JAXBContext.newInstance("dustin.examples")
   def u = jc.createUnmarshaller()
   def movies = (Movies) u.unmarshal(new File(xmlFileName))
   return movies;
}

The simple Groovy script shown above uses the syntax MovieType.metaClass.invokeMethod = { to declare a closure that intercepts all method calls on the MovieType class. In this simple script, any method with the name "toString", "equals", or "hashCode" is intercepted and each method with one of these names has its implementation replaced with a call to the MovieTypeCommons class introduced in this earlier post. Any intercepted method that does not have a name matching "toString", "equals", or "hashCode" is not treated and the code simply turns around and invokes that intended method without change. The gist of all this is that only methods with the three mentioned names are changed in implementation (in this case to override the nearly useless Object-provided implementation with something useful) and all other methods are left well enough alone.

The Groovy metaClass for MovieType is used to invoke invokeMethod to intercept method calls. This same metaClass is also used to get a handle on the method that was intercepted so that this handle's invoke method can be used to invoke the originally intended method in the manner that it was originally called.

After the closure for MovieType is defined, the script goes on to use the conveniences of this method interception to invoke equals (via Groovy's == operator) and toString() on the MovieType class. The good news here is that this script does determine that JAXB objects with the same content are equal and does provide a nice String representation of them thanks to the intercepted and alternatively handled methods.


There are different flavors of method interception in Groovy. The GroovyInterceptable interface is defined in its Javadoc documentation as a "marker interface used to notify that all methods should be intercepted through the invokeMethod mechanism of GroovyObject." Making a Groovy class implement this interface provides similar method interception as the approach I demonstrated earlier in this post using metaClass.invokeMethod.

If the code needing to use JAXB-generated classes is Groovy, this is an elegant way to "add" methods to those classes for common functionality such as equality checking, hash code generation, and String representation. Of course, this approach can be generalized to cover any such situations when existing classes (even Java classes like JAXB-generated MovieType) need to support methods they don't statically support.

Thursday, August 25, 2011

Adding Common Methods to JAXB-Generated Classes (Separate Class/Groovy Categories)

I have previously discussed using JAXB2 Basic Plugins to add common methods to JAXB-generated Java classes. In this blog post, I look at another approach for performing the same behaviors on JAXB-generated objects as these classes might normally provide for themselves. In this case, I look at writing a separate class to perform the same functionality that classes normally define for themselves in the common and overridden methods equals(Object), hashCode(), and toString().

The next code listing shows a JAXB-generated class (see my previous post for the XSD used to generate this class) that has been generated with the default settings of the JAXB 2 RI xjc binding compiler without use of JAXB2 Basic Plugins. In other words, there is no "common" method defined for this class such as toString(), hashCode(), or equals(Object).

If one does not have access to the source schema or for some reason cannot regenerate the JAXB classes using a framework like JAXB2 Basic Plugins to automatically add these common methods to the generated classes, another approach that can be used is to have a totally distinct class or piece of code perform the same functionality on these classes. The following is a simple Java class that performs equals, hashCode, and toString functionality for a JAXB-generated class that does not have its own overridden implementations of these.

MovieTypeCommons.java
package dustin.examples;

import java.util.Objects;

/**
 * <p>Class that compares a JAXB-generated MovieType class to add common methods
 * {@code toString()}, {@code equals(Object)}, and {@code hashCode()} that a
 * class normally overrides from {@link java.lang.Object}, but which are not
 * overridden in the JAXB-generated class.</p>
 * 
 * <p>This class requires Java 7 for compiling as it uses the new
 * {@link java.lang.Objects} class.</p>
 * 
 * <p>This class could be used as-is in Java or Groovy to provide surrogate
 * "common" methods for instances of {@link dustin.examples.MovieType} or
 * could be used as a Groovy Category.</p>
 */
public class MovieTypeCommons
{
   /**
    * Performs equality comparison on two provided instances of the
    * {@link dustin.examples.MovieType} class.
    * 
    * @param movie1 First instance to be compared.
    * @param movie2 Second instance to be compared.
    * @return {@code true} if the two provided instances are equal or
    *    {@code false} if the two instances are not equal or if either provided
    *    parameter is null.
    */
   public static boolean doEquals(final MovieType movie1, final MovieType movie2)
   {
      if (movie1 == null || movie2 == null)
      {
         return false;
      }
      if (movie1.equals(movie2))
      {
         return true;
      }
      if (   !Objects.equals(movie1.title, movie2.title)
          || !Objects.equals(movie1.year, movie2.year)
          || movie1.genre != movie2.genre)
      {
         return false;
      }
      return true;
   }


   /**
    * Provide hash code for provided instance of {@link dustin.examples.MovieType}.
    * 
    * @param movie Instance for which hash code is desired.
    * @return The hash code for the provided object; will be null if provided
    *    MovieType is null.
    */
   public static int doHashCode(final MovieType movie)
   {
      return  movie != null
            ? Objects.hash(movie.title, movie.year, movie.genre)
            : null;
   }


   /**
    * Provide String representation for provided instance of
    * {@link dustin.examples.MovieType}.
    * 
    * @param movie Movie Instance for which String representation is desired.
    * @return String representation of provided instance; will be "null" if
    *    provided MovieType is null.
    */
   public static String doToString(final MovieType movie)
   {
      return  movie != null
            ? movie.title + " [" + movie.genre + "/" + movie.year + "]"
            : "null";
   }
}

The above code accepts instances of the JAXB-generated class MovieType and performs the common functionality on them. It is worth a quick diversion here to point out that handiness of Java 7's sparkling new Objects class in implementing these methods in a null-safe fashion.

The next code listing shows how a simple Java client can use this commons-providing class to handle the JAXB-generated MovieType class.

Main2.java
package dustin.examples;

import java.io.File;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

import static java.lang.System.out;
import static java.lang.System.err;

/**
 * Main class for demonstrating use of common methods on JAXB objects via a
 * separate and distinct class.
 */
public class Main2
{
   public Movies getContentsOfMoviesFile(final String xmlFileName)
   {
      Movies movies = null;
      try
      {
         final JAXBContext jc = JAXBContext.newInstance("dustin.examples");
         final Unmarshaller u = jc.createUnmarshaller();
         movies = (Movies) u.unmarshal(new File(xmlFileName));
      }
      catch (JAXBException jaxbEx)
      {
         err.println(jaxbEx.toString());
      }
      catch (ClassCastException castEx)
      {
         err.println("Unable to get Movies object out of file " + xmlFileName +
                 " - " + castEx.toString());
      }
      return movies;
   }
 

   /**
    * Simple example of using separate and distinct class to perform common
    * functionality on JAXB-generated classes that cannot provide these functions
    * for themselves.
    * 
    * @param arguments Command line arguments; none expected.
    */
   public static void main(String[] arguments)
   {
      final Main2 me = new Main2();
      final Movies movies1 = me.getContentsOfMoviesFile("movies1.xml");
      final Movies movies2 = me.getContentsOfMoviesFile("movies1.xml");
      for (final MovieType movie : movies1.getMovie())
      {
         boolean matchFound = false;
         for (final MovieType otherMovie : movies2.getMovie())
         {
            if (MovieTypeCommons.doEquals(movie, otherMovie))
            {
               matchFound = true;
               break;
            }
         }
         if (matchFound)
         {
            out.println("Match FOUND for " + MovieTypeCommons.doToString(movie));
         }
         else
         {
            out.println("NO match found for " + MovieTypeCommons.doToString(movie));
         }
      }
   }
}

When the above class's main method is executed, we see both MovieTypeCommons.doEquals(MovieType,MovieType) and MovieTypeCommons.doToString(MovieType) in action and working.


As the example above indicates, using a separate and distinct class to perform common functionality is a viable solution for working with JAXB-generated classes that don't define these themselves. However, there are some disadvantages. First, the code must be generated separately and cannot be done in a simple step as was done with JAXB2 Basic Plugins. Every time something changes, the multiple steps are required. The second problem is related in that most changes to the JAXB-generated classes require corresponding changes to the separate class that works on their instances. Even with these disadvantages in mind, it still may be a practical solution in some cases.

We can use the class defined above (MovieTypeCommons) even easier in Groovy. In fact, in Groovy, its use can be made to look very similar to what the calling code would look like if we were operating on the JAXB-generated classes directly. This can be implemented using Groovy's Objective-C-inspired Category support. As the documentation states, a Groovy category satisfies the "many situations where you might find that it would be useful if a class not under your control had additional methods that you define."

Before demonstrating use of Groovy Categories, I first "port" the Main2 simple Jav client from above to a fairly close Groovy equivalent.

compareMovieTypes.groovy
import dustin.examples.MovieType
import dustin.examples.MovieTypeCommons
import dustin.examples.Movies
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

def movies1 = getContentsOfMoviesFile("movies1.xml")
def movies2 = getContentsOfMoviesFile("movies1.xml")
movies1.movie.each
{ movie ->
   boolean matchFound = false
   movies2.movie.each
   { otherMovie ->
      if (MovieTypeCommons.doEquals(movie, otherMovie))
      {
         matchFound = true
      }
   }
   if (matchFound)
   {
      println "Match FOUND for " + MovieTypeCommons.doToString(movie)
   }
   else
   {
      println "NO match found for " + MovieTypeCommons.doToString(movie)
   }
}
   

def Movies getContentsOfMoviesFile(String xmlFileName)
{
   def jc = JAXBContext.newInstance("dustin.examples")
   def u = jc.createUnmarshaller()
   def movies = (Movies) u.unmarshal(new File(xmlFileName))
   return movies
}

This first Groovy script does NOT use Categories and calls the separate and distinct class MovieTypeCommons just as its Java equivalent did with the static methods access. Categories make this code a little cleaner and make it look as if the methods were being called directly on the instances of MovieType rather than on the separate class. The next Groovy script shows Groovy code using Categories (note the use keyword) to make it appear as if the methods were being called on the MovieType instance rather than on the separate MovieTypeCommons static methods.

compareMovieTypes2.groovy
import dustin.examples.MovieType
import dustin.examples.MovieTypeCommons
import dustin.examples.Movies
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

use (MovieTypeCommons)
{
   def movies1 = getContentsOfMoviesFile("movies1.xml")
   def movies2 = getContentsOfMoviesFile("movies1.xml")
   movies1.movie.each
   { movie ->
      boolean matchFound = false
      movies2.movie.each
      { otherMovie ->
         if (movie.doEquals(otherMovie))
         {
            matchFound = true
         }
      }
      if (matchFound)
      {
         println "Match FOUND for " + movie.doToString()
      }
      else
      {
         println "NO match found for " + movie.doToString()
      }
   }
}  

def Movies getContentsOfMoviesFile(String xmlFileName)
{
   def jc = JAXBContext.newInstance("dustin.examples")
   def u = jc.createUnmarshaller()
   def movies = (Movies) u.unmarshal(new File(xmlFileName))
   return movies;
}

In the last Groovy code listing, the code appears to call doEquals(MovieType) and doToString(MovieType> on the MovieType instance itself! This looks more like what we'd normally see when a class implements its own "equals" and "toString" methods.


Conclusion

This post has shown how a separate and distinct Java class might be used to implement common functionality for JAXB classes that don't have these common methods themselves. Groovy Categories were demonstrated as an easy approach to making it appear as if Groovy scripts were calling the common functionality methods on the instances of the JAXB-generated classes themselves. Along the way, Java 7's Objects class was used to simplify implementation of the common functionality.

NetBeans (7.0.1) Has An XML Schema Editor!

Just after clicking on the "Publish Post" button to publish my latest blog post (Adding Common Methods to JAXB-Generated Java Classes (JAXB2 Basics Plugins)), I saw Geertjan Wielenga's post XML Schema Editor in NetBeans IDE 7.0.1. The irony is that I had thought about looking for a NetBeans XSD editor plugin when writing my post on generating Java classes with common methods from XSD files using JAXB and JAXB2 Basic Plugins. However, because my XSD for the example was trivially simple, I simply used NetBeans's general XML-completion capabilities to help me generate the XSD for my example. In this blog post, I look at using the XML Schema Editor plugin mentioned in Geertjan's post with the XSD from my previous post.


Although I've been using NetBeans 7.0 for months now, I ran the update tool on it to start with and am now using NetBeans 7.0.1. I then followed Geertjan's instructions and registered the update center with the URI he provides (http://deadlock.netbeans.org/hudson/job/xml/lastSuccessfulBuild/artifact/build/updates/updates.xml). This is shown in the next screen snapshot.


Once Geertjan's specified update center is registered (I registered it under the name "NetBeans Deadlock"), the "XML Tools" plugin is available in the "Available Plugins" tab as shown in the next screen snapshot.


When I click on the "Install" button in the lower left corner, the NetBeans IDE Installer comes up. What's interesting about the "License Agreement" is that it lists a whole set of useful XML-related functions apparently supported by the plugin, including "XML Schema Support." This is shown in the next screen snapshot.


With the XML Tools plugin installed, it's now time to see how it looks with the XSD file used in my previous post. With the plugin installed, clicking on the XSD file's name in the "Files" window opens up three possible views ("Source", "Schema" and "Design"). The "Design" view is shown in the next screen snapshot.


There is a palette available for graphically designing an XML Schema Definition. This is much nicer than hand-typing it like I did. You can drag an attribute or other element from the palette over onto the design and then type in the appropriate name.

The "Tree View" of the Schema tab of the XSD file is shown in the next screen snapshot.


I like the "Tree View" for quickly ascertaining the hierarchical nature of the XSD. In the same "Schema" tab, the "Columns" view is also available as indicated in the next screen snapshot.


The "Validate XML" feature is also useful in the "Schema" tab. The results of clicking on the icon with two arrows pointing down is shown next.


I don't show the "Source" tab here because it's the standard source code editor window one has for XSDs without the plugin.

I probably would have not found this plugin even if I had looked for it, because I needed the recommendation to register the particular update center called out in Geertjan's post.

It is nice to have an XML Schema Editor in NetBeans. I don't manipulate XSD files very often, but this will make it ever easier and quicker to create and maintain them in the future when I need XSD files. This plugin for handling XML Schema Definitions is a welcome addition to NetBeans's XML support. Thanks, Geertjan, for the tip!

Wednesday, August 24, 2011

Adding Common Methods to JAXB-Generated Java Classes (JAXB2 Basics Plugins)

I've used Java Architecture for XML Binding (JAXB) successfully for a wide set of problems and generally really like it. However, it is not without its downsides. One down side that occasionally manifests itself as an issue is the lack of toString(), equals(Object), and hashCode() method implementations in default JAXB-generated objects. In this post, I look at using JAXB2 Basic Plugins (referenced from JAXB Commons) to remedy that.

For this post, I use a very simple example XML Schema Definition that describes XML grammar for storing basic movie information. Although I could generate Java classes from DTD with JAXB, I'm going to use the more typical approach here of using an XSD as the source.

Movie.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

   <xs:element name="Movies">
      <xs:complexType>
         <xs:sequence maxOccurs="unbounded">
            <xs:element name="Movie" type="movieType"/>
         </xs:sequence>
      </xs:complexType>
   </xs:element>

   <xs:complexType name="movieType">
      <xs:attribute name="title" type="xs:string" />
      <xs:attribute name="year" type="xs:long"/>
      <xs:attribute name="genre" type="movieGenre"/>
   </xs:complexType>

   <xs:simpleType name="movieGenre">
      <xs:restriction base="xs:string">
         <xs:enumeration value="Action"/>
         <xs:enumeration value="Animated"/>
         <xs:enumeration value="Comedy"/>
         <xs:enumeration value="Documentary"/>
         <xs:enumeration value="Drama"/>
         <xs:enumeration value="Romance"/>
         <xs:enumeration value="Science Fiction"/>
      </xs:restriction>
   </xs:simpleType> 

</xs:schema>

It is easy to generate Java classes using the xjc binding compiler provided with the Oracle's JDK 7 implementation. This is shown in the next screen snapshot.


The command shown in the above screen snapshot (xjc -d src -p dustin.examples Movie.xsd ) places the generated classes in a destination directory specified by the -d option (src) and generates all classes in a package called dustin.examples (based on -p option).

The next screen snapshot shows that the appropriate classes have been generated (two Java classes representing the contents described by the XSD and an ObjectFactory). The Main.java class is not JAXB-generated and was there before running the xjc compiler.


The generated enum representing movie genre is shown next. It's not an issue that it lacks the common methods because, as an enum, these aren't really necessary to be explicitly coded.

MovieGenre.java
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2011.08.21 at 11:17:19 PM MDT 
//


package dustin.examples;

import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlEnumValue;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for movieGenre.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * <p>
 * <pre>
 * <simpleType name="movieGenre">
 *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
 *     <enumeration value="Action"/>
 *     <enumeration value="Animated"/>
 *     <enumeration value="Comedy"/>
 *     <enumeration value="Documentary"/>
 *     <enumeration value="Drama"/>
 *     <enumeration value="Romance"/>
 *     <enumeration value="Science Fiction"/>
 *   </restriction>
 * </simpleType>
 * </pre>
 * 
 */
@XmlType(name = "movieGenre")
@XmlEnum
public enum MovieGenre {

    @XmlEnumValue("Action")
    ACTION("Action"),
    @XmlEnumValue("Animated")
    ANIMATED("Animated"),
    @XmlEnumValue("Comedy")
    COMEDY("Comedy"),
    @XmlEnumValue("Documentary")
    DOCUMENTARY("Documentary"),
    @XmlEnumValue("Drama")
    DRAMA("Drama"),
    @XmlEnumValue("Romance")
    ROMANCE("Romance"),
    @XmlEnumValue("Science Fiction")
    SCIENCE_FICTION("Science Fiction");
    private final String value;

    MovieGenre(String v) {
        value = v;
    }

    public String value() {
        return value;
    }

    public static MovieGenre fromValue(String v) {
        for (MovieGenre c: MovieGenre.values()) {
            if (c.value.equals(v)) {
                return c;
            }
        }
        throw new IllegalArgumentException(v);
    }

}

The real issues of not having common methods can arise for the other JAXB-generated class, which is shown next in the Movies and MovieType classes..

Movies.java (default 'xjc' output)
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2011.08.24 at 09:06:04 PM MDT 
//


package dustin.examples;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * <complexType>
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence maxOccurs="unbounded">
 *         <element name="Movie" type="{}movieType"/>
 *       </sequence>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "movie"
})
@XmlRootElement(name = "Movies")
public class Movies {

    @XmlElement(name = "Movie", required = true)
    protected List<MovieType> movie;

    /**
     * Gets the value of the movie property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the movie property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getMovie().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link MovieType }
     * 
     * 
     */
    public List<MovieType> getMovie() {
        if (movie == null) {
            movie = new ArrayList<MovieType>();
        }
        return this.movie;
    }

}

MovieType.java (default 'xjc' output)
//
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2011.08.24 at 09:06:04 PM MDT 
//


package dustin.examples;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for movieType complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * <complexType name="movieType">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="year" type="{http://www.w3.org/2001/XMLSchema}long" />
 *       <attribute name="genre" type="{}movieGenre" />
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "movieType")
public class MovieType {

    @XmlAttribute(name = "title")
    protected String title;
    @XmlAttribute(name = "year")
    protected Long year;
    @XmlAttribute(name = "genre")
    protected MovieGenre genre;

    /**
     * Gets the value of the title property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getTitle() {
        return title;
    }

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

    /**
     * Gets the value of the year property.
     * 
     * @return
     *     possible object is
     *     {@link Long }
     *     
     */
    public Long getYear() {
        return year;
    }

    /**
     * Sets the value of the year property.
     * 
     * @param value
     *     allowed object is
     *     {@link Long }
     *     
     */
    public void setYear(Long value) {
        this.year = value;
    }

    /**
     * Gets the value of the genre property.
     * 
     * @return
     *     possible object is
     *     {@link MovieGenre }
     *     
     */
    public MovieGenre getGenre() {
        return genre;
    }

    /**
     * Sets the value of the genre property.
     * 
     * @param value
     *     allowed object is
     *     {@link MovieGenre }
     *     
     */
    public void setGenre(MovieGenre value) {
        this.genre = value;
    }

}

Unfortunately, this generated MovieType and Movies classes lack implementations of common methods toString(), equals(Object), and hashCode(). There may be situations in which these methods are desirable. There are several approaches that could be used to deal with this, but the approach that is the focus of the remainder of this post is to use the JAXB2 Basic Plug-ins to instruct the xjc binding compiler to create these methods.

The JAXB2 Basics ZIP file can be downloaded at http://confluence.highsource.org/display/J2B/Downloads. As of this writing clicking on the links to download Release 0.6.1 or Release 0.6.2 lead to 404 errors, but you can download Release 0.6.0 by clicking on its link. The downloaded file is relatively small. JAXB2 Basics is intended to be run with the JAXB 2 Reference Implementation's xjc binding compiler.

The next code listing is for a Java class that will compare JAXB-generated objects based on the same XML file. A natural expectation is that there would be matching objects for matching XML content.

Main.java
package dustin.examples;

import java.io.File;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

import static java.lang.System.out;
import static java.lang.System.err;

/**
 * Main class for demonstrating use of common methods on JAXB objects.
 */
public class Main
{
   public Movies getContentsOfMoviesFile(final String xmlFileName)
   {
      Movies movies = null;
      try
      {
         final JAXBContext jc = JAXBContext.newInstance("dustin.examples");
         final Unmarshaller u = jc.createUnmarshaller();
         movies = (Movies) u.unmarshal(new File(xmlFileName));
      }
      catch (JAXBException jaxbEx)
      {
         err.println(jaxbEx.toString());
      }
      catch (ClassCastException castEx)
      {
         err.println("Unable to get Movies object out of file " + xmlFileName +
                 " - " + castEx.toString());
      }
      return movies;
   }

   /**
    * Main function for testing out JAXB-generated objects equality
    * and toString() functionality.
    * 
    * @param arguments Command line arguments; none expected.
    */
   public static void main(String[] arguments)
   {
      final Main me = new Main();
      final Movies movies1 = me.getContentsOfMoviesFile("movies1.xml");
      final Movies movies2 = me.getContentsOfMoviesFile("movies1.xml");
      if (movies1.equals(movies2))
      {
         out.println("YES! Expected same XML to lead to matching objects.");
      }
      else
      {
         out.println("No.  Did not expect same XML file to lead to different instances.");
      }
      for (final MovieType movie : movies1.getMovie())
      {
         boolean matchFound = false;
         for (final MovieType otherMovie : movies2.getMovie())
         {
            if (movie.equals(otherMovie))
            {
               matchFound = true;
               break;
            }
         }
         if (matchFound)
         {
            out.println("Match FOUND for " + movie);
         }
         else
         {
            out.println("NO match found for " + movie);
         }
      }
   }
}

This simple code demonstrates the presence or lack of an overridden equals(Object) method and lack of an overridden toString() method. In this case, using the JAXB RI 2 xjc binding compiler, we see that the lack of these methods leads to surprising results as shown in the next screen snapshot.


The above output demonstrates that even when default xjc-generated JAXB objects are populated with the very same XML source file, they are not considered equal and don't override toString(). This is, of course, because they lack their own overridden versions of these most important methods.

There are numerous ways to handle this if it is necessary to print the contents of a JAXB object instantiated from a default generated class without the common methods. One approach would be to have a third-party class perform equality checks on the two provided objects and provide methods for building String representations of these objects. However, the approach that I focus on for the remainder of this post is that of using the JAXB2 Basic Plugins for equals, hashCode, and toString to have these common methods automatically generated and included in the JAXB/xjc-generated classes when they are constructed.

I think using Ant is the easiest way to run xjc with the JAXB2 Basic plugins. An Ant build file made especially for this purpose is shown next.

xjc-build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="RunningXjc" default="generate-sources" basedir=".">
   <description>Runs Xjc Binding Compiler</description>

   <target name="generate-sources">
      <taskdef name="xjc" classname="org.jvnet.jaxb2_commons.xjc.XJC2Task">
		   <classpath>
            <fileset dir="C:\Users\Dustin\Downloads\jaxb-ri-20110601\lib">
               <include name="activation.jar"/>
               <include name="jaxb-api.jar"/>
				   <include name="jaxb-impl.jar"/>
		 		   <include name="jsr173_1.0_api.jar"/>
               <include name="stax-api-*.jar"/>
               <include name="jaxb-xjc.jar"/>
			   </fileset>
            <fileset dir="C:\jaxb2-basics-dist-0.6.0\dist">
               <include name="jaxb2-basics-ant-*.jar"/>
            </fileset>
		   </classpath>
      </taskdef>

	<!-- Generate the Java code for XSD -->
	<xjc destdir="${basedir}/src" extension="true" package="dustin.examples">
		<arg line="-Xequals -XhashCode -XtoString"/>
		<schema dir="${basedir}">
		 	<include name="Movie.xsd"/>
		</schema>
		<!-- JAXB2 Plugins and Dependencies -->
		<classpath>
			<fileset dir="C:\jaxb2-basics-dist-0.6.0\dist">
				<include name="jaxb2-basics-0.6.0.jar"/>
            <include name="jaxb2-basics-ant-0.6.0.jar"/>
				<include name="jaxb2-basics-runtime-0.6.0.jar"/>
				<include name="jaxb2-basics-tools-0.6.0.jar"/>
            <include name="jaxb2-basics-testing-0.6.0.jar"/>
            <include name="jaxb2-basics-annotate-0.6.0.jar"/>
			</fileset>
         <fileset dir="C:\jaxb2-basics-dist-0.6.0\jaxb2-basics-dist-0.6.0\lib">
				<include name="commons-beanutils-1.7.0.jar"/>
				<include name="commons-lang-2.2.jar"/>
				<include name="commons-logging-1.1.1.jar"/>
            <include name="annox-0.5.0.jar"/>
         </fileset>
		</classpath>
	</xjc>
</target>
</project>

When the above Ant target is executed, the xjc binding compiler is again run (via the Ant xjc task), but this time uses the three specified plugins to generate the equals, hashCode, and toString methods. The output of this is shown in the next screen snapshot.


The files are all generated again, but they are larger this time because of the common methods and support methods added for those. These generated classes are shown in their directory in the next screen snapshot.


The enum MovieGenre is no different with the plugins, which is fine because enums have reasonable toString methods and their identity and equality comparisons are always the same given the same classloader. The two classes, however, are significantly different with toString(), equals(Object), and hashCode() methods and several supporting methods added to them. I list the generated source code for these two classes, Movies and MovieType, next.

Movies.java (xjc with JAXB2 Plugins for 'common' methods)
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2011.08.24 at 09:23:08 PM MDT 
//


package dustin.examples;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.jvnet.jaxb2_commons.lang.Equals;
import org.jvnet.jaxb2_commons.lang.EqualsStrategy;
import org.jvnet.jaxb2_commons.lang.HashCode;
import org.jvnet.jaxb2_commons.lang.HashCodeStrategy;
import org.jvnet.jaxb2_commons.lang.JAXBEqualsStrategy;
import org.jvnet.jaxb2_commons.lang.JAXBHashCodeStrategy;
import org.jvnet.jaxb2_commons.lang.JAXBToStringStrategy;
import org.jvnet.jaxb2_commons.lang.ToString;
import org.jvnet.jaxb2_commons.lang.ToStringStrategy;
import org.jvnet.jaxb2_commons.locator.ObjectLocator;
import org.jvnet.jaxb2_commons.locator.util.LocatorUtils;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * <complexType>
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence maxOccurs="unbounded">
 *         <element name="Movie" type="{}movieType"/>
 *       </sequence>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "movie"
})
@XmlRootElement(name = "Movies")
public class Movies
    implements Equals, HashCode, ToString
{

    @XmlElement(name = "Movie", required = true)
    protected List<MovieType> movie;

    /**
     * Gets the value of the movie property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the movie property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getMovie().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link MovieType }
     * 
     * 
     */
    public List<MovieType> getMovie() {
        if (movie == null) {
            movie = new ArrayList<MovieType>();
        }
        return this.movie;
    }

    public boolean equals(ObjectLocator thisLocator, ObjectLocator thatLocator, Object object, EqualsStrategy strategy) {
        if (!(object instanceof Movies)) {
            return false;
        }
        if (this == object) {
            return true;
        }
        final Movies that = ((Movies) object);
        {
            List<MovieType> lhsMovie;
            lhsMovie = this.getMovie();
            List<MovieType> rhsMovie;
            rhsMovie = that.getMovie();
            if (!strategy.equals(LocatorUtils.property(thisLocator, "movie", lhsMovie), LocatorUtils.property(thatLocator, "movie", rhsMovie), lhsMovie, rhsMovie)) {
                return false;
            }
        }
        return true;
    }

    public boolean equals(Object object) {
        final EqualsStrategy strategy = JAXBEqualsStrategy.INSTANCE;
        return equals(null, null, object, strategy);
    }

    public int hashCode(ObjectLocator locator, HashCodeStrategy strategy) {
        int currentHashCode = 1;
        {
            List<MovieType> theMovie;
            theMovie = this.getMovie();
            currentHashCode = strategy.hashCode(LocatorUtils.property(locator, "movie", theMovie), currentHashCode, theMovie);
        }
        return currentHashCode;
    }

    public int hashCode() {
        final HashCodeStrategy strategy = JAXBHashCodeStrategy.INSTANCE;
        return this.hashCode(null, strategy);
    }

    public String toString() {
        final ToStringStrategy strategy = JAXBToStringStrategy.INSTANCE;
        final StringBuilder buffer = new StringBuilder();
        append(null, buffer, strategy);
        return buffer.toString();
    }

    public StringBuilder append(ObjectLocator locator, StringBuilder buffer, ToStringStrategy strategy) {
        strategy.appendStart(locator, this, buffer);
        appendFields(locator, buffer, strategy);
        strategy.appendEnd(locator, this, buffer);
        return buffer;
    }

    public StringBuilder appendFields(ObjectLocator locator, StringBuilder buffer, ToStringStrategy strategy) {
        {
            List<MovieType> theMovie;
            theMovie = this.getMovie();
            strategy.appendField(locator, this, "movie", buffer, theMovie);
        }
        return buffer;
    }

}

MovieType.java (xjc with JAXB2 Plugins for 'common' methods)
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2011.08.24 at 09:23:08 PM MDT 
//


package dustin.examples;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
import org.jvnet.jaxb2_commons.lang.Equals;
import org.jvnet.jaxb2_commons.lang.EqualsStrategy;
import org.jvnet.jaxb2_commons.lang.HashCode;
import org.jvnet.jaxb2_commons.lang.HashCodeStrategy;
import org.jvnet.jaxb2_commons.lang.JAXBEqualsStrategy;
import org.jvnet.jaxb2_commons.lang.JAXBHashCodeStrategy;
import org.jvnet.jaxb2_commons.lang.JAXBToStringStrategy;
import org.jvnet.jaxb2_commons.lang.ToString;
import org.jvnet.jaxb2_commons.lang.ToStringStrategy;
import org.jvnet.jaxb2_commons.locator.ObjectLocator;
import org.jvnet.jaxb2_commons.locator.util.LocatorUtils;


/**
 * <p>Java class for movieType complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * <complexType name="movieType">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <attribute name="title" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="year" type="{http://www.w3.org/2001/XMLSchema}long" />
 *       <attribute name="genre" type="{}movieGenre" />
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "movieType")
public class MovieType
    implements Equals, HashCode, ToString
{

    @XmlAttribute(name = "title")
    protected String title;
    @XmlAttribute(name = "year")
    protected Long year;
    @XmlAttribute(name = "genre")
    protected MovieGenre genre;

    /**
     * Gets the value of the title property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getTitle() {
        return title;
    }

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

    /**
     * Gets the value of the year property.
     * 
     * @return
     *     possible object is
     *     {@link Long }
     *     
     */
    public Long getYear() {
        return year;
    }

    /**
     * Sets the value of the year property.
     * 
     * @param value
     *     allowed object is
     *     {@link Long }
     *     
     */
    public void setYear(Long value) {
        this.year = value;
    }

    /**
     * Gets the value of the genre property.
     * 
     * @return
     *     possible object is
     *     {@link MovieGenre }
     *     
     */
    public MovieGenre getGenre() {
        return genre;
    }

    /**
     * Sets the value of the genre property.
     * 
     * @param value
     *     allowed object is
     *     {@link MovieGenre }
     *     
     */
    public void setGenre(MovieGenre value) {
        this.genre = value;
    }

    public boolean equals(ObjectLocator thisLocator, ObjectLocator thatLocator, Object object, EqualsStrategy strategy) {
        if (!(object instanceof MovieType)) {
            return false;
        }
        if (this == object) {
            return true;
        }
        final MovieType that = ((MovieType) object);
        {
            String lhsTitle;
            lhsTitle = this.getTitle();
            String rhsTitle;
            rhsTitle = that.getTitle();
            if (!strategy.equals(LocatorUtils.property(thisLocator, "title", lhsTitle), LocatorUtils.property(thatLocator, "title", rhsTitle), lhsTitle, rhsTitle)) {
                return false;
            }
        }
        {
            Long lhsYear;
            lhsYear = this.getYear();
            Long rhsYear;
            rhsYear = that.getYear();
            if (!strategy.equals(LocatorUtils.property(thisLocator, "year", lhsYear), LocatorUtils.property(thatLocator, "year", rhsYear), lhsYear, rhsYear)) {
                return false;
            }
        }
        {
            MovieGenre lhsGenre;
            lhsGenre = this.getGenre();
            MovieGenre rhsGenre;
            rhsGenre = that.getGenre();
            if (!strategy.equals(LocatorUtils.property(thisLocator, "genre", lhsGenre), LocatorUtils.property(thatLocator, "genre", rhsGenre), lhsGenre, rhsGenre)) {
                return false;
            }
        }
        return true;
    }

    public boolean equals(Object object) {
        final EqualsStrategy strategy = JAXBEqualsStrategy.INSTANCE;
        return equals(null, null, object, strategy);
    }

    public int hashCode(ObjectLocator locator, HashCodeStrategy strategy) {
        int currentHashCode = 1;
        {
            String theTitle;
            theTitle = this.getTitle();
            currentHashCode = strategy.hashCode(LocatorUtils.property(locator, "title", theTitle), currentHashCode, theTitle);
        }
        {
            Long theYear;
            theYear = this.getYear();
            currentHashCode = strategy.hashCode(LocatorUtils.property(locator, "year", theYear), currentHashCode, theYear);
        }
        {
            MovieGenre theGenre;
            theGenre = this.getGenre();
            currentHashCode = strategy.hashCode(LocatorUtils.property(locator, "genre", theGenre), currentHashCode, theGenre);
        }
        return currentHashCode;
    }

    public int hashCode() {
        final HashCodeStrategy strategy = JAXBHashCodeStrategy.INSTANCE;
        return this.hashCode(null, strategy);
    }

    public String toString() {
        final ToStringStrategy strategy = JAXBToStringStrategy.INSTANCE;
        final StringBuilder buffer = new StringBuilder();
        append(null, buffer, strategy);
        return buffer.toString();
    }

    public StringBuilder append(ObjectLocator locator, StringBuilder buffer, ToStringStrategy strategy) {
        strategy.appendStart(locator, this, buffer);
        appendFields(locator, buffer, strategy);
        strategy.appendEnd(locator, this, buffer);
        return buffer;
    }

    public StringBuilder appendFields(ObjectLocator locator, StringBuilder buffer, ToStringStrategy strategy) {
        {
            String theTitle;
            theTitle = this.getTitle();
            strategy.appendField(locator, this, "title", buffer, theTitle);
        }
        {
            Long theYear;
            theYear = this.getYear();
            strategy.appendField(locator, this, "year", buffer, theYear);
        }
        {
            MovieGenre theGenre;
            theGenre = this.getGenre();
            strategy.appendField(locator, this, "genre", buffer, theGenre);
        }
        return buffer;
    }

}

When the simple test is executed against these new generated Java classes, the results are more satisfying.


Using the JAXB2 plugins did what we needed and the JAXB-generated objects with same content are now properly considered equal and there is a better-than-nothing (which is what we had before) String representation of the objects' contents. There is some "cost" to this, however. As the generated code above shows, the JAXB-generated classes must implement specific interfaces and implement significant support methods above and beyond the common methods themselves.

This post has only shown three of the JAXB2 Plugins that are available (some of the others require an extra step of specifying binding customization within the source XSD or within a binding file). Several more are available, but it is especially common to want implementations of toString and equals and hashCode and this post has shown how to get those with JAXB-generated classes using JAXB2 Plugins.