Introducing static typing

As a Software Engineer consultant in Zuhlke, I have an opportunity to work on various projects in various stages of development. Recently I have joined another existing project and I have found out again that we use Map<String, Object> too much, instead of mapping the objects to classes and benefit from all the goods of static typing. I think I have never before appreciated how powerful static typing is, and how much the lack of it can hurt (maybe that’s why I prefer to use Java over JavaScript?). The main reason for us to use maps is jdbi – we execute the SQL, we get back List<Map<String, Object>>. But mapping it to objects is too much effort so instead we keep working with maps. But what if mapping could be trivial and painless?

What is wrong with Map<String, Object>?

To start with, a few reasons why maps are bad:

  • there is no code auto-completion
  • finding a type of a property is impossible at compile-time
  • casting the values may fail at run-time
  • it is not possible to find usages of given property
  • static code analysis is impossible, we cannot easily identify unused properties (in case of classes IDE shows a warning)
  • more error prone (typos)

So generally, finding what kind of data we are dealing with is far more difficult. We can never know whether what we see is all, or whether there are some optional properties, which appear in map only sometimes. Writing the code is slower, as we have to search other sources to figure out properties names. And finally, in case of any errors the feedback loop is greatly increased – errors that could be reported by compiler are happening at runtime instead – so completely opposite to what agile development is about.

So what we would like? We would like to pass in an SQL and a class to some component that will do some magic and give us the list of objects of the class that we passed:

public class Employee {
    public final String name;
    public final String surname;
    // etc.
}

public class Main{

    public static void main(String... args) {
        // ...
        String sql = "SELECT name, surname, ...";
        List<Employee> employees = magicComponent.doMagic(sql, Employee.class);
    }

}

I have successfully implemented such “magic component” for one of our clients in the past, which greatly improved the maintainability of the code and exposed a lot of problems (e.g. properties which are always null, because they were never selected in SQL or unused properties which required joins to extra tables which in turn gave as free performance improvement).

When I have faced the problem again in another project, I have decided to spend some of my free time to solve it again – better, open source, under free licence and not bound to jdbi, but offering wider usage.

Solution

What I have been working on is a MapToObjectConverter, which has a single public method:

public <T> T convert(Map<String, Object> map, Class<T> targetClass)

So having this you can iterate over the list of maps, convert each of them into the object and return the list of staticly typed objects.

You can find the code in my public github repo, available under Apache version 2 licence. I am in the process of getting it to Maven Central Repository. For now, you can try it out and tell me what you think, all feedback welcome.

What it does and does not do:

  • assigns the values from the map to fields whose names are equal to the keys
  • throws exception if there are entries without corresponding fields (of course listing the keys)
  • throws exception if there are fields for which there were no values (of course listing names of all such fields)
  • assigns the fields regardless of their access modifier and final keyword – no methods or annotations are required in the class
  • creates the instance of the class without calling its constructor so you have a complete freedom in how you want to define the class
  • differs between no value for key or value being null
  • requires the field to be Optional if the value is null, so once we have the staticly typed class, we know there aren’t any nulls
  • it checks the type of field and value, also in case of Optional fields
  • can map String values to enums (using static valueOf(String) method)
  • allows the fields to be supertypes of values, so you can assign Integer value to Number field
  • unfortunately, it doesn’t allow wildcards in Optionals, so Integer value can be assigned to Optional<Integer> field but cannot be assigned to field declared as Optional<? extends Number> (this might be improved in future)
  • doesn’t allow raw Optionals

Example:

public enum Gender {
    MALE, FEMALE
}

public class Employee {

    public final String name;
    public final int age;
    public final Gender gender;
    public final Optional<String> phoneNumber;

    public Employee(String name, int age, Gender gender, Optional<String> phoneNumber) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.phoneNumber = phoneNumber;
    }

}

public class Example {

    @Test
    public void convertsMapToEmployee() {
        Map<String, Object> employeeMap = new HashMap<>();
        employeeMap.put("name", "Jaroslaw Pawlak");
        employeeMap.put("age", 26);
        employeeMap.put("gender", "MALE");
        employeeMap.put("phoneNumber", null);

        MapToObjectConverter converter = new MapToObjectConverter();

        Employee employee = converter.convert(employeeMap, Employee.class);

        assertEquals("Jaroslaw Pawlak", employee.name);
        assertEquals(26, employee.age);
        assertEquals(Gender.MALE, employee.gender);
        assertEquals(Optional.empty(), employee.phoneNumber);
        // multiple assertions give poor diagnostics, use shazamcrest instead
    }

}

What might be coming in future versions:

  • wildcards for Optional fields
  • mappers (so we can have Address object as a field in Employee or can convert value to enum other than by calling valueOf method)

About Jaroslaw Pawlak

I have done MSci in Computer Science at King’s College London and currently work as Software Engineer specialising in Java. I spend most of my time in front of computer improving my programming (and other) skills or just relaxing with a good game. I also train some sports but at the moment I am not a member of any club. I love cycling and volleyball, but I have also played a lot of football, tennis and trained martial arts.

Posted on January 30, 2016, in My Projects. Bookmark the permalink. 3 Comments.

  1. Hi Jarek!

    Hope you’re well. It’s been some time since your last post!

    What do you think about the object-relational mapping software that’s currently available for java, like Hibernate? Is there any particular reason why you’re not using one?
    https://en.wikipedia.org/wiki/List_of_object-relational_mapping_software#Java

    • Hi Mateusz,

      The reason of writing my own mapper is that none of the existing mappers I have seen offers what we were looking for. I mean here mostly simplicity – there are no annotations or any other requirements on the class’ members (such as no-arg constructor), there is no need to write your own mapper for every class (as in jdbi’s mappers) and finally it offers only one public method so it’s hard to misuse and you don’t need any tutorials in order to make it work.

Leave a reply to Mateusz Cancel reply