Renaming a Java package involves changing all package references in source and resource files and moving files to the directory layout of the new package. This article presents a method for repackaging of a project’s source files using Apache Ant.

Say you have been developing a prototype under a temporary package name and it is time to move it to production under a proper package name. It is not something you are likely to do very often and the consequences of breakage are high if you make a mistake. An IDE like Eclipse can take care of it for you, or you could use Perl (see at the bottom).

Or it can also be done with a couple of Ant tasks. (The fact that I looked to solve this with Ant first may be an indication that my developer’s instincts are out of whack. Follow at your peril.)

There are two steps to renaming a Java package:

  1. Change all in-file references from the old package to the new package.

  2. Move files from the old package directory to the new package directory.

Note
Step 0 is back everything up before making any changes.

Step 1. Change package references

We will use the <copy> task with the <replacestring> token filter and a <globmapper> to create new *.java.new files containing the package changes.

Consider the case of renaming the package gsl.dmex to net.gslsrc.dmex.

Rename package references
<copy todir="src">
    <fileset dir="src">
        <include name="**/*.java"/>
    </fileset>
    <globmapper from="*.java" to="*.java.new"/>
    <filterchain>
        <replacestring from="gsl.dmex" to="net.gslsrc.dmex"/>
    </filterchain>
</copy>

The <replacestring> "from" attribute is the old package name we want to replace; the "to" attribute is the new package name. This filter will replace all occurences of the old package, including the package declaration, import statements, fully-qualified class names and any uses of the package name in strings and Javadoc. Consequently, the old package name needs to be fairly distinct if we don’t want to find ourselves making incorrect substitutions.

If you want to substitute the package name in other file types as well (such as properties files), just add more <include> and associated <globmapper> elements to the fileset. Or include all files and use <globmapper from="*" to="\*.new"/>.

Step 2. Move files to new package directory

The simplest solution is to just move the *.java.new files over their corresponding *.java file and then manually move the directory or directories. This manual approach is necessary if the files are under version control and you wish to retain the change history in the new package.

If, as in the example above, there is only one directory to move, the Ant task is:

Move new files over old
<move todir="src" overwrite="true">
    <fileset dir="src">
        <include name="**/*.java.new"/>
    </fileset>
    <globmapper from="*.java.new" to="*.java"/>
</move>

Then you move the directory dmex from src/gsl to src/net/gslsrc.

If the directory contents are under version control, the move must be performed using the version control tool in order to retain the change history. For example, if using Mercurial, the commands are:

Move directory (Mercurial)
mkdir -p src/net/gslsrc
hg rename src/gsl/dmex src/net/gslsrc
hg commit -m "Repackaged to net.gslsrc"

If there is no version control and we want to do it all in one step using Ant’s <move> task, the following set of Ant tasks demonstrates the process:

Move new files to new directory
<mkdir dir="src/net/gslsrc/dmex"/>
<move todir="src/net/gslsrc/dmex">
    <fileset dir="src/gsl/dmex">
        <include name="**/*.java.new"/>
    </fileset>
    <globmapper from="*.java.new" to="*.java"/>
</move>
<delete dir="src/gsl"/>

This does not move any non-Java resources that might be in the source directory (properties files, etc). Considering that wholesale repackaging is such an occasional task, it is probably safer and simpler to move the directories manually.

Note
Or do it all with Perl…

The basic Bash & Perl one-liner to do the in-file package reference change is as follows:

find ./src -name "*.java" | xargs perl -i.bak -pe 's/gsl\.dmex/net.gslsrc.dmex/g'

Use -i instead of -i.bak to change the files in place. We still have to move the directories manually.