Tuesday, October 22, 2013

Updating Source Code to Java 7

I had this vague memory that NetBeans had a way to upgrade source code to Java 7, which seemed like a good thing to do. But when I searched on the web I couldn't find much. I did find stuff about the IDE giving hints and fixes individually in the IDE but nothing about mass changes. (Which is partly what prompted me to write this.) I also looked for a way to do it with Eclipse but didn't find anything.

So I downloaded the latest NetBeans (7.4) and hunted through the menus. I found Refactor > Inspect and Transform which has a Configuration choice for Convert to JDK 7.

TIP: Set your tab and formatting (e.g. switches) preferences before you run Inspect and Transform. It didn't seem to work correctly when I changed the preferences while Inspect and Transform was open.

It found the following applicable changes in my code:

  • Use diamond inference
  • Convert to switch over strings
  • Convert to try-with-resources
  • Replace with multicatch
  • Replace with multicatch catching specific exceptions

The majority were diamond inference. There would have been even more, but I already used Guava's helpers such as Lists.newArrayList which avoid repeating the generic types.

Convert to try-with-resources didn't merge surrounding try-catch's but there were only a few of these so it was easy to fix them manually.

I wasn't too sure about the last item - replacing catching general exceptions with catching multiple specific exceptions. It seemed like it wouldn't catch everything it did before so I didn't accept those changes. (unchecked them)

But when I clicked on Do Refactoring I got a little "Refactoring" window that was blank. I assumed it was working and left it for a while. But it never went away, and when I tried to close it I couldn't. So I exited out of NetBeans (with no problems) and tried it again. This time nothing happened (except the Inspect and Transform window closed). I thought maybe it was finished but nothing had changed. I ran it again and got only a few of the issues and Do Refactoring worked (on those few). Next time I ran it, I got the long list again. I finally noticed the error marker in the bottom right. I submitted the error and it appears to be a known bug :-(

I ended up doing one package at a time and that seemed to work fine.

Monday, October 21, 2013

Fixing a Suneido Design Problem

In Suneido object.Delete(key) returns false if the member isn't found, otherwise it returns the object.

Several times we've had bugs resulting from doing things like:

object.Delete(key).Add(...)

which works as expected, except when key isn't found and Delete returns false.

It's likely the worst of possible designs. It would have been better if it returned nothing, or true/false, or my favorite - always the object.

I've been aware of this problem for quite a while but I was hesitant to change it because I was afraid I'd break existing code. I finally decided to go through our code and see if it would actually break much.

There were about 800 uses of Delete.

By far the majority ignored the return value.

I didn't find a single place where we made use of the false return value.

I did find a number of uses which assumed that it always returned the object - i.e. potential bugs.

Other than being tedious, the worst part was seeing all the ugly code. I wonder if it's possible to write code that doesn't make you cringe when you come back to it later.

I found quite a few places where we were doing multiple deletes so while I was at it, I changed Delete to handle multiple arguments.

This is a small change, but I think it's just as important to get the details right as it is to work on the big picture.

Monday, October 14, 2013

More Hamcrest Hassles

The Hamcrest library is very useful. So useful that other useful libraries, like JUnit, include pieces of it. And then JUnit is so useful that Eclipse includes its own copy.

Not surprisingly, having multiple copies, of different versions, of different subsets, with some signed and some not, results in numerous problems. For accounts of my own experiences see: Upgrading to Eclipse Kepler 4.3, Eclipse Hamcrest Runaround, and I Give Up. Searching the web will find lots of other people with similar problems.

Once again, I had thought I had solved this by not using Eclipse's copy of JUnit. Everything has appeared to be working fine for months.

Until I was adding a test today. In good TDD style, I started by adding the test before making the change. It failed, as expected, but not with the error message I expected. I got:

java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch

I thought maybe it was because I was using org.junit.Assert.assertThat instead of org.hamcrest.MatcherAssert.assertThat - but switching it didn't fix anything.

I also noticed that Eclipse was marking org.hamcrest.CoreMatchers.is as deprecated. Maybe it should be org.hamcrest.Matchers.is? Nope, still deprecated. I eventually found a comment on Stack Overflow that there are three overloads of "is" and it's only the class one that is deprecated, not the one I'm using. So I guess I just live with that warning :-(

Another comment on Stack Overflow mentioned that Mockito also included it's own version of Hamcrest. Hmmm... I don't think I was aware of that before.

One of the suggested solutions to this problem is to rearrange the order of the jar files on the class path. I had tried that previously without any success. But I was only moving JUnit and Hamcrest, since I wasn't aware that Mockito was also involved.

I find the Eclipse project properties Java Build Path a little confusing. There's a Libraries tab that lists all the jars alphabetically and you can't change the order. And then there's an Order and Export tab where you can change the order. I'm not sure why two tabs are needed. There's also a Referenced Libraries in the Package Explorer that does show the actual order, but doesn't let you change it.

I moved Mockito down in the list so it was below Hamcrest (JUnit was already below) and sure enough, that solved the problem.

Except now I had a different error in another test. That one turned out to be because I was using "is" with a class. Maybe it's deprecated in one of the versions/copies of Hamcrest but removed in the version of Hamcrest I'm explicitly including? Luckily this was simple to fix by just changing it to instanceOf.

It looks like you can download separate jars for Mockito which would let you leave out it's copy of Hamcrest. Except that it appears to be using a different version of Hamcrest (1.1) from the one I'm using (1.3). I have no idea if that would cause problems, but since it's currently not broken, I don't think I'll try to fix it!

Probably someone out there will tell me that I should be using Maven to manage dependencies, and maybe I should. But I'm not so sure that would eliminate these problems. I see several comments on the web about the same issues when using Maven.

Sunday, October 13, 2013

jSuneido GUI


What's special about this screenshot of the IDE isn't what's visible.

It's that this is running on jSuneido! (the Java implementation of Suneido).

Up till now jSuneido has only been the server side. The only "UI" it had was a command line REPL.

But in the long run, I'd rather not support two implementations of Suneido. It would be nice if we could just use jSuneido since it's a better implementation.

Suneido's user interface is Win32 based and implemented with the DLL interface. None of the UI is built into the exe, it's all Suneido code in stdlib. (Other than a few support functions.)

Ideally, we'd switch to a portable GUI, but that's a huge job and would likely mean a bunch of changes to our application code.

So we decided to see if we could implement a Windows DLL interface in jSuneido and get Suneido's existing GUI to run on it.

One of Suneido's early programmers , Victor Schappert, returned to us and worked on this project. Thanks Victor!

As you can see, it's far enough along to run most of the IDE. but we still have a few things left to do like the COM interface and SuneidoAPP interface to the IE browser component.

As usual, the code is in version control on SourceForge. The JSDI project in Mercurial (Hg) contains a support dll for jSuneido (written in C++) that jSuneido talks to via JNI. A pre-built version of jsdi.dll is included in the jSuneido project.