Thứ Bảy, 24 tháng 11, 2012

Scripted Reports with Groovy

Groovy has become my favorite scripting language and in this blog I look at some of Groovy's features that make it particularly attractive for presenting text-based reports. The post will show how custom text-based reports of data stored in the database can be easily presented with Groovy. I will highlight several attractive features of Groovy along the way.

I use the Oracle Database 11g Express Edition (XE) for the data source in my example in this post, but any data source could be used. This example does make use of Groovy's excellent SQL/JDBC support and uses the Oracle sample schema (HR). A visual depiction of that sample schema is available in the sample schema documentation.

My example of using Groovy to write a reporting script involves retrieving data from the Oracle HR sample schema and presenting that data via a text-based report. One portion of the script needs to acquire this data from the database and Groovy adds only minimal ceremony to the SQL statement needed to do this. The following code snippet from the script shows use of Groovy's multi-line GString to specify the SQL query string in a user-friendly format and to process the results of that query.


def employeeQueryStr =
"""SELECT e.employee_id, e.first_name, e.last_name,
e.email, e.phone_number,
e.hire_date, e.job_id, j.job_title,
e.salary, e.commission_pct, e.manager_id,
e.department_id, d.department_name,
m.first_name AS mgr_first_name, m.last_name AS mgr_last_name
FROM employees e, departments d, jobs j, employees m
WHERE e.department_id = d.department_id
AND e.job_id = j.job_id
AND e.manager_id = m.employee_id(+)"""

def employees = new TreeMap<Long, Employee>()
import groovy.sql.Sql
def sql = Sql.newInstance("jdbc:oracle:thin:@localhost:1521:xe", "hr", "hr",
"oracle.jdbc.pool.OracleDataSource")
sql.eachRow(employeeQueryStr)
{
def employeeId = it.employee_id as Long
def employee = new Employee(employeeId, it.first_name, it.last_name,
it.email, it.phone_number,
it.hire_date, it.job_id, it.job_title,
it.salary, it.commission_pct, it.manager_id as Long,
it.department_id as Long, it.department_name,
it.mgr_first_name, it.mgr_last_name)
employees.put(employeeId, employee)
}

The Groovy code above only adds a small amount of code on top of the Oracle SQL statement. The specified SELECT statement joins multiple tables and includes an outer join as well (outer join needed to include the President in the query results despite that position not having a manager). The vast majority of the first part of the code is the SQL statement that could be run as-is in SQL*Plus or SQL Developer. No need for verbose exception catching and result set handling with Groovy's SQL support!

There are more Groovy-specific advantages to point out in the code snippet above. Note that the import statement to import groovy.sql.Sql was allowed when needed and did not need to be at the top of the script file. The example also used Sql.newInstance and Sql.eachRow(GString,Closure). The latter method allows for easy application of a closure to the results of the query. The it special word is the default name for items being processed in the closure. In this case,it can be thought of a a row in the result set. Values in each row are accessed by the underlying database columns' names (or aliases in the case of mgr_first_name and mgr_last_name).

One of the advantages of Groovy is its seamless integration with Java. The above code snippet also demonstrated this via Groovy's use of TreeMap, which is advantageous because it means that the new Employee instances placed in the map based on data retrieved from the database will always be available in order of employee ID.

In the code above, the information retrieved from the database and processed via the closure is stored for each row in a newly instantiated Employee object. This Employee object provides another place to show off Groovy's brevity and is shown next.

Employee.groovy

@groovy.transform.Canonical
class Employee
{
Long employeeId
String firstName
String lastName
String emailAddress
String phone_number
Date hireDate
String jobId
String jobTitle
BigDecimal salary
BigDecimal commissionPercentage
Long managerId
Long departmentId
String departmentName
String managerFirstName
String managerLastName
}

The code listing just shown is the entire class! Groovy's property supports makes getter/setter methods automatically available for all the defined class attributes. As I discussed in a previous blog post, the @Canonical annotation is a Groovy AST (transformation) that automatically creates several useful common methods for this class [equals(Object), hashCode(), and toString()]. There is no explicit constructor because @Canonical also handles this, providing a constructor that accepts that class's arguments in the order they are specified in their declarations. It is difficult to image a scenario in which it would be easier to easily and quickly create an object to store retrieved data values in a script.

A JDBC driver is needed for this script to retrieve this data from the Oracle Database XE and the JAR for that driver could be specified on the classpath when running the Groovy script. However, I like my scripts to be as self-contained as possible and this makes Groovy's classpath root loading mechanism attractive. This can be used within this script (rather than specifying it externally when invoking the script) as shown next:


this.class.classLoader.rootLoader.addURL(
new URL("file:///C:/oraclexe/app/oracle/product/11.2.0/server/jdbc/lib/ojdbc6.jar"))

Side Note: Another nifty approach for accessing the appropriate dependent JAR or library is use of Groovy's Grape-provided @Grab annotation. I didn't use that here because Oracle's JDBC JAR is not available in any legitimate Maven central repositories that I am aware of. An example of using this approach when a dependency is available in the Maven public repository is shown in my blog post Easy Groovy Logger Injection and Log Guarding.

With the data retrieved from the database and placed in a collection of simple Groovy objects built for holding this data and providing easy access to it, it is almost time to start presenting this data in a text report. Some constants defined in the script are shown in the next excerpt from the script code.


int TOTAL_WIDTH = 120
String HEADER_ROW_SEPARATOR = "=".multiply(TOTAL_WIDTH)
String ROW_SEPARATOR = "-".multiply(TOTAL_WIDTH)
String COLUMN_SEPARATOR = "|"
int COLUMN_SEPARATOR_SIZE = COLUMN_SEPARATOR.size()
int COLUMN_WIDTH = 22
int TOTAL_NUM_COLUMNS = 5
int BALANCE_COLUMN_WIDTH = TOTAL_WIDTH-(TOTAL_NUM_COLUMNS-1)*COLUMN_WIDTH-COLUMN_SEPARATOR_SIZE*(TOTAL_NUM_COLUMNS-1)-2

The declaration of constants just shown exemplify more advantages of Groovy. For one, the constants are statically typed, demonstrating Groovy's flexibility to specifying types statically as well as dynamically. Another feature of Groovy worth special note in the last code snippet is the use of the String.multiply(Number) method on the literal Strings. Everything, even Strings and numerics, are objects in Groovy. The multiply method makes it easy to create a String of that number of the same repeating character.

The first part of the text output is the header. The following lines of the Groovy script write this header information to standard output.


println "\n\n${HEADER_ROW_SEPARATOR}"
println "${COLUMN_SEPARATOR}${'HR SCHEMA EMPLOYEES'.center(TOTAL_WIDTH-2*COLUMN_SEPARATOR_SIZE)}${COLUMN_SEPARATOR}"
println HEADER_ROW_SEPARATOR
print "${COLUMN_SEPARATOR}${'EMPLOYEE ID/HIRE DATE'.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
print "${'EMPLOYEE NAME'.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
print "${'TITLE/DEPARTMENT'.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
print "${'SALARY INFO'.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
println "${'CONTACT INFO'.center(BALANCE_COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
println HEADER_ROW_SEPARATOR

The code above shows some more addictive features of Groovy. One of my favorite aspects of Groovy's GString support is the ability to use Ant-like ${} expressions to provide executable code inline with the String. The code above also shows off Groovy's GDK String's support for the center(Number) method that automatically centers the given String withing the specified number of characters. This is a powerful feature for easily writing attractive text output.

With the data retrieved and available in our data structure and with the constants defined, the output portion can begin. The next code snippet shows use of Groovy's standard collections each method to allow iteration over the previously populated TreeMap with a closure applied to each iteration.


employees.each
{ id, employee ->
// first line in each output row
def idStr = id as String
print "${COLUMN_SEPARATOR}${idStr.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
def employeeName = employee.firstName + " " + employee.lastName
print "${employeeName.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
def jobTitle = employee.jobTitle.replace("Vice President", "VP").replace("Assistant", "Asst").replace("Representative", "Rep")
print "${jobTitle.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
def salary = '$' + (employee.salary as String)
print "${salary.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
println "${employee.phone_number.center(BALANCE_COLUMN_WIDTH)}${COLUMN_SEPARATOR}"

// second line in each output row
print "${COLUMN_SEPARATOR}${employee.hireDate.getDateString().center(COLUMN_WIDTH)}"
def managerName = employee.managerFirstName ? "Mgr: ${employee.managerFirstName[0]}. ${employee.managerLastName}" : "Answers to No One"
print "${COLUMN_SEPARATOR}${managerName.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
print "${employee.departmentName.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
String commissionPercentage = employee.commissionPercentage ?: "No Commission"
print "${commissionPercentage.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
println "${employee.emailAddress.center(BALANCE_COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
println ROW_SEPARATOR
}

The last code snippet is where the data retrieved from the database is output in a relatively attractive text format. The example shows how handles in a closure can be named to be more meaningful. In this case, they are named id and employee and represent the key (Long) and value (Employee) of each entry in the TreeMap.

There are other Groovy features in the last code snippet worth special mention. The presentation of commission uses Groovy's Elvis operator (?:), which makes even Java's conditional ternary look verbose. In this example, if the employee's commission percentage meets Groovy truth standards, that percentage is used; otherwise, "No Commission" is printed.

The handling of the hire date provides another opportunity to tout Groovy's GDK benefits. In this case, Groovy GDK Date.getDateString() is used to easily access the date-only portion of the Date class (time not desired for hire date) without explicit use of a String formatter. Nice!

The last code example also demonstrates use of the as keyword to coerce (cast) variables in a more readable way and also demonstrates more leverage of Java features, in this case taking advantage of Java String's replace(CharSequence, CharSequence) method. Groovy adds some more goodness to String again in this example, however. The example demonstrates Groovy's supporting extracting the first letter only of the manager's first name using subscript (array) notation ([0]) to get only the first character out of the string.

So far in this post, I've shown snippets of the overall script as I explained the various features of Groovy that are demonstrated in each snippet. The entire script is shown next and that code listing is followed by a screen snapshot of how the output appears when the script is executed. The complete code for the Groovy Employee class was shown previously.

generateReport.groovy: The Complete Script

#!/usr/bin/env groovy

// Add JDBC driver to classpath as part of this script's bootstrapping.
// See http://marxsoftware.blogspot.com/2011/02/groovy-scripts-master-their-own.html.
// WARNING: This location needs to be adjusted for specific user environment.
this.class.classLoader.rootLoader.addURL(
new URL("file:///C:/oraclexe/app/oracle/product/11.2.0/server/jdbc/lib/ojdbc6.jar"))


int TOTAL_WIDTH = 120
String HEADER_ROW_SEPARATOR = "=".multiply(TOTAL_WIDTH)
String ROW_SEPARATOR = "-".multiply(TOTAL_WIDTH)
String COLUMN_SEPARATOR = "|"
int COLUMN_SEPARATOR_SIZE = COLUMN_SEPARATOR.size()
int COLUMN_WIDTH = 22
int TOTAL_NUM_COLUMNS = 5
int BALANCE_COLUMN_WIDTH = TOTAL_WIDTH-(TOTAL_NUM_COLUMNS-1)*COLUMN_WIDTH-COLUMN_SEPARATOR_SIZE*(TOTAL_NUM_COLUMNS-1)-2



// Get instance of Groovy's Sql class
// See http://marxsoftware.blogspot.com/2009/05/groovysql-groovy-jdbc.html
import groovy.sql.Sql
def sql = Sql.newInstance("jdbc:oracle:thin:@localhost:1521:xe", "hr", "hr",
"oracle.jdbc.pool.OracleDataSource")

def employeeQueryStr =
"""SELECT e.employee_id, e.first_name, e.last_name,
e.email, e.phone_number,
e.hire_date, e.job_id, j.job_title,
e.salary, e.commission_pct, e.manager_id,
e.department_id, d.department_name,
m.first_name AS mgr_first_name, m.last_name AS mgr_last_name
FROM employees e, departments d, jobs j, employees m
WHERE e.department_id = d.department_id
AND e.job_id = j.job_id
AND e.manager_id = m.employee_id(+)"""

def employees = new TreeMap<Long, Employee>()
sql.eachRow(employeeQueryStr)
{
def employeeId = it.employee_id as Long
def employee = new Employee(employeeId, it.first_name, it.last_name,
it.email, it.phone_number,
it.hire_date, it.job_id, it.job_title,
it.salary, it.commission_pct, it.manager_id as Long,
it.department_id as Long, it.department_name,
it.mgr_first_name, it.mgr_last_name)
employees.put(employeeId, employee)
}

println "\n\n${HEADER_ROW_SEPARATOR}"
println "${COLUMN_SEPARATOR}${'HR SCHEMA EMPLOYEES'.center(TOTAL_WIDTH-2*COLUMN_SEPARATOR_SIZE)}${COLUMN_SEPARATOR}"
println HEADER_ROW_SEPARATOR
print "${COLUMN_SEPARATOR}${'EMPLOYEE ID/HIRE DATE'.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
print "${'EMPLOYEE NAME'.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
print "${'TITLE/DEPARTMENT'.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
print "${'SALARY INFO'.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
println "${'CONTACT INFO'.center(BALANCE_COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
println HEADER_ROW_SEPARATOR

employees.each
{ id, employee ->
// first line in each row
def idStr = id as String
print "${COLUMN_SEPARATOR}${idStr.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
def employeeName = employee.firstName + " " + employee.lastName
print "${employeeName.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
def jobTitle = employee.jobTitle.replace("Vice President", "VP").replace("Assistant", "Asst").replace("Representative", "Rep")
print "${jobTitle.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
def salary = '$' + (employee.salary as String)
print "${salary.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
println "${employee.phone_number.center(BALANCE_COLUMN_WIDTH)}${COLUMN_SEPARATOR}"

// second line in each row
print "${COLUMN_SEPARATOR}${employee.hireDate.getDateString().center(COLUMN_WIDTH)}"
def managerName = employee.managerFirstName ? "Mgr: ${employee.managerFirstName[0]}. ${employee.managerLastName}" : "Answers to No One"
print "${COLUMN_SEPARATOR}${managerName.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
print "${employee.departmentName.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
String commissionPercentage = employee.commissionPercentage ?: "No Commission"
print "${commissionPercentage.center(COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
println "${employee.emailAddress.center(BALANCE_COLUMN_WIDTH)}${COLUMN_SEPARATOR}"
println ROW_SEPARATOR
}

In this blog post, I've attempted to show how Groovy provides numerous features and other syntax support that make it easier to write scripts for generating readable and relatively attractive output. For more general Groovy scripts that provide text output support, see Formatting simple tabular text data. Although these are nice general solutions, an objective of my post has been to show that it is easy and does not take much time to write customized scripts for generating custom text output with Groovy. Small Groovy-isms such as easily centering a String, easily converting a Date to a String, extracting any desired character from a string based on array position notation, and easily accessing database data make Groovy a powerful tool in generating text-based reports.

Thứ Bảy, 17 tháng 11, 2012

RMOUG Training Days 2013 Presentations Announced: A Mobile Emphasis

The Rocky Mountain Oracle Users Group (RMOUG) has announced the presentations to be given at Training Days 2013. As shown on that page, I will be presenting "Charting Oracle Database Data with JavaFX and Groovy." The abstract for my presentation as shown on the conference materials is shown next:

JavaFX 2.x makes generation and display of data-powered charts powerful and straightforward. JavaFX’s simple APIs allow data sets to be used to create numerous types of charts including pie charts, bar charts, line charts, area charts, bubble charts, and more. JavaFX also supports dynamic charts that are automatically updated when the underlying data changes. With JavaFX poised to become part of Java SE, it is destined to be a standardized technology that is readily available in many environments.

Groovy is a dynamic scripting language that also runs on the JVM and can be used to write concise but powerful scripts. Groovy makes retrieving data from a database relatively painless and is much easier to use than even JDBC. Groovy’s XML parsing is also similarly easy to use and makes Groovy an ideal language for parsing XML to generate charts. JavaFX and Groovy together make it easy to write simple scripts that easily create visually impressive charting results. JavaFX and Groovy can be used with other Java/JVM-based libraries to generate these charts in various medium from websites to desktop clients to PDFs.

I also intend to discuss in this presentation an obvious topic when discussing use of JavaFX and Groovy together: GroovyFX.

One of the major themes of this year's RMOUG Training Days 2013 conference appears to be developing mobile applications, either with Oracle Application Express (APEX) or with Oracle ADF Mobile. The main Oracle web page on Oracle ADF Mobile describes it as "an HTML5 and Java mobile development framework that enables developers to build and extend enterprise applications for iOS and Android from a single code base" and is "based on a hybrid mobile architecture" and "supports access to native device services." The following are some of the sessions at RMOUG Training Days 2013 that are obviously covering mobile application development with Oracle ADF Mobile or with APEX.

  • Mobile Integration through Oracle Technologies
    • Objectives and outline indicate this session will cover general mobile development with Oracle technologies.
    • Jordan Braunstein, Visual Integrator Consulting
  • Oracle ADF – The No Slides Overview
    • "See how far you can get with Oracle ADF in one hour of building web and mobile applications."
    • Shay Shmeltzer, Oracle Corporation
  • Develop Compelling On-Device Mobile Apps – The Simpler Way
    • "This session will discuss and demonstrate developing an on-device mobile application using the technologies and tools you are familiar with: JDeveloper, Java, and ADF Mobile, without writing a single line of device-native code. You can deploy this single code base to both iOS and Android-based devices."
    • Joe Huang, Oracle Corporation
  • ADF Mobile eCourse Pilot
    • "Through interactive presentation and hands-on exercises, you’ll examine the principles to consider when designing mobile applications, as well as understand the road map for developing them."
    • Lynn Munsinger, Oracle Corporation
  • Bring Your iPads! (Because You’re Gonna Build a Mobile APEX App in One Hour!)
    • "Oracle Application Express integrates very easily with JQuery Mobile and this combination can be used to create mobile applications that are supported on a wide range of mobile devices relatively simple."
    • Chris Ostrowski, Avout
  • Building Mobile Applications with Oracle Application Express
    • "This session provides an overview of the basics of jQuery mobile, explains how it is integrated with Oracle Application Express, and discusses how customers can quickly build mobile web applications and extend their existing Oracle Application Express applications with mobile capabilities."
    • David Peake, Oracle Corporation

RMOUG Training Days 2013 looks to have a plethora of database-related presentations as normal, but several of them are focused on MySQL as well as the Oracle database. I will likely try to attend as many of the mobile application development sessions as I can and look forward to presenting on generating charts for data using JavaFX and Groovy.

RMOUG Training Days 2013 will be held 11-13 February 2012 at the Colorado Convention Center in Denver, Colorado.

Thứ Bảy, 27 tháng 10, 2012

Design Patterns: Mogwai or Gremlins?

The 1994 book Design Patterns: Elements of Reusable Object-Oriented Software introduced many software developers to the concept of "a catalog of simple and succinct solutions to commonly occurring design problems" that nearly every object-oriented software developer knows of today as "design patterns." Like most technical concepts (whether real or hype or somewhere in between), "design patterns" seemed to go through the normal stages of acceptance, rising rapidly from new idea to the prevalent way of thinking. As is always the case, this rapid rise in popularity led to backlash as design patterns were overused, abused, and otherwise used inappropriately. Today, design patterns seem to have become accepted as a useful tool when used correctly, but are generally recognized as dangerous in the wrong hands.

I have generally avoided devoting an entire blog post to a discussion of the good, the bad, and the ugly of use of design patterns, but a fellow software developer recently made up an analogy related to his observations of the use and misuse of design patterns that motivated me to write this post. Andy pointed out that there seems to be a tendency among some software developers to take an innocent and well-intentioned design pattern and turn it to evil, like turning a Mogwai like Gizmo into a Gremlin. In this post, I look in more detail at why this is a particularly fitting movie-themed analogy for turning effective use of design patterns into misuse and abuse of design patterns.

The 1984 movie Gremlins begins with an inventor and father in Chinatown purchasing a Mogwai. Mr. Wing, the owner of the store, does not want to sell the Mogwai to the inventor/father because "with Mogwai comes much responsibility." However, Mr. Wing's grandson sneakily sells the Mogwai to the inventor/father while warning him of three important things to be aware of related to care of the Mogwai. These three things are:

  1. "Keep him out of the light. He hates bright light, especially sunlight. It will kill him."
  2. "Keep him away from water. Don't get him wet."
  3. "But the most important rule, the one you can never forget, no matter how much he cries or how much he begs never, never feed him after midnight."

The appropriate use of design patterns is not affected by bright light, water, or eating after midnight, but the effects of not taking care when applying design patterns can have effects similar to not taking care of Mogwai properly.

Rapidly Spawning Design Patterns

When Mogwai or Gremlins get wet, spontaneous reproduction of more Mogwai or Gremlins occurs. The effect can be very similar for developers with design patterns. It is easy for a developer new to design patterns (or a developer who is excited about a new design pattern that he or she has recently learned) to apply too many design patterns to the same problem. If design patterns are good, more of them must be better. It is similarly easily for developers to fall into the trap of applying the same favorite design pattern to too many different, diverse, and unrelated problems (Maslow's Hammer).

Design Patterns Turned Evil

The Mogwai turned into mischievous Gremlins if they ate after midnight. Similarly, design patterns can be more evil than good if used inappropriately. A misapplied design pattern can obfuscate the intention of the code. Several design patterns used together can obscure the intent as well. Design patterns that are meant to facilitate better design can and often do lead to worse design when not used carefully. What is a design pattern in one situation might be an anti-pattern in a different situation.

One of the benefits of cataloging the common design principles as patterns is the ability to aid communication among developers and designers. However, design patterns can have the exact opposite effect (hindering understanding and communication) when misapplied or overused. I have also seen the case when a developer insists he or she is using a particular design pattern when he or she is really using a totally different design pattern or even an anti-pattern. In such cases, use of "design pattern" terminology also confuses rather than clarifying.

Well-Intentioned But Ill-Conceived

These problems most commonly arise when developers apply the design patterns because they believe they should rather than because they truly understand their value in a particular situation. Rather than applying the same design pattern to every problem or shoe-horning a design pattern into a situation in which it does not fit well, the developer needs to understand the advantages and objectives of different design patterns, along with trade-offs associated with the design patterns, to make an informed decision about application of design patterns.

Effective Use of Design Patterns

It seems to me that the best use of design patterns occurs when a developer applies them naturally based on experience when need is observed rather than forcing their use. After all, when the Gang of Four compiled their book on design patterns, they were cataloging existing design patterns that developers had been using already. Indeed, some of the patterns covered in their book became so popular that they were incorporated into Java language syntax and into other newer languages. For example, Java provided the interface (which aids many of the design patterns covered in the original design patterns book) and newer languages such as Scala and Groovy have added their own pattern implementations.

Use of Design Patterns: Gizmo or Gremlin?

When used properly, design patterns are attractive and desirable just as Gizmo the Mogwai is a desirable pet. However, when used inappropriately or applied without appropriate care and consideration, design patterns can turn into Gremlins, wreaking havoc on one's code base and hindering the ability to understand and maintain one's design. Note that the design patterns themselves are not necessarily the problem, but rather the people entrusted with proper use of design patterns determine whether they maintain desirable like Gizmo or undesirable like the Gremlins.

Thứ Tư, 24 tháng 10, 2012

Java/NetBeans: Overridable Method Call in Constructor

I wrote about the NetBeans hint "Overridable Method Call in Constructor" in the blog post Seven Indispensable NetBeans Java Hints. In this post, I look at why having an overridable method called from a parent class's constructor is not a good idea.

The next class, Employee, is a contrived example of a class in which the extensible class's constructor calls an overridable method (setSalaryRange()).

Employee.java

package dustin.examples.overridable;

/**
* Simple employee class that is intended to be a parent of a specific type of
* employee class. The main purpose of this class is to demonstrate the
* insidious dangers associated with a constructor calling an overridable method.
*
* @author Dustin
*/
public class Employee
{
private String lastName;
private String firstName;
private JobTitle jobTitle;
protected int minWeeklySalary;
protected int maxWeeklySalary;

public enum JobTitle
{
CHIEF_EXECUTIVE_OFFICER("CEO"),
COMPUTER_SCIENTIST("Computer Scientist");

private String displayableTitle;

JobTitle(final String newDisplayableTitle)
{
this.displayableTitle = newDisplayableTitle;
}

public String getDisplayableTitle()
{
return this.displayableTitle;
}
}

public Employee(
final String newLastName, final String newFirstName, final JobTitle newJobTitle)
{
this.lastName = newLastName;
this.firstName = newFirstName;
this.jobTitle = newJobTitle;
setSalaryRange();
}

public void setSalaryRange()
{
this.minWeeklySalary = 5;
this.maxWeeklySalary = 10;
}

@Override
public String toString()
{
return this.firstName + " " + this.lastName + " with title '"
+ this.jobTitle.getDisplayableTitle()
+ "' and with a salary range of $" + this.minWeeklySalary + " to $"
+ this.maxWeeklySalary + ".";
}
}

NetBeans flags the existence of an overridable method called from a constructor as shown in the next screen snapshot (NetBeans 7.3 in this case):

To demonstrate a common problem associated with overridable methods called in a constructor, a child class is needed. That is shown next with the code listing for ComputerScientist, which extends Employee.

ComputerScientist.java

package dustin.examples.overridable;

/**
* Class representing a specific type of employee (computer scientist), but its
* real purpose is to demonstrate how overriding a method called in the parent
* class's constructor leads to undesired behavior.
*
* @author Dustin
*/
public class ComputerScientist extends Employee
{
private final int MIN_CS_WEEKLY_SALARY_IN_DOLLARS = 1000;
private static final int MAX_CS_WEEKLY_SALARY_IN_DOLLARS = 60000;

private int marketFactor = 1;

public ComputerScientist(
final String newLastName, final String newFirstName, final int newMarketFactor)
{
super(newLastName, newFirstName, JobTitle.COMPUTER_SCIENTIST);
this.marketFactor = newMarketFactor;
}

@Override
public void setSalaryRange()
{
this.minWeeklySalary = MIN_CS_WEEKLY_SALARY_IN_DOLLARS * this.marketFactor;
this.maxWeeklySalary = MAX_CS_WEEKLY_SALARY_IN_DOLLARS * this.marketFactor;
}
}

Finally, a simple test driving application is required to run this example. That is shown in the next simple executable class (Main.java).

Main.java

package dustin.examples.overridable;

import dustin.examples.overridable.Employee.JobTitle;
import static java.lang.System.out;

/**
* Simple driver of the demonstration of why calling an overridable method in
* the constructor of an extendible class is a bad idea.
*
* @author Dustin
*/
public class Main
{
public static void main(final String[] arguments)
{
final ComputerScientist cs = new ComputerScientist("Flintstone", "Fred", 5);
final Employee emp = new Employee("Rubble", "Barney", JobTitle.CHIEF_EXECUTIVE_OFFICER);

out.println(cs);
out.println(emp);
}
}

One might expect the Computer Scientist, Fred Flintstone, to earn a weekly salary in the range of $1,000 to $60,000. However, that is not what is shown when the simple main application is executed (command line output and NetBeans output shown).

The reason the Computer Scientist's salary range is not correct is that the parent class's (Employee's) constructor must first be run before the extending class (ComputerScientist) is completely instantiated. The child class does override the setSalaryRange() method, but this overridden implementation depends on an instance variable (marketFactor) that is not yet initialized in the child instance when the parent's constructor calls this child class's overridden method.

There are multiple ways to avoid this problem. Perhaps the best and easiest approaches are those recommended by the NetBeans hint that flagged this issue.

As the screen snapshot above shows, NetBeans provides four easy and effective ways to deal with the issue of an overridable method called from the constructor of a class. Because the issue involves an "overridable" method and a child class that is not fully instantiated when that overridable method is invoked during parent's constructor, an obvious tactic is to make the parent class final so that it cannot be extended. This obviously will only work for new classes that don't have classes extending them. I have found that Java developers often don't put a lot of consideration into making a class final or planning for it to be extensible, but this is an example of where such consideration is worthwhile.

When it is not practical to make the parent class final, NetBeans offers three other approaches for addressing the problem of an overridable method called from the parent class constructor. Even if the class cannot be final, that method can have the final modifier applied to it so that the constructor is no longer calling an "overridable" method. This allows a child class to still extend the parent class, but it cannot override that method and so won't have an implementation that depends on instance level variables that have not yet been initialized.

The other two ways shown that NetBeans uses to handle the issue of an overridable method being called from a constructor likewise focus on making that invoked method not overridable. In these other two cases, this is accomplished by making the invoked method static (class level rather than instance level) or by making the method private (but then not accessible at all to the child class).

In my particular example above, another way to fix the specific issue would have been to convert the instance-level marketFactor variable into a class-level (static) variable because that would move its initialization forward enough to be used in the invocation of the overridden method. The problem with this method is that there is still an overridable method invoked from the parent constructor and that method can have more than one state issue to worry about.

In general, I try to be very careful about a constructor calling methods as part of an instance's instantiation. I prefer to use a static factory that constructs an object and calls static methods to set that instance appropriately. It is always wise to be cautious with implementation inheritance and this issue of overridable methods called from a constructor is just another in the list of reasons why caution is warranted.

My example shown in this post is relatively simple and it is easy to figure out why the results were not as expected. In a much larger and more complicated example, it might be more difficult to find this and it can lead to pernicious bugs. NetBeans helps tremendously by warning about overridable methods called from constructors so that appropriate action can be taken. If a class is not extended and there are no plans to extend it, then making the class final is easy and appropriate. Otherwise, NetBeans presents other options for ensuring that all methods called from a constructor are not overridable.

Thứ Năm, 18 tháng 10, 2012

The Checker Framework

One of the interesting tools I learned about at JavaOne 2012 is The Checker Framework. One of the Checker Framework's web pages states that the Checker Framework "enhances Java’s type system to make it more powerful and useful," allowing software developers "to detect and prevent errors in their Java programs." One way to look at the Checker Framework is as an implementation of what JSR 305 ("Annotations for Software Defect Detection") might have been had it not fallen into the Dormant stage.

The intention of JSR 308 ("Annotations on Java Types") is to "extend the Java annotation syntax to permit annotations on any occurrence of a type." Once JSR 308 is approved and becomes part of the Java programming language, annotations will be allowed in places they are not currently allowed. Although JSR 308 is still in Early Draft Review 2 stage, Checker Framework allows a developer to include commented-out annotation code in places not currently allowed until made available by JSR 308. It is important to note here that JSR 308 only makes annotations more generally available (specifies more types of source code against which they can be applied) and does not specify any new annotations.

The Checker Framework requires Java SE 6 or later. The Checker Framework can be downloaded as a single ZIP file at http://types.cs.washington.edu/checker-framework/current/checkers.zip. The downloaded file can be unzipped to the directory checker-framework and then an environmental variable called CHECKERS can be set to point to that expanded directory's subdirectory "checkers." For example, if the checkers.zip is unzipped to C:\checker-framework, then the environmental variable CHECKERS should be set to C:\checker-framework\checkers.

One the Checker Framework checkers.zip has been downloaded, expanded, and pointed to by the CHECKERS environmental variable, it is time to try the Checker Framework out. The "long way" of running the Checker Framework is shown next and is used with the -version tag to verify that Checker Framework is applied:

Windows

java -Xbootclasspath/p:%CHECKERS%/binary/jsr308-all.jar -jar %CHECKERS%/binary/jsr308-all.jar -version
Linux

java -Xbootclasspath/p:$CHECKERS/binary/jsr308-all.jar -jar $CHECKERS/binary/jsr308-all.jar -version

The above should lead to output that looks something like that shown in the next screen snapshot.

The installed Checker Framework can now be applied to compiling code. The next code listing shows a simple class that specifies that a method argument should not be null via the checkers.nullness.quals.NonNull (@NonNull) annotation.

Example of Using Checker Framework's @NonNull

package dustin.examples;

import checkers.nullness.quals.NonNull;
import static java.lang.System.out;

public class CheckersDemo
{
public void printNonNullToString(@NonNull final Object object)
{
out.println(object.toString());
}

public static void main(final String[] arguments)
{
final CheckersDemo me = new CheckersDemo();
final String nullStr = null;
me.printNonNullToString(nullStr);
}
}

The above code listing shows a null being passed to a method with the argument annotated with @NonNull. NetBeans 7.3 flags this with the yellow squiggles and warning if hovered over. This is shown in the next screen snapshots.

Although NetBeans flags the null setting of a parameter marked with the @NonNull annotation, the compiler builds that code without complaint. This is where the Checker Framework comes in. Because it's a pain to type in the long command I showed previously, I either run the command shown above with a script or set up an alias as described in the Checker Framework Installation Instructions. In this case, I'll use an alias like this:

Setting Windows Command Line Alias for Java Checker

doskey javachecker=java -Xbootclasspath/p:%CHECKERS%\binary\jsr308-all.jar -jar %CHECKERS%\binary\jsr308-all.jar $*

The setting of this alias and running it with the -version flag is demonstrated in the next screen snapshot.

It is far easier to apply this approach with the alias set. This can be used to compile the class in question as shown next (command using my 'javachecker' alias and image showing result).


javachecker -d classes src\dustin\examples\*.java

The above command demonstrates that I am able to use normal javac options such as -d to specify the destination directory for compiled .class files and pass along the Java source files to be compiled as normal. The example also demonstrates that without specifying the checker processor to run as part of the compilation, the @NotNull additional typing is not enforced during compilation.

Before showing how to specify a processor to force the @NonNull to be be enforced during compilation, I want to quickly demonstrate that this compilation approach will still report standard compiler errors. Just for this example, I have renamed the "nullStr" variable passed to the method of interest on line 17 to "nullStry" so that it is a compiler error. The next two screen snapshots show this change (and NetBeans's reported compilation error) and how the Checker Framework compilation approach also reports the javac error.

Having shown that this approach to compilation compiles compilable code normally, reports compiler errors normally, and shows version appropriately, it is time to apply it to stronger type enforcement. I fix the compiler error in my code by removing the extra "y" that I had added. Then, I need to pass -processor checkers.nullness.NullnessChecker as an additional flag and argument to the compilation process. Note that there are other processors besides NullnessChecker, but I am using NullnessChecker here to enforce the @NonNull at compile time.

The following shows the command along with the output window demonstrating that command in action. Note that the compilation process is not allowed to complete and an error based on violation of the @NonNull typing is reported.


javachecker -processor checkers.nullness.NullnessChecker -d classes src\dustin\examples\*.java

This blog post has introduced the Checker Framework and shown how to quickly apply it to stronger type enforcement in Java source code. I only focused on one type of stronger typing here, but the Checker Framework supplies other built-in type checks and supports the option of writing custom type enforcement checks.

Thứ Ba, 9 tháng 10, 2012

NetBeans 7.3 Beta is More Than Easel: Hints and FXML Code Completion

NetBeans 7.3, which is now available in Beta, is already probably best known for its Project Easel features. However, in this post I look at some new features outside of Project Easel that I am happy to see now available in NetBeans.

New Hint: null Dereference

I'm a big fan of NetBeans's hints supports as proven by my blog posts on Seven Indispensable NetBeans Java Hints, Seven NetBeans Hints for Modernizing Java Code, Creating a NetBeans 7.1 Custom Hint, NetBeans 7.2 beta: Faster and More Helpful, and NetBeans 7.1's Unused Assignment and Dead Branch Hints. NetBeans 7.3 introduces another useful hint with the "null Dereference" hint.

The "null dereference" hint warns the developer when variables that might be null in certain cases are being dereferenced. This is shown in the next screen snapshot.

Before looking at another example of this hint in action, I want to first point out the new code editor Breadcrumbs feature. On the bottom of the above image, there are three greater-than inequality signs (> following the three respective labels "SevenThree", "processNullValue", and "if (valueStr != null). These correspond to places in the code where the highlighted variable is used (class it is used in, method it is used in, and conditional within method it is used in). Clicking on any of the greater-than signs expands possibilities of where that variable is next used. This is a handy feature for following code flow for a certain variable within static code.

Returning to the NetBeans "null deference hint," another way to demonstrate that new hint in code is via use of the NetBeans @org.netbeans.api.annotations.common.NullAllowed annotation. Applying this annotation to a parameter of the example method shown earlier leads to the hint being displayed. As a side note, this NetBeans annotation has the feel of the annotations discussed in relation to the Checker Framework in the JavaOne 2012 presentation "Build Your Own Type System for Fun and Profit."

New Suggestion: Invert If Hint

There are times when it is helpful to invert a conditional, such as to improve readability of the code. NetBeans 7.3 provides this with the "Invert If" suggestion. This is demonstrated in the folowing three screen snapshots.

JavaFX FXML Code Completion

One of the features I missed most when working with JavaFX in NetBeans was the inability to enjoy code completion when using FXML. FXML does not have a defined grammar that facilitates any generic XML parser helping with code completion, but fortunately NetBeans 7.3 adds FXML completion to its repertoire (addressing NetBeans Bug 204741).

The next screen snapshot shows the FXML raw editor code completion in action. In this case, an "import" tag is recommended. Note that because I have SceneBuilder installed with my installation of NetBeans, simply clicking on an FXML file always brings that file up in SceneBuilder. To edit this file in XML directly as shown in the next screen snapshot, I right-clicked on the file's name in the Project browser and then selected the "Edit" option.

This version of NetBeans is still in beta and this FXML code completion seems a little buggy. I kept seeing the following exception message when trying to edit an existing FXML file:

The following is a portion of the stack trace logged in the reference log file:


WARNING [org.netbeans.modules.editor.bracesmatching.MasterMatcher]: Origin offsets out of range, origin = [366, 371], caretOffset = 382, lookahead = 2, searching forward. Offending BracesMatcher: org.netbeans.modules.xml.text.bracematch.XMLBraceMatcher@1e084dc
SEVERE [org.openide.util.Exceptions]
java.lang.NullPointerException
at org.netbeans.modules.javafx2.editor.completion.impl.PropertyCompleter.complete(PropertyCompleter.java:191)
at org.netbeans.modules.javafx2.editor.FXMLCompletion2$Q$Task.run(FXMLCompletion2.java:207)
at org.netbeans.modules.parsing.impl.TaskProcessor.callUserTask(TaskProcessor.java:583)
at org.netbeans.modules.parsing.api.ParserManager$MimeTaskAction.run(ParserManager.java:377)
at org.netbeans.modules.parsing.api.ParserManager$MimeTaskAction.run(ParserManager.java:360)
at org.netbeans.modules.parsing.impl.TaskProcessor$2.call(TaskProcessor.java:200)
at org.netbeans.modules.parsing.impl.TaskProcessor$2.call(TaskProcessor.java:197)
at org.netbeans.modules.masterfs.filebasedfs.utils.FileChangedManager.priorityIO(FileChangedManager.java:176)
at org.netbeans.modules.masterfs.providers.ProvidedExtensions.priorityIO(ProvidedExtensions.java:360)
at org.netbeans.modules.parsing.impl.Utilities.runPriorityIO(Utilities.java:72)
at org.netbeans.modules.parsing.impl.TaskProcessor.runUserTask(TaskProcessor.java:197)
Caused: org.netbeans.modules.parsing.spi.ParseException
at org.netbeans.modules.parsing.impl.TaskProcessor.runUserTask(TaskProcessor.java:205)
at org.netbeans.modules.parsing.api.ParserManager.parse(ParserManager.java:331)
at org.netbeans.modules.javafx2.editor.FXMLCompletion2$Q$Task.run(FXMLCompletion2.java:182)
at org.netbeans.modules.parsing.impl.TaskProcessor.callUserTask(TaskProcessor.java:583)
at org.netbeans.modules.parsing.api.ParserManager$UserTaskAction.run(ParserManager.java:150)
at org.netbeans.modules.parsing.api.ParserManager$UserTaskAction.run(ParserManager.java:134)
at org.netbeans.modules.parsing.impl.TaskProcessor$2.call(TaskProcessor.java:200)
at org.netbeans.modules.parsing.impl.TaskProcessor$2.call(TaskProcessor.java:197)
at org.netbeans.modules.masterfs.filebasedfs.utils.FileChangedManager.priorityIO(FileChangedManager.java:176)
at org.netbeans.modules.masterfs.providers.ProvidedExtensions.priorityIO(ProvidedExtensions.java:360)
at org.netbeans.modules.parsing.impl.Utilities.runPriorityIO(Utilities.java:72)
at org.netbeans.modules.parsing.impl.TaskProcessor.runUserTask(TaskProcessor.java:197)
Caused: org.netbeans.modules.parsing.spi.ParseException
at org.netbeans.modules.parsing.impl.TaskProcessor.runUserTask(TaskProcessor.java:205)
at org.netbeans.modules.parsing.api.ParserManager.parse(ParserManager.java:102)
[catch] at org.netbeans.modules.javafx2.editor.FXMLCompletion2$Q.query(FXMLCompletion2.java:129)
at org.netbeans.spi.editor.completion.support.AsyncCompletionTask.run(AsyncCompletionTask.java:223)
at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:1454)
at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:2036)
SEVERE [org.openide.util.RequestProcessor]: Error in RequestProcessor org.netbeans.spi.editor.completion.support.AsyncCompletionTask
java.lang.AssertionError: AsyncCompletionTask: query=org.netbeans.modules.javafx2.editor.FXMLCompletion2$Q@163ab6b: query.query(): Result set not finished by resultSet.finish()
at org.netbeans.spi.editor.completion.support.AsyncCompletionTask.run(AsyncCompletionTask.java:225)
at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:1454)
at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:2036)
Caused: org.openide.util.RequestProcessor$FastItem: task failed due to

Although NetBeans 7.3 is still in beta, I am enjoying using it and finding most things to work as I'd expect. A downside of using beta versions is the inevitable problems, but these have not been too big of a deal so far. I look forward to the production release of NetBeans 7.3.

Thứ Bảy, 6 tháng 10, 2012

JavaOne 2012: Observations and Impressions

I am starting this particular blog post as I sit the the San Francisco International Airport waiting to board an airplane to head home after another satisfying but tiring JavaOne (2012) experience. It is difficult to write another blog post after having frantically written ~30 blog posts on the conference since the keynotes on last Sunday, but I want to record some of my observations and impressions of the conference while they're still relatively fresh. More than in previous years, I did embed some general observations (usually complaints) within posts on individual sessions.

This post is broken up into "the good," "the bad," and "the ugly" of JavaOne 2012. I want to emphasize that the conference overall was outstanding and I am appreciative of the opportunity to have attended. I hope the overall tone of my post reflects my overall highly positive feelings about this conference, but also presents a realistic portrait of the not-so-great aspects of the conference.

The Good

Overall Technical Content

There is a wide variety of things conference attendees look forward to in a conference. Many of us look forward to many of the same things in a conference. For me, the single most important attribute of a technical conference is its content. In that category, JavaOne 2012 was a success. There was actually too much good content to take it all in, but that's a welcome dilemma.

High Attention to Low-Level Details

I think Adam Bien made an important observation: even though it's nice to have community involvement in the conference, JavaOne presents a special opportunity to hear from the folks (mostly Oracle employees) working "in the trenches" on the latest Java APIs, specifications, and SDKs. Bien put it this way, "I mainly attended sessions delivered by Oracle engineers. 90% of this sessions were great with unique, deep technical content probably only deliverable by someone implementing the low level stuff. This is my personal motivation for attending JavaOne."

I've been to database-oriented conferences where many of the Oracle employees' presentations are heavy on marketing and slideware and low on technical detail. That's not the case at JavaOne where Oracle employees present the low-level details that Java developers want to hear.

Breadth and Scope of Technical Content

No matter in which dimension it is measured, JavaOne 2012 featured breadth and depth of content. Subjects in Java SE, Java EE, Java ME/embedded, web, JVM (alternate languages), and even some non-Java topics were available in nearly every session block. The keynotes (especially the Strategy Keynote and Technical Keynote) and select presentations that I attended provided roadmaps and vision for what lies ahead.

I enjoyed the breadth of "temporal usefulness" available in the presentations. I learned about things I like won't use anytime soon but are interesting and mind-expanding (Ceylon, JavaFX Embedded, Play Framework, Akka, Tiggzi), things that I'll definitely use in the intermediate future (Project Lambda, JSR 310 Date/Time API), things I'll use in the near future (Scala), and things I'll use almost as soon as I get home (JDK 7's jcmd, NetBeans Project Easel, Checker Framework). I was even able to learn several new tips and/or tricks for things for which I already had significant familiarity (Groovy, JavaFX, NetBeans's custom declarative language for refactoring/hints).

Attention to Community

I stated above that I agree with Adam Bien's assertion that one of the most valuable aspects of JavaOne is the access to people working directly on the future of Java. That being stated, I do appreciate Oracle making a real effort to reach out to the community. I posted during several presentations in which the speakers solicited feedback and ideas from the community and the audience. This was a nearly universal theme of any of the presentations related to anything open source. The JavaOne Community Keynote is the most obvious manifestation of JavaOne's commitment to community, but that theme was reiterated in numerous presentations.

The Host City

San Francisco is a great city to visit and offers lots to do for downtime and for people traveling with JavaOne participants who are not themselves attending JavaOne. Although I look forward to any opportunity I get to attend JavaOne, I think I look forward to the visit to San Francisco as much as the conference. It's definitely an interesting city to visit with great dining and other activities. The weather was pleasant and clear most of the time, though fog rolled in occasionally to remind us it is San Francisco and it was unusually hot in the early portion of the conference.

Oracle makes the presence of Oracle OpenWorld and JavaOne well-known throughout the city. Taxicabs feature signs for the respective conferences on their advertisements, there are signs all over the place, and some sections of the downtown near the conference venues (Moscone for Oracle OpenWorld and three Union Square hotels for JavaOne) for activities.

Extracurricular Activities

JavaOne provides numerous extracurricular activities beyond the technical content of the conference and beyond what the city provides. I didn't participate in many of these this year due to other commitments and activities, but the offerings are fairly impressive. The Oracle Appreciation Night, which featured Pearl Jam and Kings of Leon this year, is especially impressive. Although there are numerous disadvantages to JavaOne being the "little brother" held simultaneously with Oracle OpenWorld, some of these activities are available because of the bigger and better attended big brother conference being held simultaneously.

The Return of James Gosling

There was no denying that the "surprise" return of James Gosling to JavaOne (Community Keynote) left a big and very positive impression. The nostalgic factor (reminder of JavaOne's most glorious days) seemed to be as big as Gosling's presentation itself. I monitored a lot of the Twitter traffic during the week on "javaone" and no single Tweet or set of Tweets came anywhere close to being tweeted and re-treeted as often as mention of Gosling's return to JavaOne.

Increased Exposure to Tools

Master craftsmen in any industry are more successful with the correct tools. At JavaOne 2012, I became familiar with tools that I either had not been aware of previously or had not fully appreciated previously. These were either the subject of the presentations I saw or were used "incidentally" during projects and hallways discussions. These projects included JaCoCo Java Code Coverage Library (first read about in a Tweet), Checker Framework, the Oracle JDK 7 jcmd command-line tool, and NetBeans 7.3 Project Easel. I was also reminded that JDeveloper provides one of the better free UML tools, an important reminder now that NetBeans no longer supports UML (UML last supported in NetBeans 6.7).

Online JavaOne 2012 Coverage

Modern technology continues to make JavaOne more accessible to developer worldwide each year. Oracle made a lot of content available online early in the conference and individual members of the community also contributed significantly to the JavaOne coverage. Even some of the individual contributions were in part due to Oracle; I, for example, attended JavaOne 2012 on a blogger pass and was able to write posts like this one thanks to that complimentary pass. Between attending sessions, visiting some San Francisco sites, and writing my own blog posts, I've only been able to read a fraction of the other posts written about JavaOne 2012. I hope to catch up on those in coming weeks. I did try to watch Tweeted messages about the conference as it went along and was impressed with the quick coverage of important aspects of the conference.

Oracle has made "featured keynotes and highlights" available online (video). There have been several Oracle-originated blogs of interest including Oracle Outlines Roadmap for Java SE and JavaFX at JavaOne 2012, Virtual Collateral Rack (PDFs of sessions), Thursday Community Keynote: 'By the Community, For the Community', JavaOne 2012 Sunday Strategy Keynote, and The JavaOne 2012 Sunday Technical Keynote.

Individual JavaOne 2012 summaries include Jim Gough's Highlights From Java One 2012, Mark Stephens's 5 key things I learnt at Javaone2012, Yakov Fain's My Three Days at JavaOne 2012, and Trisha Gee's JavaOne: The Summary.

A Dose of Reality

The blogosphere tends to distort the reality of software development for a variety of reasons (dominated by "new" and "interesting" developments, for one). Attending conferences can be a good way to talk to others to get a better perspective on the reality of general software development. For example, at JavaOne 2012, there were several reminders that there is still significant software development that occurs on the desktop (it's not all web/mobile) and that the demise of UML has been overstated.

The Bad

These "bad" things are mostly accepted parts of the JavaOne experience. They are certainly outweighed by the good both in terms of number of "bad" or "good" things and in terms of importance of the things. In other words, there were more good things about JavaOne and the good things were more important to me than the bad things.

The Hotels Venue

The spreading of JavaOne over three Union Square hotels (Hilton, Parc 55, and Nikko) and the Masonic Auditorium would probably not be as big of a negative if JavaOne attendees were not aware of the presentations-friendly Moscone Center in the same city just blocks away. I am getting used to this venue and can navigate it better now than previously. I actually often enjoy the opportunity of going outside to move between buildings. However, I also found myself changing a couple selected presentations in the last couple of days because my original choice was in a particularly poor conference room area.

Poor Wifi

The Wifi at JavaOne simply cannot scale to the number of people wanting to use it via laptops, iPads, iPod Touch devices, Android tablets, and other personal devices. The Wifi was pretty good in the mornings before things got going and was outstanding on Thursday afternoon when a lot of people had already left.

The Food

Like the venues, the food is not completely awful; it's just not very good. It is sufficient for what is needed (providing nutrients and energy), but its lack of flavor stands in stark contrast to the excellent breakfasts and dinners I enjoyed again this year while in San Francisco.

Getting To and Leaving San Francisco

My flights into and out of San Francisco were both delayed due to fog in San Francisco and/or due to metering of traffic in the airport. In addition to this, we were told that the U.S. Navy's use on SFO for some of their Fleet Week exercises was the reason we sat on the runway for an extra twenty minutes. This is an example of where the good (being in San Francisco for the conference) outweighed the bad.

The Ugly

Inconsiderate and Intentionally Rude Misbehavior

Perhaps the ugliest part of JavaOne 2012 had little to do with the conference itself or its organizers, but was instead caused by a small portion of its attendees. It seemed that I repeatedly got behind the person trying to text and walk at the same time. These individuals slowed down traffic in the already congested halls as they walked more slowly and wandered in unpredictable directions and caused people to try to walk around them, causing additional issues. People tend not to drive and text as well as they might think and walking and texting is no different. The walking while texting may be less dangerous than driving while texting, but it's not without its dangers. There was one guy I was behind who was stopping intermittently while trying to eat and walk down the stairs because he was losing his lunch or snack. Continuing to try to do both made it so that neither was done well.

Other misbehavior that I observed were observed by others as well. These included unnecessary presentation hijacking, mobile phones ringing in sessions and some people even taking the call without leaving, people cutting in lines, and excessive entering and exiting of presentations at mid-point (most noticeably a problem when someone who sat in the first few rows made a show of his or her exit). The majority of attendees were well-behaved, but the small fraction of inconsiderate and even intentionally rude attendees was probably the ugliest part of JavaOne 2012. In defense of JavaOne, this "ugliness" seems to be more reflective of human behavior than of the conference.

Additional / Miscellaneous Observations

Trendy Topics

Some of the topics that seemed particular popular at this year's JavaOne included REST, HTML5, Project Nashorn, JDK8/Lambda, NetBeans, and Embedded/Raspberry Pi.

Convergence

A major theme of JavaOne 2012 was "convergence." This theme was explicitly identified in the keynotes and several presentations such as "Looking into the JVM Crystal Ball" (convergence of Oracle's JRockit and HotSpot JVMs), "Mastering Java Deployment" (convergence of Java SE and JavaFX), "JavaFX on Smart Embedded Devices" (convergence of JavaFX and JavaFX Embedded, representing convergence of editions of Java [EE, SE, ME]), "NetBeans.Next - The Roadmap Ahead" (sharing of features between NetBeans and JDeveloper), and "Diagnosing Your Application on the JVM" (convergence of VM tools between JRockit and HotSpot and converge of command-line tools into single new jcmd tool).

One of the manifestations of this convergence of versions of Java is the renaming of versions. It was interesting to hear multiple speakers refer to current JavaFX as JavaFX 2.2 and the "next" major version of JavaFX as JavaFX 8 (version that was to be called JavaFX 3). This version naming change is documented in the post JavaFX 2.2 is here, and JavaFX 8.0 is on its way! Similarly, Java ME is seeing a version naming change as well: Java ME 3.2 is the current version and Java ME 8 is the "next" major version.

JDK 7 Update 10: The Next 'Big' Minor Release?

I heard multiple Oracle presenters mention features that they are already using in JDK 7 Update 10. Given that most of us who are using JDK 7 are using JDK 7 Update 6 (and JDK 7 Update 7 is the current regular download), it sounds to me like JDK 7 Update 10 may be the next "minor" release of JDK 7 with significant new tools for things such as application diagnosis and application deployment.

The naming of JDK minor releases with odd numbers for Critical Patch Updates (CPUs) and even numbers for "limited update releases" was announced previously. JDK 7u10 Build b10 is available in Developer Preview.

"Java" Becoming Bigger Than Ever

One thing that is clearer to me than ever before after attending JavaOne 2012 is that "Java" has become big for any one person to get his or her hands around the whole thing. Even some of the most knowledgeable experts I know in the Java community were heard to say that they would need to ask someone else to answer a specific question out of their area of expertise. It's becoming increasingly difficult for any one person to thoroughly understand all aspects of Java (JVM, EE, SE, ME, etc.). When you throw in alternate languages and new frameworks and tools, one person simply cannot learn or understand all of it. It's great that we have so many choices, but it can be frustrating to see entire areas of "Java" that would be interesting to delve into, but simply require too much time and effort to give it those areas the desired degree of attention.

Overall

Overall, I think JavaOne 2012 was a success by most peoples' measures. It certainly was by mine. I'm not the only one who was sorry to see it end.

JavaOne 2013 will be held September 22–26, 2013, in San Francisco.