Custom JFileChooser

The default JFileChooser doesn’t prompt to overwrite files when saving. It also doesn’t automatically add an extension to the file if the user didn’t type one. I had to do a custom one to support these features for better usability.

The limitation of this specific implementation is it only supports one “image” extension, and it’s not i18n-ed. Customize it more for your own needs.

private class CustomFileChooser extends JFileChooser {
  private String extension;
  public CustomFileChooser(String extension) {
    super();
    this.extension = extension;
    addChoosableFileFilter(new FileNameExtensionFilter(
      String.format("%1$s Images (*.%1$s)", extension), extension));
  }

  @Override public File getSelectedFile() {
    File selectedFile = super.getSelectedFile();

    if (selectedFile != null) {
      String name = selectedFile.getName();
      if (!name.contains("."))
        selectedFile = new File(selectedFile.getParentFile(), 
          name + '.' + extension);
    }

    return selectedFile;
  }

  @Override public void approveSelection() {
    if (getDialogType() == SAVE_DIALOG) {
      File selectedFile = getSelectedFile();
      if ((selectedFile != null) && selectedFile.exists()) {
        int response = JOptionPane.showConfirmDialog(this,
          "The file " + selectedFile.getName() + 
          " already exists. Do you want to replace the existing file?",
          "Ovewrite file", JOptionPane.YES_NO_OPTION,
          JOptionPane.WARNING_MESSAGE);
        if (response != JOptionPane.YES_OPTION)
          return;
      }
    }

    super.approveSelection();
  }
}

Dump XML in Java

In this example, node is the XML node (which can be a document) you want to dump. You’ll see the XML in System.out. If you like the output in a String (e.g. for logging), use a StringWriter as the output.


Transformer serializer = TransformerFactory.newInstance().newTransformer();
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.transform(new DOMSource(node), new StreamResult(System.out));

Skype “Call to …, no answer”

I kept getting this error when I tried to call my conference meeting center with Skype. At first I thought it was just not getting through, when I realize it didn’t work with echo123 too. The error message was:

Call to skype test call, no answer

Google tells me the problem was due to my audio settings. In my case the speaker was pointing to the wrong device, and the call went through after changing it. You can get to your audio settings by going to Tools > Options > General > Audio Settings.

The error message should have provided more information e.g. “Call to …, no answer. Please check your audio settings.”.

code stench

Avoid referencing resources by absolute paths as they are likely to end up in jars. Depend on a delegated strategy which uses Class.getResourceAsStream().

Avoid using i18n for non language purposes. It should be used solely for text shown on the screen. Code properties should be kept in property files. And vice versa.

Local WordPress shows empty page

I thought it’ll be easy to pull my WP site down to local and make some theme changes. Just install XAMPPLite, export/import my database, backup the site files and go.

It kept showing an empty site, with no errors reported in the log, so I ended up tracing through the code to find out the what was not working. Below were the other changes I had to make.

The siteurl and home attributes in the wp_options table of the database had to be updated. I opted to change it in wp-config.ini using the following 2 lines:

define('WP_HOME', 'http://localhost/wp' );
define('WP_SITEURL', 'http://localhost/wp');

I realize some PHP was not parsed when the shorter tag is used. This option needs to be explicitly enabled in php.ini.

short_open_tag = On

The OpenID plugin requires the GMP extension, which needs to be enabled in php.ini. The comments on the PHP documentation site helped.

extension=php_gmp.dll

Eclipse Remote Debugging

Eclipse has a powerful debugger, which allow breakpoints, code stepping, variable inspection, expressions, hot code replacement etc. Therefore any application that is run from Eclipse can be debugged.

Even if it is a built and released application running on a separate machine, it can also be debugged remotely from an Eclipse IDE. As this option is built into the JVM, it can work on any kind of Java application; from simple Java applications to web applications to complex Eclipse RCP plugins.

Just add these JVM options to the command that starts the application/web server.

-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=1234

When the application is started, it will wait for a debugger to be attached.

From Eclipse, Open the Debug dialog, and create a new “Remote Java Application”. Set the host and port in the “Connection Properties” section to the waiting application. Click “Debug” and watch it go! Set the breakpoints and it can be debugged as if it was locally run.

Small Tips

Don’t catch NullPointerException. Check for it.

String concatenation to create a hash key or to store multiple values is easy but fragile. Prefer an object key with a proper hashcode. Prefer an object to store multiple values. Otherwise use a standard such as CSV instead of using your own “dash-separated values”. Use a library to handle escaping problems (a name may also contain a comma).

If you do need to concat Strings, use StringBuilder/StringBuffer. Know the difference between the two.

EclEmma

Emma is a coverage tool.

EclEmma is an Eclipse plugin that generates Emma coverage. It installs via an update site. It executes via the Run Dialog, so any existing run configuration can be easily “coveraged” (including RCP JUnit tests). An additional coverage tab in the Run Dialog allows you to select which packages will be instrumented.

Results are shown graphically in an Eclipse view, grouped by packages. The view allows you to drill into classes and into methods, showing the coverage of each level along the way. Double-clicking in the view brings up the source code, which is color coded to represent which lines were covered.

This is very useful during the personal development process, as individuals can selectively run unit tests to check for coverage in the related modules they are working with. The results are interactive and allows the developer to quickly see which areas require coverage improvement. This is much easier than waiting and going through a Continuous Integration report later (if any). In fact, I have successfully employed this approach to identify areas lacking coverage, and discovering bugs after having test cases for those areas identified.