Beautiful casting gone bad

Recently I encountered a blog entry describing a “beautiful” way of making the code more readable by creating a gereric helper method to perform object casting. Today I want to share some opinions about this improvement and general thoughts about coding.

The premise

In essence author of this post was trying to solve following problem: imagine you have a context object (HttpSession for example) that is used as a map of String keys to some possibly large, complicated generic values of different types. The contents of it are set by an external code out of your control. You can request any value from this context by specifying the key, but the interface contract is to return an Object so if you want to use it you need to cast it into proper type. In that case your code usually looks quite ugly:

1:
2:
3:
4:
5:
    HttpSession session = getHttpSession()
    // We know that an attribute "phonebook" is a map
    // of names (String) to sets of telephone numbers (String)
    Map<String, Set<String>> phonebook =
            (Map<String, Set<String>>) session.getAttribute("phonebook");

The beautiful solution to that problem according to the author was creating following helper method:

1:
2:
3:
    public static <T> T cast(Object obj) {
        return (T) obj;
    }

Now all you need to do is to import it in a static way in every class and replace the ugly casting with a short and readable invocation of our beautiful method:

1:
2:
3:
4:
5:
    HttpSession session = getHttpSession()
    // We do not need to know anything about the type
    // of "phonebook" - cast() method does everything for us
    Map<String, Set<String>> phonebook =
            cast(session.getAttribute("phonebook"));

So what’s wrong?

It may seem that this is a huge improvement for readability as before almost half of the code was casting, which obscured the real logic of the program. But this helper method in fact is no help at all, as it creates serious vulnerabilities to error. In fact it basically removes type-checking from your code and therefore makes every tiny error to appear in runtime instead of compile time.

The first problem you may run into is when by mistake you use incompatible types for casting. The chance of that happening is very high: it may happen just by copy-pasting wrong part of code, during refactoring when you change the type of object in the context or just because of naming confusion. The problem is not that error will happen but that you will find out about it only after running the program. See the following errors – all resulting in ClassCastException:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
   // Naming issue: some may think telephone number is actually a number
    Number telephoneNumber = cast("1234567");

    // Refactoring: type of "digits" changed from List<Character>
    // to Set<Character> but not all places using it have been updated:
    session.setAttribute("digits", setOfDigits);
    List<Character> characters = cast(session.getAttribute("digits"));

    // Copy-paste error: this line was copy-pasted from other
    // place in the code and the old key was left by mistake
    String authorName = cast(session.getAttribute("authorId"));

The errors shown above are serious, but not the worst thing that can happen. Since there is no way for the compiler to find them it is very possible that they will appear during code execution, possibly in production crashing your application. The good thing about them is that when they’ll appear you will get a stack trace pinpointing the location of an error. The following code shows a worse kind of error – the one that will kill your program and leave you no clue why that happen:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
   // we have a map of Integers to Integers
    Map<Integer, Integer> integerMap = new HashMap<Integer, Integer>();
    integerMap.put(123, 123);
    session.setAttribute("map", integerMap);

    // Because of an error we cast it to a map of String to String
    Map<String, String> badMap = cast(session.getAttribute("map"));

    // we pass the map between many objects and doing many operations on it
    String s1 = badMap.get(1);
    badMap.put("2", "2");
    String s2 = badMap.get("2");
    String s3 = badMap.get(2);
    String s4 = badMap.get(123);

It is obvious the mistake was made, but when it will manifest itself? Unfortunately this will not happen in line 7 when casting is done. Even the code in lines 10-13 will not result in a exception! Due to many factors (see posts about map type safety and checked set) the error will wait until line 14 to crash your application. The stack trace you will get probably won’t help you much as line 14 in reality may be far away from the place when casting is done.

Is there a way to make it better?

The biggest problem with the cast() method is not the casting itself, but the uncontrolled way it is being done and the vulnerability to simple code editing errors. You might say: “The cast() method is far from perfect, but still most of the errors above apply to the normal casting. So maybe it’s worth to use it to gain readability?” No, it’s not. There is a better solution for the problem of dealing with context-like objects: writing an adapter for it that will provide a readable and type safe interface. See the following snippet:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
   public class HttpSessionAdapter {
        private final HttpSession session;

        public HttpSessionAdapter(HttpSession session) {
            this.session = session;
        }

        public Map<String, Set<String>> getPhonebook() {
            return (Map<String, Set<String>>)
                    session.getAttribute("phonebook");
        }
    }

This adapter provides type-checking and allows to encapsulate all vulnerabilities in one place, therefore drastically decreasing the chance that anyone using the session’s attributes will make an runtime error. What is more it also gives a boost to readability of the code – now to get a phonebook no casting or attribute requests are needed, you just ask the adapter for it!

1:
2:
3:
4:
5:
6:
7:
    HttpSession session = getHttpSession()
    HttpSessionAdapter sessionAdapter = new HttpSessionAdapter(session);

    // You do not need to know now the phonebook type, as
    // Java typing will enforce it. Also you do not need to know
    // the structure of session nor the names of the keys!
    Map<String, Set<String>> phonebook = sessionAdapter.getPhonebook();

It is important to state that this solution is not bulletproof, but thats because of the way we stated the problem. The fact that we do not control the types of objects originally inserted into the session can cause an runtime exception if an error in inserting occurs. To remove that vulnerability we would have to add ’set’ methods to control the types of inserted object the same way we control it in ‘get’ methods.

Conclusion

You may be tempted in solving your problems by using the features of Java in a non standard way, trying to find magical solutions that show your deep knowledge of the language. Unfortunately this very often leads to design decisions that are more ‘cool’ than thought trough. Whenever possible try to obey the OOD rules as they usually are the most reliable and error/change proof of coding, even if at the time you do not see the direct benefits from that.

Inspecting your Java Beans

When working with Java Beans you may sometimes encounter a problem of inspecting a bean that you do not know. Suppose you wanted to find all of a bean’s properties. One way to do it is directly use Java Reflection API, searching for all the getter and setter methods, parsing their names for the property name, getting its type and so on. It can be however tedious and error-prone. Instead, you could use classes available in java.beans package and make them scan the bean class for you.

Without further ado, let’s see a simple example of using java.beans.Introspector class for scanning Java Beans. We will use following Java Bean:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
public class TestBean {
    private String name;
    private int beanId;
    public TestBean (int beanId, String name) {
        this.beanId=beanId;
        this.name=name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public int getBeanId() {
        return beanId;
    }
}

It isn’t actually a ‘real’ Java Bean (it does not implement Serializable for example) but for our needs it’s enough that it declares a few getter and setter methods. It has both a setter and a getter for field ‘name’, and only a getter for field ‘beanId’, which makes it a read-only field.

We will inspect this bean in the main method below, printing all of its properties. Inspected bean’s information will be stored in an object of class java.bean.BeanInfo:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
public class BeanInspection {
    public static void main(String[] args)
        throws IntrospectionException {

        //We use Inspector class to get a BeanInfo object
        //containing informations about the Java Bean class
        BeanInfo testBeanInfo =
            Introspector.getBeanInfo(TestBean.class);

        //Here we will print out all the discovered
        //property names of our bean
        for (PropertyDescriptor propertyDescriptor :
            testBeanInfo.getPropertyDescriptors()) {
            System.out.println("Property: " +
                propertyDescriptor.getName());
        }
    }
}

It will print the following output:

Property: beanId
Property: class
Property: name

What happened here? Why is there some ‘class’ property that we did not declare in our bean? TestBean, like any other class, extends java.lang.Object, which declares getClass() method. Introspector checks for all properties available in the class, also those declared in super-classes. But there is a way to tell the Introspector to search for properties in our bean, ignoring at the same time all the properties found in some super-class of the bean. We do it by specifying the super-class as the second parameter to the getBeanInfo method:

7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
        //This time we call getBeanInfo method with
        //two arguments. The second one is class
        //whose properties should be ignored during inspection.
        BeanInfo testBeanInfo =
            Introspector.getBeanInfo(TestBean.class, Object.class);
        for (PropertyDescriptor propertyDescriptor :
            testBeanInfo.getPropertyDescriptors()) {
            System.out.println("Property: " +
                propertyDescriptor.getName());
        }

It will ignore the ‘class’ property found in Object, hence printing out only ‘beanId’ and ‘name’.

Java Beans API is much more powerful than just finding Java Bean’s properties. To find out more about how it can be used, check out for example this page.

SHA1 and MD5 checksums in Java

If you need to calculate a hash function on a file or a message, there is an existing API in Java that can do that for you. It isn’t perfect, but it is really easy to use and supports most of the popular checksum calculation algorithms – MD5 and SHA1 among them. Without further ado check out the following code snippet that reads in a file and calculates both hashes for it:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.util.Formatter;

public class HashFunctionTest {

    public static String calculateHash(MessageDigest algorithm,
            String fileName) throws Exception{

        FileInputStream     fis = new FileInputStream(fileName);
        BufferedInputStream bis = new BufferedInputStream(fis);
        DigestInputStream   dis = new DigestInputStream(bis, algorithm);

        // read the file and update the hash calculation
        while (dis.read() != -1);

        // get the hash value as byte array
        byte[] hash = algorithm.digest();

        return byteArray2Hex(hash);
    }

    private static String byteArray2Hex(byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        return formatter.toString();
    }

    public static void main(String[] args) throws Exception {
        String fileName = "javablogging.png";

        MessageDigest sha1 = MessageDigest.getInstance("SHA1");
        MessageDigest md5  = MessageDigest.getInstance("MD5");        

        System.out.println(calculateHash(sha1, fileName));
        System.out.println(calculateHash(md5, fileName));
    }
}

You are not forced to read input trough DigestInputStream – the API of MessageDigest class allows you also to simply use any array of bytes. Unfortunately there is no method to read in the whole input stream, you have to do the reading on your own.

This class is designed to be use internally and unfortunately does not support printing out the hash code as a human readable String. As you can see in the code above we use Formatter class to do that – it’s a readable, but slow solution. If you need something faster you can check the following post showing many different ways to do byte[] to Hex String conversion.

If you’re interested check out the following post on www.javamex.com about the comparison of different possible hash functions that you can use.