New Adventures in Software by Dan Dyer

About 8 years ago I made the decision to use TestNG for unit testing a Java project at work because it offered a much neater approach to the problem than JUnit 3.x. The only problem was that the HTML reports it generated were ugly. So I quickly hacked together a plug-in using Apache Velocity that would present the information in a way that I preferred and called it ReportNG. There was nothing elegant about the solution and the reports were functional but not particularly attractive, but it scratched an itch. It seemed to be an itch that irritated a lot of other developers because it attracted probably more users than any other, better written code that I’ve open-sourced before or since. I have made no substantial changes to it in years but there are still people using it.

I don’t do nearly as much Java as I used to and where I do I am either not using ReportNG or it is sufficient as it is. For these reasons, and because it ought to be replaced by something better (which probably already exists somewhere – I haven’t looked), I wanted to make it explicit to people still relying on it that there will be no further updates to ReportNG. You have three options:

Continue using version 1.1.4 and accept that it will never get any better.

Fork it on GitHub and make whatever changes you like. The Apache licence is permissive enough to allow most things.

It’s been a couple of years since the last release of ReportNG, my cobbled together alternative reporting plug-in for TestNG. In the time since I’ve done nothing but a few users have submitted useful improvements. So, after some prompting, I’ve released version 1.1.4 (download zip, tgz).

Thanks to Kayla Nimis, criccio, Arcadie, and Nalin Makar the new version has the following improvements:

The report now shows the reason for skipping a test.

You can specify the org.uncommons.reportng.failures-only property to generate a more minimal report.

ReportNG will now create any missing parent directories of the report directory rather than failing if they are absent.

A post with code in it. Because it’s been a long time since the last one.

If you work with ListViews in Android, as all Android developers will do at some point, you may notice that if you set your list items to be non-selectable the dividers that are drawn between each cell disappear. In the Holo Light theme you would normally get a thin light grey dividing line between cells. Depending on how you’ve implemented your adapter, you may find that these dividers become white/transparent when the cells are not selectable. According to Android framework engineer Romain Guy, this is the intended behaviour.

As Haythem Souissi points out in this Stack Overflow answer, you can work around this by ensuring that the areAllItemsEnabled method returns true, even though all items are not enabled (maybe none of them are). The isEnabled method will take care of actually disabling the cells and the dividers will be drawn between each of them.

All very straightforward so far but it all goes wrong again when you try to add a non-selectable header view to the list. The way that ListView deals with headers and footers is that it creates its own adapter to wrap/decorate yours and insert the header/footer views in the appropriate places. This is fine but it’s not delegating the areAllItemsEnabled method, so our above fix no longer works.

Fortunately, and unusually for Android, everything we need to resolve this issue is part of the public API. The adapter decorator class is android.widget.HeaderViewListAdapter. We just need to create our own instance, wrapping our own adapter, and override areAllItemsEnabled as above. There’s a slight complication in that we have to wrap the header view in an instance of ListView.FixedViewInfo and this is a non-static inner class of ListView, but we can reach into our bag of obscure Java tricks to create an instance from outside the enclosing class.

// I assume you know how get a reference to the ListView and create your own adapter.ListView listView = (ListView) view.findViewById(android.R.id.list);
CustomAdapter adapter = new CustomAdapter(context, listOfItems);// You can create any view you like for the header.
TextView listHeader = (TextView) inflater.inflate(R.layout.list_header, null);
listHeader.setText("My Header Text");// This is how you create an instance of the non-static nested class, providing// it with a reference to an instance of the containing class (ListView).ListView.FixedViewInfo headerInfo = listView.new FixedViewInfo();
headerInfo.view = listHeader;
headerInfo.isSelectable = false;// HeaderViewListAdapter insists on concrete ArrayLists.ArrayList headers = newArrayList(1);
headerInfoList.add(headerInfo);ArrayList footers = newArrayList(0);
HeaderViewListAdapter wrapper = new HeaderViewListAdapter(headers, footers, adapter){
@Overridepublicboolean areAllItemsEnabled(){returntrue;}};
listView.setAdapter(wrapper);

It’s five years ago this week that I first released Uncommons Maths as a standalone project spun-off from an early version of the Watchmaker Framework. Uncommons Maths is a Java library that provides, among other things, various classes for working with random numbers, probability distributions and combinatorics. There hasn’t been a release in over two years so today I’ve published a maintenance release, version 1.2.3, on GitHub.

There are two main changes in this version. Firstly, thanks to a contribution from Dave LeBlanc, the Uncommons Maths JAR file is now a valid OSGi bundle. Secondly, I found and fixed a pretty fundamental bug in the convertBytesToLong method of BinaryUtils. The fact this bug went undetected for so long suggests that nobody is actually using this method. It also reinforces that full test coverage is worthless if you don’t select your test inputs carefully.

Finally, the documentation has been updated to make it clear that none of the RNG implementations support the seeding mechanism inherited from the java.util.Random base class. The reason for this is that the setSeed method only takes a single long argument. This means it’s not possible to provide more than 64 bits of entropy, which is insufficient for most of the Uncommons Maths RNGs. In practice calling this method on an RNG instance has no effect. Ideally the method would be over-ridden to throw UnsupportedOperationException but to do so is not possible because setSeed is invoked internally by the java.util.Random constructors. If it threw an exception it would not be possible to create an instance of an object that inherits from java.util.Random.

Those of you who will be attending JavaOne this year (2nd – 6th October in San Francisco) might be interested in Matthew Ring’s BoF session on genetic algorithms in Java. Matthew tells me that he will be presenting his software that uses my Watchmaker Framework for Evolutionary Computation as part of his session Using Java and Genetic Algorithms to Beat the Market. Here’s the abstract:

Predicting the future is dangerous business. Is Java up to the task? This session discusses and demonstrates a fun and understandable stock-picking system built with Java 6 and various Java-based open source projects. The discussion ranges from machine learning concepts (specifically genetic algorithms) and core Java development with specific code examples to trading system back-testing. Attendees are sure to come away excited, ready to tackle that next hard big-money problem, and confident that Java is a capable partner.

I’ve just pushed a new version of ReportNG (an HTML reporting plug-in for TestNG) to GitHub. This is a minor enhancement release that incorporates a few patches submitted by users. Thanks to Jeff Weiss, ReportNG should now load custom stylesheets from the classpath as well as the file system and it should have less broken dependencies if you are using it with Maven. By default ReportNG will now also not generate the annoying Velocity log file (if you want the log file you can re-enable it via a system property). This change is thanks to C. Baldwin.

I’m not a Maven user, so I’ve never made any effort to use ReportNG from Maven. Maven users were left to figure it out for themselves. Well, Marcin Zajączkowski has figured it out for himself and has documented what’s involved.

Yesterday I moved Uncommons Maths (random number generators, probability distributions, combinatorics and a few other numbery type things) from Java.net to GitHub. My other projects have been on GitHub for a while but this one hadn’t been moved mostly because it hasn’t seen any recent activity. I also took this opportunity to push out another release incorporating a couple minor fixes (serialisation and thread safety issues) that have been sitting in the Subversion repository for almost a year.

Unfortunately, the LVL is pretty much the only option for protecting apps sold via the Android Market (other app stores have their own protection mechanisms). The choice for Android developers is mediocre protection or no protection at all (Google apparently intends to withdraw its previous copy protection mechanism). You can thwart the most casual Android pirates and make things harder for the determined but that’s about as good as it gets.

Obfuscating LVL-protected Apps with Proguard

Assuming that you choose to add the LVL to your app, you’ll no doubt want to follow Google’s advice and obfuscate your code, probably using Proguard. If you do, you might hit a couple of problems that prevent the LVL from working properly.

I added the LVL source to my application and built it as a single entity but it is also possible to incorporate the LVL as a library project.

Disable Aggressive Overloading

The first problem I encountered was a limitation in the Dalvik VM. Unlike the JVM, it does not (did not?) permit static fields of different types to have the same name. In normal Java development this situation never arises but Proguard has an option to aggressively overload names to make decompilation more difficult. For Android development this option should not be used otherwise you will get VerifyErrors.

Avoid Renaming the ILicensingService Intent

The checkAccess method of the LVL’s LicenseChecker class binds to the licensing service as follows:

The problem with calling ILicensingService.class.getName() is that, after obfuscation, the class has a different name and therefore the wrong intent is created. This will show up in the log as an error with the message “Could not bind to service” and the licence check will always fail.

You could fix this by modifying the Proguard configuration to avoid renaming the ILicensingService interface or, even more straightforwardly, you could just modify the code in LicenseChecker and hard-code the appropriate action:

There are only two small changes in this release. The first is a fix for an avoidable NullPointerException if the target directory does not exist. The second updates ReportNG to work with this change in TestNG 5.13.1. Thanks to Nalin for providing a patch for this issue.