JasperReports nuances

JasperReports is an engine that can allow you to generate reports in HTML, PDF, or many other formats. When I say reports here, I mean reports that are essentially pieces of paper that convey something meant to be reviewed by someone. Invoices, Statements, Forecasts, or anything that needs to be dynamically presented on paper for review is a good candidate.

One positive about JasperReports is that it’s all Java based, and plugs in well into your Java ecosystem. On the other hand, if you’re just now looking for a reporting engine, I may try to dissuade you from using JasperReports. It seems to have become outdated. There have been few updates in the last couple years (if any), and community support seems to be waning (you only find old blog posts, forums threads, etc). And documentation is also a bit lacking. But if you’re already using JasperReports, this post is for you.

It took me a while to figure how to get JasperReports to do certain things, because again the documentation is weak. So I figured I’d share these insights just in case someone else is struggling with the same thing.

  • Setting the foreground/background color of a field programatically
    This was not obvious at all. Sometimes you need to set the background color or text color of a field dynamically, based on some data value. Let’s say a data field literally has the color in it: for example $F{BACKCOLOR}, and you want to set the background color of a field to the value contained in $F{BACKCOLOR} (say “#0000FF”). In order to accomplish this, you’ll need to edit the properties of the TextField, and set this property:

    net.sf.jasperreports.style.backcolor

    …to this value:

    $F{BACKCOLOR}

And similarly to set the foreground color (text color), set this property for the TextField:

net.sf.jasperreports.style.forecolor

…to a field of your choosing that has the color in it. (Or hard code the color by typing into the value for this property, surrounded by double quotes to specify a constant).

  • JSON queries against your DataSet
    JasperReports seems to play pretty well with JSON. But something that isn’t obvious is a way to query/filter the JSON data within the JasperReports engine, which it is populated into a data set.To demonstrate how to do this, let’s take an example JSON data:

[{“letters”:[{“category”:”A to C”,”data”:[“a”,”b”,”c”]},{“category”:”D to F”,”data”:[“d”,”e”,”f”]}]}]

Or more visually friendly, like so:

JasperReportsJsonExample

Now let’s say you want to limit your JasperReports Data Set to “letters”, and furthermore a certain category. What you need to do is edit the query for the Data Set, and specify the following:

letters(category==A to C)

And that’s it!

  • More to come later

Sorting a JSON Array in Java

There are a number of approaches you can take. But a simple one is to first convert it to a Java Collection, and use Collections.sort() with a custom comparator.

The example I’ll follow consists of an org.json.JSONArray which is has (and only has) org.json.JSONObject’s. So a json array of json objects, which is pretty common. Say you want to sort the JSONObjects in the JSONArray, based on a key in the JSONObject.

Let’s start by converting a JSONArray to a Collection of JSONObjects, using the java List type:

List<JSONObject> myJsonArrayAsList = new ArrayList<JSONObject>();
for (int i = 0; i < myJsonArray.length(); i++)
    myJsonArrayAsList.add(myJsonArray.getJSONObject(i));

Now you can use Collections.sort() with a custom comparator. Let’s say you have a key named “key” in each json object, which maps to an int, and you want to sort on int value. You would use the following code:

Collections.sort(myJsonArrayAsList, new Comparator<JSONObject>() {
    @Override
    public int compare(JSONObject jsonObjectA, JSONObject jsonObjectB) {
    	int compare = 0;
    	try
    	{
    		int keyA = jsonObjectA.getInt("key");
    		int keyB = jsonObjectB.getInt("key");
    		compare = Integer.compare(keyA, keyB);
    	}
    	catch(JSONException e)
    	{
    		e.printStackTrace();
    	}
    	return compare;
    }
});

That’ll do. Now, let’s take it a step further. Let’s say the values in the key field of each json object are Strings, and you want to sort based on the Strings, but in a particular order. You want the string “oranges” to come first, “bananas” to come second, “pineapples” to come third, and “apples” to come last.

An easy way to go about this is to create a HashMap, and assign these strings integer values. Then use those integer values to compare. Here’s what the code would look like for that:

Collections.sort(myJsonArrayAsList, new Comparator<JSONObject>() {
    @Override
    public int compare(JSONObject jsonObjectA, JSONObject jsonObjectB) {
    	int compare = 0;
    	try
    	{
			HashMap<String,Integer> fruitTypeSorts = new HashMap<String,Integer>();
			fruitTypeSorts.put("orange", 1);
			fruitTypeSorts.put("bananas", 2);
			fruitTypeSorts.put("pineapples", 3);
			fruitTypeSorts.put("apples", 4);
			int valueA=fruitTypeSorts.get(jsonObjectA.getString("key"));
			int valueB=fruitTypeSorts.get(jsonObjectB.getString("key"));
			return Integer.compare(valueA, valueB);
    	}
    	catch(JSONException e)
    	{
    		e.printStackTrace();
    	}
    	return compare;
    }
});

And voila! Now you have the List sorted based on the key value, with objects with key values oranges being first, then bananas, and so on.

To tie it all together, you want to convert it back to a JSONArray. To put the sorted JSONObjects back into your original array, simply:

myJsonArray = new JSONArray();
for (int i = 0; i < myJsonArrayAsList.size(); i++) {
	myJsonArray.put(myJsonArrayAsList.get(i));
}