The Wall Street Journal story today about IBM possibly acquiring Sun Microsystems ("IBM in Talks to Buy Sun in Bid to Add to Web Heft") is, at the highest level, nothing too new. It has been rumored for years that Sun would be a likely takeover target and Java developers have naturally wondered what would happen to Java and Java-related products if that was to happen. What today's story did do, however, is provide details that seem to take this past a rumor to a real story. The article points out that any such transaction might not complete and there are hurdles such as regulatory approval, shareholder approval, etc.
Most people seem to believe that software, including Java, will have little to no motivating influence on this alleged transaction. The article IBM/Sun deal won't be about the software, experts say does discuss what role Java might play or not play in the transaction. However, for those of us active in the Java development community, the effect of any acquisition on the Java programming language and platform (rather than the motivating power of acquiring Java) is of interest.
The Java ecosystem is large enough that it would likely continue to exist for years to come even if Sun Microsystems is acquired. However, there is no question that Sun exerts considerable leverage on the direction of the Java language and the Java platform and this direction would certainly be impacted by someone else acquiring Java along with the rest of Sun. IBM has contributed heavily to Javadom in the past with open source contributions like Eclipse, with commercial offerings such as the WebSphere application server, heavy participation in the Java Community Process (JCP), and with significant contributions to the literature with sites such as DeveloperWorks.
While an acquisition of Sun would most likely lead to subtler changes in the general Java programming language and platform direction, the effect could be much more pronounced and obvious for specific parts of Java and for specific Java-related products. Three products that would be of particular interest to me in such a scenario are NetBeans, GlassFish, and JavaFX. I am also curious about what effect this would have on JavaOne and on Java SE 7.
There are several things I really like about the NetBeans IDE, including its JavaScript and Ruby support, its integration with GlassFish, and its Swing GUI Builder. I also appreciate having another open source and freely available choice for a Java IDE. Given IBM's significant role in bringing about the Eclipse IDE and the sometimes bitter history between Eclipse and NetBeans, one has to wonder what the short-term and long-term fate of NetBeans would be if IBM acquired Sun. While NetBeans is an open source project, it it still heavily influenced and developer by Sun employees. This means that while the NetBeans project might live on, it would be much more difficult for it to continue to thrive and improve as quickly as it has in recent years without the same financial support.
I like to use the GlassFish application server because it provides such early peeks into the Java Enterprise Edition latest features and because it has been relatively straightforward to install and use. With IBM already owning its own commercial application server in WebSphere, there is some question about the level of interest in continuing investment in an open source alternative to their own product. As with NetBeans, the project could be forked, but the same risks of loss of momentum, slowing of support, and slowing of release of new features exists.
Sun has obviously invested significant time, energy, and resources into JavaFX. The topic has dominated the last two JavaOne conferences and is well represented in the catalog for the 2009 JavaOne Conference. The question is if a company acquiring Sun would have the same level of interest in JavaFX or have greater or less interest in JavaFX.
Speaking of JavaOne, an acquisition of Sun would almost certainly have an impact on this annual conference. The 2009 edition would likely change mostly in terms of discussions and unofficial functions, but future versions of the conference would likely see some dramatic shifts in focus. For example, if IBM purchased Sun, IBM presence at JavaOne would obviously be bigger than it was even in the early years of JavaOne.
Finally, with it sounding like we'll see Java SE 7 in 2010, I cannot help but wonder what effect, if any, a purchase of Sun in 2009 would have on that release. My guess is that it would only have a relatively minor effect on Java SE 7, but could potentially have a much larger effect on future versions of Java. It seems like an acquisition of Sun by IBM would almost certainly impact the Java Community Process in general.
Other Articles on the Possibility of IBM Purchasing Sun Microsystems
Java Crowd Has Mixed Views on Potential Sun-IBM Deal
IBM in Talks to Buy Sun?
Analysis of Potential Acquisition of Sun by IBM
Sun-IBM Merger: Is This Really Happening?
IBM Buying Sun Microsystems Makes No Sense: It's a Red Herring
Dustin's Software Development Cogitations and Speculations My observations and thoughts concerning software development (general development, Java, JavaFX, Groovy, Flex, ...). Select posts from this blog are syndicated on DZone and Java Code Geeks and were formerly syndicated on JavaWorld.
Wednesday, March 18, 2009
Monday, March 16, 2009
The Java Collections Class
One of my favorite standard Java classes is the Collections class. This is not surprising considering how often I find myself using the Java Collections Framework. Each Java Collection interface and implementation is useful in its own right, but the Collections class provides some convenience methods that are highly useful in working with Java collections.
The Javadoc API documentation for java.util.Collections explains the basics of this class such as the fact that all of its methods are static and that they all either operate on a provided collection or return a collection (here I am using "collection" more broadly to include Map as opposed to narrowly focusing on collections implementing the Collection interface). There are so many highly useful methods in this class that I am going to only focus on a subset of them to keep what is already a lengthy blog posting from becoming too large.
Empty Collections
Several of the methods provided by
The following sample code shows how one of these "empty" methods can be used and the image below the code demonstrates the UnsupportedOperationException that is thrown when the code execution tries to add an element to this empty collection that is immutable. For this particular example, I am using
demonstrateEmptySet()
Results of Running demonstrateEmptySet()

Single-Element Collections
Another functionality provided by
demonstrateSingletonList()
Results of Running demonstrateSingletonList()

I have found these various "singleton" methods to be useful for passing a single value to an API that requires a collection of that value. Of course, this works best when the code processing the passed-in value does not need to add to the collection.
Unmodifiable Collections
The methods already covered for returning empty collections and single-element collections provided these collections as unmodifiable collections. For situations in which an unmodifiable collection is desired with more than one element, appropriate methods are Collections.unmodifiableList(List), Collections.unmodifiableMap(Map), Collections.unmodifiableSet(Set), and the most general Collections.unmodifiableCollection(Collection). In addition to these, there are also methods for returning a Set or Map that is sorted in addition to being unmodifiable: Collections.unmodifiableSortedMap and Collections.unmodifiableSortedSet.
A source code example of using
demonstrateUnmodifiableMap()
Results of Running demonstrateUnmodifiableMap()

As a brief side note here, I intentionally added to this example the changing of values of the Map that underlies the unmodifiable Map to demonstrate that the source Collections upon which unmodifiable versions are returned can still be changed as needed. It is only the returned collection that is unmodifiable in the sense that it cannot have elements added to it or elements removed from it.
Checked Collections
All of the methods on the Collections class examined in this posting so far have returned unmodifiable collections as either empty, single-element, or multi-element collections. However, the Collections class is capable of much more than simply provide unmodifiable wrappers on collections. The "checked" methods [Collections.checkedCollection(Collection, Class), Collections.checkedList(List, Class), Collections.checkedMap(Map, Class), and Collections.checkedSet(Set, Class)] are useful for dealing with mixes of collections that use generic types and collections handling based one raw collections.
Before the introduction of generics with J2SE 5, we were required to find out about type problems associated with collections as we pulled an item out of a collection and cast it to the expected type at runtime. The advent of J2SE 5 generics enabled us to generally move this type mismatch detection from runtime on extraction of the items from a collection to compile time on insertion into the collection. This is highly advantageous because we can find the problem where it really occurs originally (at insertion) and because we can find it sooner (at compile time rather than at runtime).
Unfortunately, there are ways in which this type checking can be circumvented. For example, if a module out of our control accesses our collection as a raw collection, that module will be able to insert non-compliant items in the collection. Of course, we could also do the same ourselves if we're not careful or have legacy code that did not get fully ported. The Javadoc documentation for the Collections.checkedCollection method explains that these "checked" methods are also useful for debugging problems associated with ClassCastExceptions and generically typed collections by wrapping a collection instantiation in one of these calls.
To illustrate the problem that can occur when generically typed collections and raw collections are mixed, the following code intentionally does that mixture and the resulting problems are documented in the screen snapshot with its output.
demonstrateProblemWithoutCheckedCollection()
Results of demonstrateProblemWithoutCheckedCollection

This problem may look easy to address, but it is much more challenging if the mixed use of raw collections with generically typed collections is separated by many lines of code, different methods, or even different classes. In fact, the error upon access of the non-compliant collection element could happen well after its insertion in terms of both time passed and number of lines of code executed.
The use of the "checked" collection method brings some of the advantages of generically typed collections back even when raw collections are mixed. The following code sample and the screen snapshot of the output it generates are shown next.
demonstrateProblemFixedWithCheckedCollection()
Results of demonstateProblemFixedWithCheckedCollection()

Although use of the "checked" method here still results in the error being detected at runtime, it provides the advantage of detecting the error where it originally occurs (insertion) rather than some unknown amount of time later.
Enumerations and Collections
The Enumeration has been available since JDK 1.0. Because the Enumeration interface is used with several key legacy APIs, it can be useful to be able to easily convert back and forth between an
The following source code example demonstrates the conversion of an Enumeration to a List and the screen snapshot after it demonstrates its output.
demonstrateEnumerationToList()
Results of demonstrateEnumerationToList()

The next code listing and its resulting screen snapshot demonstrate converting a Collection to an Enumeration.
demonstrateCollectionToEnumeration()
Results of demonstrateCollectionToEnumeration()

List Order Change-ups
The
The "shuffle" method is used to randomly reorder items in a List.
demonstrateShuffle()
Results of demonstrateShuffle()

The "reverse" method simply reverses the order of items in a List.
demonstrateReverseList()
Results of demonstrateReverseList()

The "rotate" method rotates elements in a List by the provided number of spots.
demonstrateRotate()
Results of demonstrateRotate()

So Many More
The
Conclusion
The Collections class is one of the most valuable classes in the Java SDK. This blog posting has attempted to demonstrate some of its highly useful methods, but there are many more in addition to those shown here. Use of the
The Javadoc API documentation for java.util.Collections explains the basics of this class such as the fact that all of its methods are static and that they all either operate on a provided collection or return a collection (here I am using "collection" more broadly to include Map as opposed to narrowly focusing on collections implementing the Collection interface). There are so many highly useful methods in this class that I am going to only focus on a subset of them to keep what is already a lengthy blog posting from becoming too large.
Empty Collections
Several of the methods provided by
java.util.Collections perform similar functionality on different types of collections. For example, the methods Collections.emptySet(), Collections.emptyMap(), and Collections.emptyList() perform the same functionality, but on Sets, Maps, and Lists respectively. In the case of these methods, they each return the appropriate collection type that is empty (no elements in it), typesafe, and immutable. In other words, the provided collection is empty and nothing can be added to it. As I have blogged about previously, this is useful for implementing the recommendation of Effective Java to return empty collections rather than null.The following sample code shows how one of these "empty" methods can be used and the image below the code demonstrates the UnsupportedOperationException that is thrown when the code execution tries to add an element to this empty collection that is immutable. For this particular example, I am using
Collections.emptySet(), but the principle is the same for the List and Map versions.demonstrateEmptySet()
/**
* Provide an empty set.
*/
public void demonstrateEmptySet()
{
log("===== DEMONSTRATING EMPTY SET =====", System.out);
final Set<String> emptySet = Collections.emptySet();
log("Size of returned emptySet(): " + emptySet.size(), System.out);
log("----- Adding String to Collections.emptySet() returned Set -----", System.out);
emptySet.add("A new String to add.");
}
Results of Running demonstrateEmptySet()

Single-Element Collections
Another functionality provided by
Collections for Set, List, and Map is providing of a single-element collection that, like its empty element sibling, is immutable and typesafe. To illustrate this, the next code sample and output screen snapshot will demonstrate use of Collections.singletonList(T), though the same principles apply to Collections.singletonMap(K,V) and Collections.singleton(T) (no "Set" in method name is not an accidental omission on my part though that method does apply to the Set).demonstrateSingletonList()
/**
* Provide a Set with a single element.
*/
public void demonstrateSingletonList()
{
log("===== DEMONSTRATING SINGLETON LIST ======", System.out);
final List<String> singleElementList =
Collections.singletonList("A single String to add.");
log( "Size of returned singletonList(): "
+ singleElementList.size()
+ NEW_LINE,
System.out);
log(
"----- Adding String to Collections.singletonList() returned List -----",
System.out);
singleElementList.add("Another String to add.");
}
Results of Running demonstrateSingletonList()

I have found these various "singleton" methods to be useful for passing a single value to an API that requires a collection of that value. Of course, this works best when the code processing the passed-in value does not need to add to the collection.
Unmodifiable Collections
The methods already covered for returning empty collections and single-element collections provided these collections as unmodifiable collections. For situations in which an unmodifiable collection is desired with more than one element, appropriate methods are Collections.unmodifiableList(List), Collections.unmodifiableMap(Map), Collections.unmodifiableSet(Set), and the most general Collections.unmodifiableCollection(Collection). In addition to these, there are also methods for returning a Set or Map that is sorted in addition to being unmodifiable: Collections.unmodifiableSortedMap and Collections.unmodifiableSortedSet.
A source code example of using
Collections.unmodifiableMap(Map) and the results of running that example are shown next.demonstrateUnmodifiableMap()
/**
* Demonstrate use of Collections.unmodifiableMap(). Also demonstrates
* how the underlying collection (or Map in this case) can be changed even
* when set to an unmodifiable version.
*/
public void demonstrateUnmodifiableMap()
{
log("===== DEMONSTRATING UNMODIFIABLE MAP =====", System.out);
final Map<MovieGenre, String> unmodifiableMap =
Collections.unmodifiableMap(this.favoriteGenreMovies);
log(
"Map BEFORE MODIFICATION: " + NEW_LINE + unmodifiableMap.toString(),
System.out);
log(
"----- Putting a new value in Map for existing key in underlying Map. -----",
System.out);
this.favoriteGenreMovies.put(MovieGenre.JAMES_BOND, "Thunderball");
log( "The Unmodifiable Map AFTER MODIFICATION: " + NEW_LINE
+ unmodifiableMap.toString(), System.out);
log(
"----- Putting a completely new key in the underlying map. -----",
System.out);
this.favoriteGenreMovies.put(MovieGenre.MYSTERY, "The Usual Suspects");
log( "The Unmodifiable Map AFTER MODIFICATION: " + NEW_LINE
+ unmodifiableMap.toString(), System.out);
log(
"----- Now try to 'put' to the unmodifiable wrapper collection -----",
System.out);
unmodifiableMap.put(MovieGenre.MYSTERY, "Rear Window");
}
Results of Running demonstrateUnmodifiableMap()

As a brief side note here, I intentionally added to this example the changing of values of the Map that underlies the unmodifiable Map to demonstrate that the source Collections upon which unmodifiable versions are returned can still be changed as needed. It is only the returned collection that is unmodifiable in the sense that it cannot have elements added to it or elements removed from it.
Checked Collections
All of the methods on the Collections class examined in this posting so far have returned unmodifiable collections as either empty, single-element, or multi-element collections. However, the Collections class is capable of much more than simply provide unmodifiable wrappers on collections. The "checked" methods [Collections.checkedCollection(Collection, Class), Collections.checkedList(List, Class), Collections.checkedMap(Map, Class), and Collections.checkedSet(Set, Class)] are useful for dealing with mixes of collections that use generic types and collections handling based one raw collections.
Before the introduction of generics with J2SE 5, we were required to find out about type problems associated with collections as we pulled an item out of a collection and cast it to the expected type at runtime. The advent of J2SE 5 generics enabled us to generally move this type mismatch detection from runtime on extraction of the items from a collection to compile time on insertion into the collection. This is highly advantageous because we can find the problem where it really occurs originally (at insertion) and because we can find it sooner (at compile time rather than at runtime).
Unfortunately, there are ways in which this type checking can be circumvented. For example, if a module out of our control accesses our collection as a raw collection, that module will be able to insert non-compliant items in the collection. Of course, we could also do the same ourselves if we're not careful or have legacy code that did not get fully ported. The Javadoc documentation for the Collections.checkedCollection method explains that these "checked" methods are also useful for debugging problems associated with ClassCastExceptions and generically typed collections by wrapping a collection instantiation in one of these calls.
To illustrate the problem that can occur when generically typed collections and raw collections are mixed, the following code intentionally does that mixture and the resulting problems are documented in the screen snapshot with its output.
demonstrateProblemWithoutCheckedCollection()
/**
* Demonstrate problems that can occur when Collections.checkedCollection is
* not used.
*/
private void demonstrateProblemWithoutCheckedCollection()
{
log("1. Demonstrate problem of no checked collection.", System.out);
final Integer arbitraryInteger = new Integer(4);
final List rawList = this.favoriteBooks;
rawList.add(arbitraryInteger);
final List<String> stringList = rawList;
for (final String element : stringList)
{
log(element.toUpperCase(), System.out);
}
}
Results of demonstrateProblemWithoutCheckedCollection

This problem may look easy to address, but it is much more challenging if the mixed use of raw collections with generically typed collections is separated by many lines of code, different methods, or even different classes. In fact, the error upon access of the non-compliant collection element could happen well after its insertion in terms of both time passed and number of lines of code executed.
The use of the "checked" collection method brings some of the advantages of generically typed collections back even when raw collections are mixed. The following code sample and the screen snapshot of the output it generates are shown next.
demonstrateProblemFixedWithCheckedCollection()
/**
* Demonstrate how Collections.checkedCollection helps the problem.
*/
private void demonstrateProblemFixedWithCheckedCollection()
{
log("2. Demonstrate problem fixed with checked collection", System.out);
final Integer arbitraryInteger = new Integer(4);
final List<String> checkedList = Collections.checkedList(this.favoriteBooks, String.class);
final List rawList = checkedList;
rawList.add(arbitraryInteger);
final List<String> stringList = rawList;
for (final String element : stringList)
{
log(element.toUpperCase(), System.out);
}
}
Results of demonstateProblemFixedWithCheckedCollection()

Although use of the "checked" method here still results in the error being detected at runtime, it provides the advantage of detecting the error where it originally occurs (insertion) rather than some unknown amount of time later.
Enumerations and Collections
The Enumeration has been available since JDK 1.0. Because the Enumeration interface is used with several key legacy APIs, it can be useful to be able to easily convert back and forth between an
Enumeration and a collection. Two methods that support this conversion are Collections.list(Enumeration) [converts the provided Enumeration into a List] and Collections.enumeration(Collection) [provides an enumeration over a Collection].The following source code example demonstrates the conversion of an Enumeration to a List and the screen snapshot after it demonstrates its output.
demonstrateEnumerationToList()
/**
* Demonstrate use of Collections.list(Enumeration).
*/
public void demonstrateEnumerationToList()
{
log("===== Demonstrate Collections.list(Enumeration) =====", System.out);
final Enumeration properties = System.getProperties().propertyNames();
final List propertiesList = Collections.list(properties);
log(propertiesList.toString(), System.out);
}
Results of demonstrateEnumerationToList()

The next code listing and its resulting screen snapshot demonstrate converting a Collection to an Enumeration.
demonstrateCollectionToEnumeration()
/**
* Demonstrate use of Collections.enumeration(Collection).
*/
public void demonstrateCollectionToEnumeration()
{
log("===== Demonstrate Collections.enumeration(Collection) =====", System.out);
final Enumeration books = Collections.enumeration(this.favoriteBooks);
while (books.hasMoreElements())
{
log(books.nextElement().toString(), System.out);
}
}
Results of demonstrateCollectionToEnumeration()

List Order Change-ups
The
Collections class supports randomly reordering a List [two versions of Collections.shuffle method], reversing the order of a List [Collections.reverse(List) method], and rotating entries in a list by a prescribed number of entries [Collections.rotate(List, int) method]. Code samples and the associated screen snapshots for each of these follows.The "shuffle" method is used to randomly reorder items in a List.
demonstrateShuffle()
/**
* Demonstrate Collections.shuffle(List).
*/
public void demonstrateShuffle()
{
log("===== Demonstrate Collections.shuffle(List) =====", System.out);
log("Books BEFORE shuffle: " + NEW_LINE + this.favoriteBooks, System.out);
Collections.shuffle(this.favoriteBooks);
log("Books AFTER shuffle: " + NEW_LINE + this.favoriteBooks, System.out);
}
Results of demonstrateShuffle()

The "reverse" method simply reverses the order of items in a List.
demonstrateReverseList()
/**
* Demonstrate use of Collections.reverse(List).
*/
public void demonstrateReverseList()
{
log("===== Demonstrate Collections.reverse(List) =====", System.out);
log("List BEFORE reverse:" + NEW_LINE + this.favoriteBooks, System.out);
Collections.reverse(this.favoriteBooks);
log("List AFTER reverse:" + NEW_LINE + this.favoriteBooks, System.out);
}
Results of demonstrateReverseList()

The "rotate" method rotates elements in a List by the provided number of spots.
demonstrateRotate()
/**
* Demonstrate Collections.rotate(List, int).
*/
public void demonstrateRotate()
{
log("===== Demonstrate Collections.rotate(List, int) =====", System.out);
log("Books BEFORE rotation: " + NEW_LINE + this.favoriteBooks, System.out);
Collections.rotate(this.favoriteBooks, 3);
log("Books AFTER rotation: " + NEW_LINE + this.favoriteBooks, System.out);
}
Results of demonstrateRotate()

So Many More
The
Collections class provides significantly more functionality than even that shown here. It includes methods that support collection wrappers that can be used in concurrent environments [such as Collections.synchronizedCollection(Collection)], support filling a List with a particular item (Collections.fill), support counting the number of times a particular object exists in a Collection (Collections.frequency), sorting, searching, swapping, and several more types of functionality.Conclusion
The Collections class is one of the most valuable classes in the Java SDK. This blog posting has attempted to demonstrate some of its highly useful methods, but there are many more in addition to those shown here. Use of the
Collections class not only makes working with Java collections easier, but it also provides support for best practices related to Java collection use.
Saturday, March 14, 2009
Running Individual JUnit Unit Tests from Command-line Using NetBeans build.xml File
The NetBeans IDE provides JUnit integration that can be very handy when writing and running JUnit-based unit tests. However, I like to be able to do anything I might do often outside of the IDE as well as from within the IDE. In particular, there are times when I want to do things from the command-line without the need to open up the IDE.
It can be very useful to execute a single JUnit-based unit test class rather than executing the entire unit test suite. This is easy to do in the IDE itself, but it is something I also want to do from the command-line. NetBeans supports executing a single unit test class from the command-line, but I have found that you need to be aware of a few tricks to do this. This blog posting covers the minor things one needs to know to run individual JUnit-based unit tests from the command-line using an Ant build.xml file generated by NetBeans 6.1 or NetBeans 6.5 for a standard Java Application project.
When using the NetBeans New Project wizard to create a Java Application project, one gets an Ant-compliant build.xml file as the main project build file, but most of the real work is delegated to the build-impl.xml file that is generated and placed in the nbproject subdirectory of the main project working directory.
Before demonstrating how to run an individual Test Class from the command-line line, I'll first look at how to do it through the IDE. For the IDE and command-line examples, I will be using two classes two be tested and two test classes that will test those classes. The directory structure for this project with the test classes and the classes to be tested is shown next in this screen snapshot of the NetBeans "Projects" window.

The image above shows that this NetBeans project (which was created previously as a Java Application project using the NetBeans New Project creation wizard) is called "IndividualTesting." More importantly, this image shows the two main source classes (Adder and Multiplier in the "Source Packages" area) and their respective test classes (AdderTest and MultiplierTest in the "Test Packages" area). The image also shows that Java SE 6 and JUnit 4.5 are being used.
The source code for the classes (source and test) displayed above is shown next.
Adder.java (Class to be tested)
Multiplier.java (Class to be tested)
AdderTest.java (Class to test Adder)
MultiplierTest.java (Class to test Multiplier)
With the source code written, the JUnit-based unit tests written, and the NetBeans Java Application project set up as shown above, it is almost trivial to run the unit tests. All one needs to do is use ALT+F6 or select Run->Test Project to run all the tests for that particular NetBeans project. The next two screen snapshots show how to run all of the tests and what the results look like.
Running All Project's Unit Tests

Results of All Project's Unit Tests Displayed in NetBeans

We can see that most of the tests passed, though the test that was intentionally rigged to fail (to serve our illustration needs) did lead to a report of a single test failure. We may have reason at this point to only run a single test. For example, we might want to fix a given test and only run it rather than run all the tests again. This would be an advantage in a more realistic situation where we have many more unit test classes than the two shown here and don't want to run all of them all of the time.
From NetBeans, we can run an individual test by right-clicking on that particular test result's output and selecting "Run Again." This is demonstrated for one of the successful tests and for the failed test in the next two screen snapshots.
Running Individual Test (Successful Test)

Running Individual Test (Failed Test)

When the two individual tests are re-run individually, their respective output is shown in the next two screen snapshots.
Results of Re-running Successful Individual Test

Results of Re-running Failed Individual Test

As has been demonstrated so far, it is really easy to run JUnit-based unit tests as a group or individually against the desired test method. As stated earlier, there are times when this behavior is desired from the command-line. Running the entire suite of tests is easy and is done by simply invoking the targets

When one wishes to run a unit test individually from the command-line, there are a few additional details to know. From looking at the

From the end of this output (that portion displayed in the above screen snapshot: "Must select some files in the IDE or set javac.includes"), it is clear that when this particular target is not executed within the NetBeans IDE, it requires a property
An easy method to provide the
Executing the above line sets the
With the

The same value can be specified for the
The following screen snapshot displays the end of the properly executed individual test run.

From this screen snapshot, we see the results only for the AdderTest class (test suite) we specified in the
As with all output of NetBeans-enabled JUnit test runs, significantly more output is available in the project's
The generated XML file holding the results of the JUnit-based unit tests consists of a structure that looks something like this (I added the XML comment explaining that there are typically far more properties specified in these files, but they were left out here for brevity and clarity):
As the XML sample above indicates, the full result information is available in this file. Because it is well-formed XML, there are many tools and approaches one could use to view this data. The XML data can be viewed directly in a text editor, viewed in an XML tool that will color code it and indent it appropriately, translated with XSLT to another format, processed with Java XML parsing approaches such as JAXB, or viewed/processed with many other approaches.
Because we are using Ant and JUnit, the easiest method for viewing the test results is to take advantage of the optional Ant junitreport task. This is easily added to the build.xml file as a new target ("create-unit-test-report") as shown next:
When this target is run, output similar to that shown in the next screen snapshot is seen.

In this case, the HTML generated via XSLT transformation of the unit test XML output is available under the project's newly created


The Properties link in the bottom right corner of the web page shown in the last image can be clicked on to see the lengthy list of properties used in the NetBeans project in a more user-friendly format.
Conclusion
NetBeans makes it easy to run all units tests in a project or specific JUnit-based unit test suites and tests individually. It is not much more difficult to run individual unit test suites using the command-line as long as the
It can be very useful to execute a single JUnit-based unit test class rather than executing the entire unit test suite. This is easy to do in the IDE itself, but it is something I also want to do from the command-line. NetBeans supports executing a single unit test class from the command-line, but I have found that you need to be aware of a few tricks to do this. This blog posting covers the minor things one needs to know to run individual JUnit-based unit tests from the command-line using an Ant build.xml file generated by NetBeans 6.1 or NetBeans 6.5 for a standard Java Application project.
When using the NetBeans New Project wizard to create a Java Application project, one gets an Ant-compliant build.xml file as the main project build file, but most of the real work is delegated to the build-impl.xml file that is generated and placed in the nbproject subdirectory of the main project working directory.
Before demonstrating how to run an individual Test Class from the command-line line, I'll first look at how to do it through the IDE. For the IDE and command-line examples, I will be using two classes two be tested and two test classes that will test those classes. The directory structure for this project with the test classes and the classes to be tested is shown next in this screen snapshot of the NetBeans "Projects" window.

The image above shows that this NetBeans project (which was created previously as a Java Application project using the NetBeans New Project creation wizard) is called "IndividualTesting." More importantly, this image shows the two main source classes (Adder and Multiplier in the "Source Packages" area) and their respective test classes (AdderTest and MultiplierTest in the "Test Packages" area). The image also shows that Java SE 6 and JUnit 4.5 are being used.
The source code for the classes (source and test) displayed above is shown next.
Adder.java (Class to be tested)
package dustin;
/**
* Simple class to be tested that by coincidence performs addition functionality.
*
* @author Dustin
*/
public class Adder
{
/** No-arguments constructor. */
public Adder() {}
/**
* Sum the provided integers.
*
* @param augend First integer to be added.
* @param addend Second integer to be added.
* @param addends Remaining integers, in any, to be added.
* @return Sum of provided integers.
*/
public int add(final int augend, final int addend, final int ... addends)
{
int sum = augend + addend;
for (final int individualAddend : addends)
{
sum += individualAddend;
}
return sum;
}
}
Multiplier.java (Class to be tested)
package dustin;
/**
* Simple class to be tested that by coincidence performs multiplication functionality.
*
* @author Dustin
*/
public class Multiplier
{
/**
* Multiply the provided factors.
*
* @param factor1 First factor to be multiplied.
* @param factor2 Second factor to be multiplied.
* @param factors Remaining factors to be multiplied.
* @return Product of factors multiplication.
*/
public int multiply(final int factor1, final int factor2, final int ... factors)
{
int product = factor1 * factor2;
for (final int individualFactor : factors)
{
product *= individualFactor;
}
return product;
}
}
AdderTest.java (Class to test Adder)
package dustin;
import org.junit.Assert;
import org.junit.Test;
/**
* Test for class dustin.Adder.
*
* @author Dustin
*/
public class AdderTest extends Adder
{
public AdderTest() {}
@Test
public void testAddWithTwoAddends()
{
final int expectedSum = 7;
final int resultSum = add(3,4);
Assert.assertEquals(
"Sum of two added integers does not match expected result.",
expectedSum, resultSum);
}
@Test
public void testAddWithThreeAddends()
{
final int expectedSum = 11;
final int resultSum = add(3,4,4);
Assert.assertEquals(
"Sum of three added integers does not match expected result.",
expectedSum, resultSum);
}
@Test
public void testAddWithFourAddends()
{
final int expectedSum = 14;
final int resultSum = add(3,4,4,3);
Assert.assertEquals(
"Sum of four added integers does not match expected result.",
expectedSum, resultSum);
}
@Test
public void testAddWithTwoNegativeNumbers()
{
final int expectedSum = -10;
final int resultSum = add(-6,-4);
Assert.assertEquals(
"Sum of two negative integers does not match expected result.",
expectedSum, resultSum);
}
@Test
public void testWithIntentionalError()
{
final int expectedSum = 27;
final int resultSum = add(9,3);
Assert.assertEquals(
"The two provided numbers do not add to what was expected.",
expectedSum, resultSum);
}
}
MultiplierTest.java (Class to test Multiplier)
package dustin;
import org.junit.Assert;
import org.junit.Test;
/**
* Test for class dustin.Multiplier.
*
* @author Dustin
*/
public class MultiplierTest extends Multiplier
{
/** No-arguments constructor. */
public MultiplierTest() {}
@Test
public void testMultiplyTwoIntegers()
{
final int expectedProduct = 15;
final int resultProduct = multiply(3,5);
Assert.assertEquals(
"Product of multiplication of two integers does not match.",
expectedProduct, resultProduct);
}
@Test
public void testMultiplyTwoNegativeIntegers()
{
final int expectedProduct = 20;
final int resultProduct = multiply(-4,-5);
Assert.assertEquals(
"Product of multiplication of two negative integers does not match.",
expectedProduct, resultProduct);
}
@Test
public void testMultiplyTwoMixedSignIntegers()
{
final int expectedProduct = -12;
final int resultProduct = multiply(-3,4);
Assert.assertEquals(
"Product of multiplication of two integers of mixed sign does not match.",
expectedProduct, resultProduct);
}
}
With the source code written, the JUnit-based unit tests written, and the NetBeans Java Application project set up as shown above, it is almost trivial to run the unit tests. All one needs to do is use ALT+F6 or select Run->Test Project to run all the tests for that particular NetBeans project. The next two screen snapshots show how to run all of the tests and what the results look like.
Running All Project's Unit Tests

Results of All Project's Unit Tests Displayed in NetBeans

We can see that most of the tests passed, though the test that was intentionally rigged to fail (to serve our illustration needs) did lead to a report of a single test failure. We may have reason at this point to only run a single test. For example, we might want to fix a given test and only run it rather than run all the tests again. This would be an advantage in a more realistic situation where we have many more unit test classes than the two shown here and don't want to run all of them all of the time.
From NetBeans, we can run an individual test by right-clicking on that particular test result's output and selecting "Run Again." This is demonstrated for one of the successful tests and for the failed test in the next two screen snapshots.
Running Individual Test (Successful Test)

Running Individual Test (Failed Test)

When the two individual tests are re-run individually, their respective output is shown in the next two screen snapshots.
Results of Re-running Successful Individual Test

Results of Re-running Failed Individual Test

As has been demonstrated so far, it is really easy to run JUnit-based unit tests as a group or individually against the desired test method. As stated earlier, there are times when this behavior is desired from the command-line. Running the entire suite of tests is easy and is done by simply invoking the targets
compile-test and test to compile the unit tests and run the unit tests respectively. The default targets for an Ant-based build of a NetBeans project are shown in the next screen snapshot.
When one wishes to run a unit test individually from the command-line, there are a few additional details to know. From looking at the
build-impl.xml file generated by NetBeans (or by looking at the listed targets in the screen snapshot above), it is evident that one can invoke the test-single target to run an individual test. When one tries to do this with a command line ant test-single, the following output is experienced.
From the end of this output (that portion displayed in the above screen snapshot: "Must select some files in the IDE or set javac.includes"), it is clear that when this particular target is not executed within the NetBeans IDE, it requires a property
javac.includes to be set.An easy method to provide the
javac.includes property is to pass it as a name/value pair using the -D argument passed to the ant command. For example, to provide this to run the test "testWithIntentionalError," we can do so like this:
ant -Djavac.includes=dustin\AdderTest\testWithIntentionalError single-test
Executing the above line sets the
javac.includes property to the package name and method name of the individual test to be executed.With the
javac.includes property specified, we see a different result as demonstrated in the next screen snapshot. The message is another error message and is again pretty clear: "Must select some files in the IDE or set test.includes".
The same value can be specified for the
test.includes property as was specified for the javac.includes property. In this case, because we want to re-run the individual "testWithIntentionalError," we would use the following command:
ant -Djavac.includes=dustin\AdderTest\testWithIntentionalError -Dtest.includes=dustin\AdderTest\testWithIntentionalError test-single
The following screen snapshot displays the end of the properly executed individual test run.

From this screen snapshot, we see the results only for the AdderTest class (test suite) we specified in the
javac.includes and test.includes properties. This can be much quicker than waiting for all the test suites to run if we have a large number of them.As with all output of NetBeans-enabled JUnit test runs, significantly more output is available in the project's
build/test/results directory in a file named TEST-dustin.AdderTest.xml (XML file named after the package and test class).The generated XML file holding the results of the JUnit-based unit tests consists of a structure that looks something like this (I added the XML comment explaining that there are typically far more properties specified in these files, but they were left out here for brevity and clarity):
<testsuite errors="0" failures="1" hostname="MARX-PC" name="dustin.AdderTest" tests="5" time="0.109" timestamp="2009-03-15T00:24:06">
<properties>
<!-- Only a select sample of property settings are shown here. All of the
properties associated with the NetBeans project are declared as
name/value property pairs here in the same way that the select property
values below are declared. -->
<property name="ant.file.IndividualTesting-impl" value="C:\java\examples\IndividualTesting\nbproject\build-impl.xml" />
<property name="libs.proguard.javadoc" value="" />
<property name="ant.library.dir" value="C:\apache-ant-1.7.0-bin\apache-ant-1.7.0\lib" />
<property name="libs.Spring-2-5-6.src" value="" />
<property name="libs.junit.javadoc" value="C:\Program Files\NetBeans 6.5\java2\docs\junit-3.8.2-api.zip" />
<property name="javac.includes" value="dustin/AdderTest.java" />
<property name="user.name" value="Dustin" />
</properties>
<testcase classname="dustin.AdderTest" name="testAddWithTwoAddends" time="0.016" />
<testcase classname="dustin.AdderTest" name="testAddWithThreeAddends" time="0.0" />
<testcase classname="dustin.AdderTest" name="testAddWithFourAddends" time="0.0" />
<testcase classname="dustin.AdderTest" name="testAddWithTwoNegativeNumbers" time="0.0" />
<testcase classname="dustin.AdderTest" name="testWithIntentionalError" time="0.0">
<failure message="The two provided numbers do not add to what was expected. expected:<27> but was:<12>" type="junit.framework.AssertionFailedError">junit.framework.AssertionFailedError: The two provided numbers do not add to what was expected. expected:<27> but was:<12>
at dustin.AdderTest.testWithIntentionalError(AdderTest.java:60)
</failure>
</testcase>
<system-out><![CDATA[]]></system-out>
<system-err><![CDATA[]]></system-err>
</testsuite>
As the XML sample above indicates, the full result information is available in this file. Because it is well-formed XML, there are many tools and approaches one could use to view this data. The XML data can be viewed directly in a text editor, viewed in an XML tool that will color code it and indent it appropriately, translated with XSLT to another format, processed with Java XML parsing approaches such as JAXB, or viewed/processed with many other approaches.
Because we are using Ant and JUnit, the easiest method for viewing the test results is to take advantage of the optional Ant junitreport task. This is easily added to the build.xml file as a new target ("create-unit-test-report") as shown next:
<target name="create-unit-test-report"
description="Generate reports for executed JUnit unit tests.">
<mkdir dir="report" />
<junitreport todir="./report">
<fileset dir="./build/test/results">
<include name="TEST-*.xml"/>
</fileset>
<report format="frames" todir="./report/html"/>
</junitreport>
</target>
When this target is run, output similar to that shown in the next screen snapshot is seen.

In this case, the HTML generated via XSLT transformation of the unit test XML output is available under the project's newly created
report/html directory. When the index.html file in that directory is brought up in a web browser, it appears as shown in the two images that follow.

The Properties link in the bottom right corner of the web page shown in the last image can be clicked on to see the lengthy list of properties used in the NetBeans project in a more user-friendly format.
Conclusion
NetBeans makes it easy to run all units tests in a project or specific JUnit-based unit test suites and tests individually. It is not much more difficult to run individual unit test suites using the command-line as long as the
javac.includes and test.includes properties are specified when Ant is used to run the test-single target. More aesthetically pleasing output can be obtained by using Ant's junitreport tag to translate the XML output to a more desirable format such as the default HTML representation. For additional details on using NetBeans with JUnit, see Writing JUnit Tests in NetBeans IDE.
Friday, March 13, 2009
Java String Literals: No String Constructor Required
I think that most experienced Java developers are aware of many of the many characteristics of the Java String that make it a little different than other objects. One particular nuance of the Java String that people new to Java sometimes don't fully appreciate is that a literal String is already a String object.
When first learning Java it is really easy to write a String assignment like this:
This will compile and the initialized String blogUrlString will support any needs one might expect from a String. However, the downside of this particular statement is there are actually two String instantiations in this case and one of them is unnecessary. Because the String literal "http://marxsoftware.blogspot.com/" is already a full-fledged Java String, the new operator is unnecessary and results in an extraneous instantiation. The code above can be re-written as follows:
The unnecessary String instantiation demonstrated first will lead to reduced performance in Java applications. If the extraneous instantiation occurs in limited cases outside of loops, it is likely not to be a significant performance degradation. However, if it occurs within a loop, its performance impact can be much more significant. However, even when the performance issue is only slight, I still find the extra "new" instantiation to be less readable than the second method shown above.
Joshua Bloch uses an example similar to mine above to illustrate Item 5 ("Avoid Creating Unnecessary Objects") in the Second Edition of Effective Java. He points out that this extra instantiation in frequently called code can lead to performance problems.
To demonstrate the effect of this unnecessary extra instantiation of a String, I put together the following simple class (with a nested member class and a nested enum). The full code for it appears next.
RedundantStringExample.java
For the very simple code example used in the tests above, I needed to run the tests with many loops to see truly dramatic differences. However, the performance difference was obvious. I ran the tests several times for each test and averaged the results. In general, when the loops were large enough to differentiate significant differences, I found the method using the extraneous String instantiation to take roughly four times as long to execute as the loops using the String literal directly without the extra "new."
Although I ran each test on each number of loops, I show just one representative sample run for a few key data points in the following screen capture. I mark the results of running tests with 1 million loops in yellow and running with 10 million loops in red.

There are many cases in which the extra String instantiation demonstrated above might not have any significant performance impact. However, there is no positive of specifying an extra String instantiation and there is a negative in addition to reduced performance related to the extra code clutter.
Note that the examples above extend to similar String uses. Here is another slightly altered example.
Finally, as a reminder for anyone new to Java and Java Strings, if you find yourself assembling a large String from a large number of pieces, you will typically be better off using a StringBuilder or StringBuffer instead of a String. The root cause for this again has to do with too many String instantiations.
The Java String's behavior can seem a little strange until one gets used to it and even then it still might seem a little strange. The main point to remember related to this blog posting is that String literals are full-fledged String objects and so do not require the String constructor to be explicitly invoked.
Additional Resources
Java Tutorial: Strings
String Constructor Considered Useless Turns Out to be Useful After All
Use of the String(String) Constructor in Java
What is the Purpose of the Expression "new String(...)" in Java?
Java String@Everything2.com
When first learning Java it is really easy to write a String assignment like this:
// Unnecessary and redundant String instantiation
String blogUrlString = new String("http://marxsoftware.blogspot.com/");
This will compile and the initialized String blogUrlString will support any needs one might expect from a String. However, the downside of this particular statement is there are actually two String instantiations in this case and one of them is unnecessary. Because the String literal "http://marxsoftware.blogspot.com/" is already a full-fledged Java String, the new operator is unnecessary and results in an extraneous instantiation. The code above can be re-written as follows:
// The 'new' keyword is not needed because the literal String is a full String object
String blogUrlString = "http://marxsoftware.blogspot.com/";
The unnecessary String instantiation demonstrated first will lead to reduced performance in Java applications. If the extraneous instantiation occurs in limited cases outside of loops, it is likely not to be a significant performance degradation. However, if it occurs within a loop, its performance impact can be much more significant. However, even when the performance issue is only slight, I still find the extra "new" instantiation to be less readable than the second method shown above.
Joshua Bloch uses an example similar to mine above to illustrate Item 5 ("Avoid Creating Unnecessary Objects") in the Second Edition of Effective Java. He points out that this extra instantiation in frequently called code can lead to performance problems.
To demonstrate the effect of this unnecessary extra instantiation of a String, I put together the following simple class (with a nested member class and a nested enum). The full code for it appears next.
RedundantStringExample.java
package dustin.examples;
import java.util.ArrayList;
import java.util.List;
/**
* Example demonstrating effect of redundant String instantiation.
*/
public class RedundantStringExample
{
/** Operating System-independent New line character. */
private static final String NEW_LINE = System.getProperty("line.separator");
/** List of Strings. */
private List<String> strings = new ArrayList<String>();
/** No-arguments constructor. */
public RedundantStringExample() {}
/**
* Test performance in loop over single String instantiation that is
* executed the number of times as provided by the passed-in argument.
*
* @param numberOfLoops Number of times to instantiate Single String.
* @return Results of this test.
*/
public TestResult testSingleString(final int numberOfLoops)
{
final TestResult result = new TestResult(numberOfLoops, TestType.SINGLE);
result.startTimer();
for (int counter = 0; counter < numberOfLoops; counter++)
{
strings.add("http://marxsoftware.blogspot.com/");
}
result.stopTimer();
return result;
}
/**
* Test performance in loop over redundant String instantiations that is
* executed the number of times as provided by the passed-in argument.
*
* @param numberOfLoops Number of times to instantiate Single String.
* @return Results of this test.
*/
public TestResult testRedundantStrings(final int numberOfLoops)
{
final TestResult result = new TestResult(numberOfLoops, TestType.REDUNDANT);
result.startTimer();
for (int counter = 0; counter < numberOfLoops; counter++)
{
strings.add(new String("http://marxsoftware.blogspot.com/"));
}
result.stopTimer();
return result;
}
/**
* Run the examples based on provided command-line arguments.
*
* @param arguments Command-line arguments where the first argument should
* be an integer (not decimal) numeral.
*/
public static void main(final String[] arguments)
{
final int numberArguments = arguments.length;
if (numberArguments < 2)
{
System.err.println("Please provide two command-line arguments:");
System.err.println("\tIntegral number of times to instantiate Strings");
System.err.println("\tType of test to run ('redundant', 'constant', or 'single')");
System.exit(-2);
}
final int numberOfExecutions = Integer.valueOf(arguments[0]);
final String testChoice = arguments[1];
if (testChoice == null || testChoice.isEmpty())
{
System.err.println("The second argument must be a test choice.");
System.exit(-1);
}
final RedundantStringExample me = new RedundantStringExample();
TestResult testResult = null;
if (testChoice.equalsIgnoreCase("redundant"))
{
testResult = me.testRedundantStrings(numberOfExecutions);
}
else // testChoice is "single" or something unexpected
{
testResult = me.testSingleString(numberOfExecutions);
}
System.out.println(testResult);
}
/**
* Class used to pass test results back to caller.
*/
private static class TestResult
{
/** Number of milliseconds per second. */
private static final long MILLISECONDS_PER_SECOND = 1000;
/** Number of String instantiations. */
private int numberOfExecutions;
/** Type of test this result applies to. */
private TestType testType;
/** Test begining time. */
private long startTime = -1L;
/** Test ending time. */
private long finishTime = -1L;
/**
* Constructor acceptes argument indicating number of times applicable
* test should be run
*
* @param newNumberOfExecutions Times test whose result this is will be/was
* executed.
* @param newTestType Type of test executed for this result
*/
public TestResult(final int newNumberOfExecutions, final TestType newTestType)
{
numberOfExecutions = newNumberOfExecutions;
testType = newTestType;
}
/**
* Start timer.
*/
public void startTimer()
{
startTime = System.currentTimeMillis();
}
/**
* Stop timer.
*
* @throws IllegalStateException Thrown if this stopTimer() method is
* called and the corresponding startTimer() method was never called or
* if the calculated finish time is earlier than the start time.
*/
public void stopTimer()
{
if (startTime < 0 )
{
throw new IllegalStateException(
"Cannot stop timer because it was never started!");
}
finishTime = System.currentTimeMillis();
if (finishTime < startTime)
{
throw new IllegalStateException(
"Cannot have a stop time [" + finishTime + "] that is less than "
+ "the start time [" + startTime + "]");
}
}
/**
* Provide the number of milliseconds spent in execution of test.
*
* @return Number of milliseconds spent in execution of test.
* @throws IllegalStateException Thrown if the time spent is invalid
* due to the finish time being less than (earlier than) the start time.
*/
public long getMillisecondsSpent()
{
if (finishTime < startTime)
{
throw new IllegalStateException(
"The time spent is invalid because the finish time ["
+ finishTime + " is later than the start time ["
+ startTime + "].");
}
return finishTime - startTime;
}
/**
* Provide the number of seconds spent in execution of test.
*
* @return Number of seconds spent in execution of test.
*/
public double getSecondsSpent()
{
return getMillisecondsSpent() / MILLISECONDS_PER_SECOND;
}
/**
* Provide the number of executions run as part of this test.
*
* @return Number of executions of this test.
*/
public int getNumberOfExecution()
{
return numberOfExecutions;
}
/**
* Provide the type of this test.
*
* @return Type of this test.
*/
public TestType getTestType()
{
return testType;
}
/**
* Provide String representation of me.
*
* @return My String representation.
*/
@Override
public String toString()
{
final StringBuilder builder = new StringBuilder();
builder.append("TEST RESULTS:").append(NEW_LINE);
builder.append("Type of Test: ").append(testType).append(NEW_LINE);
builder.append("Number of Executions: ").append(numberOfExecutions).append(NEW_LINE);
builder.append("Elapsed Time (milliseconds): ").append(getMillisecondsSpent()).append(NEW_LINE);
builder.append("\t\tStart: ").append(startTime);
builder.append(" ; Stop: ").append(finishTime);
return builder.toString();
}
}
/** Enum representing type of Test. */
private static enum TestType
{
SINGLE,
REDUNDANT
}
}
For the very simple code example used in the tests above, I needed to run the tests with many loops to see truly dramatic differences. However, the performance difference was obvious. I ran the tests several times for each test and averaged the results. In general, when the loops were large enough to differentiate significant differences, I found the method using the extraneous String instantiation to take roughly four times as long to execute as the loops using the String literal directly without the extra "new."
Although I ran each test on each number of loops, I show just one representative sample run for a few key data points in the following screen capture. I mark the results of running tests with 1 million loops in yellow and running with 10 million loops in red.

There are many cases in which the extra String instantiation demonstrated above might not have any significant performance impact. However, there is no positive of specifying an extra String instantiation and there is a negative in addition to reduced performance related to the extra code clutter.
Note that the examples above extend to similar String uses. Here is another slightly altered example.
// the way NOT to do it
String someString = new String("http://" + theDomain + ":" + thePort + "/servicecontext");
// better way to do this; don't need extra new instantiation
String someString = "http://" + theDomain + ":" + thePort + "/serviceContext";
// NOTE: If you start using loops to assemble long Strings similar to those
// shown above, performance needs will likely dictate use of StringBuilder
// or StringBuffer instead. See
// http://marxsoftware.blogspot.com/2008/05/string-stringbuffer-and-stringbuilder.html
// for additional details.
Finally, as a reminder for anyone new to Java and Java Strings, if you find yourself assembling a large String from a large number of pieces, you will typically be better off using a StringBuilder or StringBuffer instead of a String. The root cause for this again has to do with too many String instantiations.
The Java String's behavior can seem a little strange until one gets used to it and even then it still might seem a little strange. The main point to remember related to this blog posting is that String literals are full-fledged String objects and so do not require the String constructor to be explicitly invoked.
Additional Resources
Java Tutorial: Strings
String Constructor Considered Useless Turns Out to be Useful After All
Use of the String(String) Constructor in Java
What is the Purpose of the Expression "new String(...)" in Java?
Java String@Everything2.com
Monday, March 9, 2009
Including Images in Javadoc with NetBeans
There are times when it is useful to include images and other non-source files in the documentation generated with Javadoc. The Javadoc tool documentation refers to these types of non-Java source files as Miscellaneous Unprocessed Files and states that they should be placed in a
When using Javadoc directly or via direct use of Ant, these
This issue of NetBeans Ant-based Javadoc generation target not copying non-source files is discussed in the Sun Forum on the Javadoc Tool in the javadoc not copying from doc-files directories thread. In that forum, two postings recommend adding an alternate Ant target or overriding the NetBeans-built Ant target for generating Javadoc to support this copying. These are both useful approaches, but I think the easiest approach is to simply take advantage of NetBeans's hook for additional Javadoc tool arguments.
NetBeans generates a target with name
One really easy way to have non-Java files copied to the generated Javadoc documentation is to take advantage of the
The
doc-files subdirectory within the package directory to which the non-source file applies.When using Javadoc directly or via direct use of Ant, these
doc-files subdirectories are copied into the generated Javadoc documentation directories and are available to the HTML pages that make up the generated documentation. Unfortunately, the Javadoc mechanism provided by NetBeans 6.1 and NetBeans 6.5 for a standard NetBeans Java Application project does not support this unprocessed file copying directly. Fortunately, this is easy to address.This issue of NetBeans Ant-based Javadoc generation target not copying non-source files is discussed in the Sun Forum on the Javadoc Tool in the javadoc not copying from doc-files directories thread. In that forum, two postings recommend adding an alternate Ant target or overriding the NetBeans-built Ant target for generating Javadoc to support this copying. These are both useful approaches, but I think the easiest approach is to simply take advantage of NetBeans's hook for additional Javadoc tool arguments.
NetBeans generates a target with name
-javadoc-build in the generated build-impl.xml file that resides in the project's nbproject directory. This target invokes the Ant core javadoc tag to run the Javadoc tool. This target uses a nested fileset tag to specify that all Java files (**/*.java) should have documentation generated. Because **/*.java is specified, only Java files have documentation generated.One really easy way to have non-Java files copied to the generated Javadoc documentation is to take advantage of the
additionalparam attribute of the Javadoc tag. I often use this attribute to specify the -linksource argument in Javadoc generation, but it can be used to specify that all directories and files under the source directory get copied by specifying the -sourcepath argument. For example, if the source directory is specified with a property like ${src.dir}, one can set additionalparam=-sourcepath ${src.dir}. NetBeans allows the additionalparam option for Javadoc to be easily specified by setting the ${javadoc.additionalparam} property in the project.properties file in the same nbproject directory.The
javadoc.additionalparam property is very useful in the NetBeans development environment when one needs to override settings of its Javadoc generation that do not provide their own property-based handles.
Sunday, March 8, 2009
Colorado Software Summit 2008 Keynote Presentations Released
Colorado Software Summit 2009 has been announced (25-30 October 2009) and the main web site has been redesigned as part of this announcement. The two keynote presentations from last year's edition, Colorado Software Summit 2008, have also been made available from this main page.
As has been a conference tradition for many years, John Soyring opened the technical portion of the conference on Monday morning with the opening keynote presentation Change ... that Matters. Simon Phipps presented the Thursday morning keynote presentation The Adoption-Led Market: The Third Wave of Open Source? I blogged on these presentations after attending them and those postings are available here (Soyring's presentation) and here (Phipps's presentation).
In addition to these two keynote addresses from Colorado Software Summit 2008, you can find presentations from earlier versions of the conference on the Previous Conferences page. The page points out that additional presentations from Colorado Software Summit 2008 will be made available throughout the year.
As has been a conference tradition for many years, John Soyring opened the technical portion of the conference on Monday morning with the opening keynote presentation Change ... that Matters. Simon Phipps presented the Thursday morning keynote presentation The Adoption-Led Market: The Third Wave of Open Source? I blogged on these presentations after attending them and those postings are available here (Soyring's presentation) and here (Phipps's presentation).
In addition to these two keynote addresses from Colorado Software Summit 2008, you can find presentations from earlier versions of the conference on the Previous Conferences page. The page points out that additional presentations from Colorado Software Summit 2008 will be made available throughout the year.
Sunday, March 1, 2009
JavaOne 2009 News: Initial Acceptance/Rejection Announcements
An idea of the types of presentations that will be available at this year's edition of JavaOne (2009) is starting to form with notices going up all over the blogosphere about presentations being accepted or rejected. I have been curious if JavaFX would be the dominant topic for a third straight year. As we hear more about which presentations have been accepted, we may begin to know if JavaFX is going to be the Main Event once again. Note that All JavaOne Blogs provides a nice collection of blog postings focused on the 2009 JavaOne Conference. The JavaOne Conference on Facebook is also available.
2009 JavaOne General Background
According to this announcement for open registration, over 1300 abstracts were submitted for the 2009 JavaOne Conference. This also explains that "35 external reviewers" plus a "panel of Sun employees" review the abstracts.
The topics that are the focus of 2009 JavaOne are Rich Media Applications and Interactive Content, Mobility, Services, and Core Technologies.
Kirk Pepperdine's blog posting Your JavaONE Proposal Has Been Rejected explains Kirk's perspective on why Sun employees do get the lion's share of presentations at JavaOne. He asserts that there is no favoritism, but that it is more a reflection of the fact that it is Sun employees working on the products being selected for discussion. He also points out (and Cay Horstmann's feedback comment reiterates) that there are many more high-quality presentations than available slots.
Lukas Hasik explains in one of his blog postings that only Sun employees are allowed to submit Hands-On Labs (HOLs) for JavaOne and that the process for these differs from that for presentations and Birds of a Feather (BOFs).
Eric D. Schabell has posted a copy of a rejection letter that explains that the submitted abstracts exceeded capacity by over 400% and provides a link to the well-known post How to Get Your JavaOne Talk Accepted.
There is much discussion about an under-representation of Groovy, Grails, and Griffon at this JavaOne. Among other posts, this is highlighted in Thoughts on Groovy, Grails, Griffon at JavaOne and No Grails at JavaOne.
Specifically Accepted Presentations
The following are some of the presentations that have been advertised by someone as selected for 2009 JavaOne. I expect to see more blogs on accepted presentations this coming week and then, of course, the full schedule to be released in the near future. UPDATE: Some of the linked-to announcements of accepted abstracts have been added since the original posting.
Specifically Rejected Presentations
Bloggers are understandably less excited about announcing their rejected abstracts, but their experiences do provide insight into the process and what the likely focus of the conference will be. Also, these people are in good company as many well-known speakers seem to have their abstracts rejected. This 2005 post shows that this is nothing new.
The 2009 JavaOne Conference will be held June 2-5, 2009. Contrary to a purported rumor, this edition of JavaOne will again be held at The Moscone Center in San Francisco.
2009 JavaOne General Background
According to this announcement for open registration, over 1300 abstracts were submitted for the 2009 JavaOne Conference. This also explains that "35 external reviewers" plus a "panel of Sun employees" review the abstracts.
The topics that are the focus of 2009 JavaOne are Rich Media Applications and Interactive Content, Mobility, Services, and Core Technologies.
Kirk Pepperdine's blog posting Your JavaONE Proposal Has Been Rejected explains Kirk's perspective on why Sun employees do get the lion's share of presentations at JavaOne. He asserts that there is no favoritism, but that it is more a reflection of the fact that it is Sun employees working on the products being selected for discussion. He also points out (and Cay Horstmann's feedback comment reiterates) that there are many more high-quality presentations than available slots.
Lukas Hasik explains in one of his blog postings that only Sun employees are allowed to submit Hands-On Labs (HOLs) for JavaOne and that the process for these differs from that for presentations and Birds of a Feather (BOFs).
Eric D. Schabell has posted a copy of a rejection letter that explains that the submitted abstracts exceeded capacity by over 400% and provides a link to the well-known post How to Get Your JavaOne Talk Accepted.
There is much discussion about an under-representation of Groovy, Grails, and Griffon at this JavaOne. Among other posts, this is highlighted in Thoughts on Groovy, Grails, Griffon at JavaOne and No Grails at JavaOne.
Specifically Accepted Presentations
The following are some of the presentations that have been advertised by someone as selected for 2009 JavaOne. I expect to see more blogs on accepted presentations this coming week and then, of course, the full schedule to be released in the near future. UPDATE: Some of the linked-to announcements of accepted abstracts have been added since the original posting.
- Object Oriented Ant Scripts for the Enterprise (Douglas Bullard) [reference: feedback comment #6]
- Grails Integration Strategies (Dave Klein)
- Simplifying Development and Testing of GUIs with the Swing Application Framework (JSR 296) and FEST (Michael Hüttermann)
- Energy, CO2 Savings with Java™ Platform, Enterprise Edition and More: Project GreenFire (Adam Bien)
- Getting More Out of the Java VisualVM Tool (Geertjan Wielenga)
- [HOL] Adding Some Oomph to the Java VisualVM Tool (Geertjan Wielenga)
- [HOL] Save Your Time : Build Quickly Apps With RCP (Lukas Hasik)
- [HOL] Touch your application! - Building slick, touch-enabled UI for Java ME (Lukas Hasik)
- Developing LimeWire: Swing for the Masses (Sam)
- Caciocavallo Goes to JavaOne (Roman Kennke and Andrei Dmitriev)
- Applying Complex Event Processing (CEP) with a Stateful Rules Engine for Real-Time Intelligence (Mark Proctor and Adam Mollenkopf)
- JPA/Database Performance Tuning (Reza Rahman and Debu Panda)
- [BOF] Uses of Embedded EJB3 Containers (Reza Rahman and David Blevins)
- [BOF] A Lightweight Approach to Port JDK Software GUI Library to Unsupported Mobile/Desktop Devices (Mario Torre)
- JFugue (Brian Tarbox and David Koelle)
- [BOF] OpenJDK Porters (robilad and David Herron)
Specifically Rejected Presentations
Bloggers are understandably less excited about announcing their rejected abstracts, but their experiences do provide insight into the process and what the likely focus of the conference will be. Also, these people are in good company as many well-known speakers seem to have their abstracts rejected. This 2005 post shows that this is nothing new.
- Java Defeating the Financial Crisis - A Tale from the Font Line (Eric D. Schabell)
- David Calavera
- Bob McWhirter (6 rejections for 3 abstracts)
The 2009 JavaOne Conference will be held June 2-5, 2009. Contrary to a purported rumor, this edition of JavaOne will again be held at The Moscone Center in San Francisco.
Subscribe to:
Posts (Atom)