ant vs java – using ** to match directories

Suppose I have the following files:
/MyFiles/dir/a.txt
/MyFiles/dir/child/b.txt

In Ant, this is how you write code to output all text files in any subdirectory of a “dir” directory.

<fileset id="jb" dir="/MyFiles">
  <include name="**/dir/**/*.txt" />
</fileset>

<pathconvert pathsep="${line.separator}" property="out" refid="jb"/>
<echo>${out}</echo>

In Java, the equivalent is

public class MyPathMatcher extends SimpleFileVisitor<Path> {
  private PathMatcher matcher =
     FileSystems.getDefault().getPathMatcher( "glob:**/dir/**.txt");

 @Override
 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
   if (matcher.matches(file)) {
     System.out.println("File " + file);
   }
   return FileVisitResult.CONTINUE;
 }

  public static void main(String[] args) throws Exception {
    MyPathMatcher dirs = new MyPathMatcher();
    Files.walkFileTree(Paths.get("/MyFiles"), dirs);
   }
}

The Java documentation says “Two asterisks, **, works like * but crosses directory boundaries. This syntax is generally used for matching complete paths”. Whereas in the Ant documentation, “When ** is used as the name of a directory in the pattern, it matches zero or more directories.”

The Ant approach probably feels more natural to me because I’ve been using it longer. But the Java approach seems more logical because it doesn’t have the extra slash that doesn’t actually get matched.

java tools for dependencies and build (ant vs maven)

A student at the robotics program I mentor emailed me the following question.  Since it isn’t specific to him, I decided to answer in a blog post.

As a developer, what tools does Java have to help me manage things like dependencies and building the project? For example, Python has pip and Ruby has gem+bundler, for managing dependencies.

Can you extol the virtues of Maven and ant? Why should I use one over the other? My research leads me to believe Maven supersedes ant. Are there any other alternatives? And if you prefer one, what makes it valuable to you?

Ant and Maven are the most common build tools in the Java world.  I’ve used both.  Gradle is a third that I’ve heard a lot about.  I haven’t used Gradle, but it looks cool.  The benefits of Maven, but the Groovy language.  Maven and Gradle are actually  both a build and dependency tool.  Ant is just a build tool.  You can use Ant without any dependency management tool/repository.  Or you can use Artifactory or Ivy with Ant.

Maven came after Ant, but didn’t supersede Ant.  Both have their purposes.   We use Ant at CodeRanch to:

  1. Build the forum software 
  2. Generate the book promotion documents every week

Ant serves these purposes very well to this day.  The latest release of Ant was in the past 6 months; it is far from a dead project.  The strengths of Ant include:

  1. Ant works better when internet availability is unpredictable or very slow.   With Ant, you have complete control over when and which jars are downloaded.  (To be fair, you can work with Maven in offline mode once you have the jars locally.  But there are a lot more dependencies and therefore more to download.)
  2. Ant works better when you don’t want to do things “the Maven way.”  Maven uses convention over configuration.  Which is great when you can use those conventions.  They save a lot of time.  (And most of those conventions are fine).  It so happens at CodeRanch, we don’t deploy a full war.  We deploy a zip file containing a subset of the project files.  Again because of that internet thing.  We don’t all have the ability to upload a full war without the internet connection timing out.  This could be done in Maven, but it would be odd.  And I think it would be confusing to use Maven and ignore conventions.
  3. Ant gives you complete control.

Maven has a different set of advantages

  1. It is much faster to get started with a new project.  You can use an “archetype” to get a project template.
  2. You don’t have to think about dependencies.  If you are using X and it depends on Y, both get pulled.  The dependency management is excellent.
  3. Convention means you don’t have to set up much in your build configuration.

I think Maven is going to be better for the project I was asked about here.  You want dependency management which is something Maven excels at.  And you have a greenfield project which means there is no reason you can’t use Maven’s conventions.   Also, many other tools easily integrate with Maven (or Ant) like Findbugs which will be helpful.

upgrading to mavericks – problems including broke eclipse/ant java for jmockit – and how to fix

I didn’t upgrade to Mavericks right away because I was getting FIOS.  If there were internet problems, I wanted to know they were Verizon’s fault and not be in a position where they could claim it was my computer’s problem.  I’ve had Mavericks long enough that I can write about the experience.

The problems describe here:

  • git
  • Eclipse/Java/Ant/JMockIt
  • OpenOffice crashing

How long it took

Not counting the download, the install took 2 hours.  Much of which was Apple saying there were “17 minutes” left.  I left it alone and it didn’t finish though.  I’ve seen reports of significantly faster installs though.

Problem #1 – git

The first problem I ran into was the error message The “git” command requires the command line developer tools.  Not a big deal.  It was a two minute install.  I was just surprised as I was expecting what was installed before the upgrade to  be installed after.

Problem #2 – Java and Eclipse

And now for the meat of this.  Being able to develop again in Eclipse was by no means seemless.

Error: Ant can’t find Java

Exact message: Specified VM install not found: type MacOS X VM, name Java SE 6 (MacOS X Default)

Solution – for each Ant build:

  • Run > External Tools Configuration
  • Run in same JRE as the workspace

Error: JUnit tests don’t run in Eclipse view

When running from Eclipse, I got the stack trace:


java.lang.IllegalStateException: Unable to load Java agent; please add lib/tools.jar from your JDK to the classpath

at mockit.internal.startup.JDK6AgentLoader.getVirtualMachineImplementationFromEmbeddedOnes(JDK6AgentLoader.java:102)

at mockit.internal.startup.JDK6AgentLoader.loadAgent(JDK6AgentLoader.java:74)

at mockit.internal.startup.AgentInitialization.initializeAccordingToJDKVersion(AgentInitialization.java:41)

at mockit.internal.startup.Startup.initializeIfNeeded(Startup.java:271)

at org.junit.runner.Runner.<clinit>(Runner.java:25)

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)

at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)

at java.lang.reflect.Constructor.newInstance(Constructor.java:525)

at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:35)

at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:24)

at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)

at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:29)

at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)

at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:24)

at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.<init>(JUnit4TestReference.java:33)

at org.eclipse.jdt.internal.junit4.runner.JUnit4TestClassReference.<init>(JUnit4TestClassReference.java:25)

at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:48)

at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:38)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:452)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

java.lang.NoClassDefFoundError: org.junit.runner.Runner

at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)

at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:24)

at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.<init>(JUnit4TestReference.java:33)

at org.eclipse.jdt.internal.junit4.runner.JUnit4TestClassReference.<init>(JUnit4TestClassReference.java:25)

at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:48)

at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:38)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:452)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)

at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Solution:

First I tried switching creating a new installed JVM of type MacOS X JVM.  That didn’t help directly.  I left it like that since I didn’t want to muck around with my original configuration.  Then I added tools.jar to the installed JRE.

  1. Eclipse > Preferences
  2. Java > Installed JREs
  3. Click target JRE
  4. Edit
  5. Add external jars
  6. Add  /Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home/lib/tools.jar

Warning: The first time I tried this procedure, Eclipse hung.  I had it to kill it.  When I opened my workspace, I saw “unable to load plugin x” in every single view.  I used Time Machine to restore to before I tried changing the JREs and then re-did that change.  The second time it was successful.

I could have added tools.jar to my classpath for the project instead.  I choose not to because I was hoping updating it in the JVM install would solve the Ant problem (described below) as well.  It didn’t.  I also didn’t want to change the project .classpath as that is shared in Subversion and I didn’t want to make a change that affects others.

This whole exercise felt like a hack until I read the JMockIt instructions.  This leads me to believe I was running with a different JDK before the Mavericks upgrade.

If you are developing on a JDK of version 1.6 or newer on Mac OS X, add <jdkDir>/lib/tools.jar to the classpath, where <jdkDir> is the home directory for your local JDK 1.6 installation.

Error: JUnit tests don’t run from Ant

When running from Ant, every test failed with:

Caused an ERROR</span>
<pre>
null

java.lang.reflect.InvocationTargetException

at java.lang.reflect.Constructor.newInstance(Constructor.java:525)

What I learned:

  • I tried setting JAVA_HOME at the command line to no avail.  I confirmed javac is on the path. (/usr/bin/javac); it was.
  • I tried adding tools.jar to the classpath in launch configuration in Eclipse for running Ant.
  • If I change to fork=”no” in the <junit> task in the Ant script, most of the tests pass.  (Some of them require the JVM be forked which is why it was in the first place.) Showing the problem is when a new JVM is created, it doesn’t inherit the tools.jar from the previous step.
  • If I hard code the classpath entry for tools.jar in the Ant build file, all of the tests pass.

Solution:

If you need to fork the JVM, add the following insider you <junit> task.

<classpath location="/Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home/lib/tools222.jar" />

I don’t like this solution.  I also didn’t like the hack for Eclipse so my unease is pretty uniform here.  Luckily Ant doesn’t choke if you include a file (or disk or filesystem) in the classpath that doesn’t exist.  Which means this won’t hurt others working on the same project.

Problem #3 – Open Office crashes when opening a document

The solution was to upgrade from Open Office 3.3.0 to the latest (4)

My favorite new feature

It’s a minor one, but I like the feature to synchronization of “Read Later” between my Mac and iPad.  (I haven’t tried it yet so it may not be that nice in practice.)  Most of the new features are things I don’t need.