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.

Puzzler: the catalyst method does not work

Recently I wrote a post about a catalyst method in Java – an issue where an existence of a method that is never actually invoked can affect the code execution. The trick was that the way compiler created bytecode for static method was ambiguous for this given code snippet and therefore JVM resolved it incorrectly.

The code snippet I presented before publishing was simplified multiple times to make is as readable as possible. At some point the following simplification was suggested:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
public static class BaseSerializer {
    static <E> Object serialize(E obj) {
        return "BaseSerializer " + obj.toString();
    }
}

public static class CatalystSerializer extends BaseSerializer {
    static <E> String serialize(E obj) {
        return "CatalystSerializer " + obj.toString();
    }
}

public static class AdvancedSerializer extends CatalystSerializer {
    static <E extends Serializable> String serialize(E obj) {
        return "AdvancedSerializer " + obj.toString();
    }
}

public static void main(String[] args) {
    System.out.println(AdvancedSerializer.serialize("ABC"));
    System.out.println(AdvancedSerializer.serialize(new Object()));
}

…but did not worked – the bug was missing. So that is a puzzler: why the snippet above works fine while the code in a previous post did not (see the code for comparison). Where is the difference that made the issue appear its ugly head?

Before I give away the answer let me say what did not caused the difference. It’s obviously not because of the classes names I used (hahaha!) or the content of each of the methods. It is not because of using a different interface – Serializable in this code does the same thing as Comparable in the previous one. Finally it is not because of using Lists or any other collections – no matter how many flaws they might have it is not what contributed to the puzzle. So what is it?

If you read the previous post it won’t be a surprise to you: it’s because of type erasure. In original code the JVM got confused because two different for compiler static methods were saved as the same bytecode. This was possible due to type erasure – the generic typing was the only difference between those methods and that got ‘lost in translation’.

The situation in the code above is slightly different: you might expect that after type erasing both calls in main to AdvancedSerializer.serialize() and CatalystSerializer.serialize() will look the same and JVM will make an error again. In fact the first one will get compiled to ‘String AdvancedSerializer.serialize(Serializable)’, while second one due to a compiler brilliance will become ‘String AdvancedSerializer.serialize(Object)’!

What’s the lesson here? Well, puzzle itself is quite interesting but… I just can’t think of any :) Maybe only this: it’s good to have brilliant Java compiler, huh?

Quality Medications Here