Compile Save UI Binding based on Mockito

A very technical project on which we are working at the moment consist of refactoring a rich client (direct jdbc-DB access) into a thin-/rich-client connected to a JavaEE service layer. We've got the challenge to introduce a couple of new architectural patterns. One of the challenges is to bind the service model data to the swing based gui elements. Sure, there exists a well known bean-binding [1] project hosted on jgoodies [2] to automatically bind two properties of different objects against each other. This would look like this:

Property propertyVolume = BeanProperty.create("volume");
Property propertySliderValue = BeanProperty.create("value");
Binding bindingVolumeSlider = Bindings.createAutoBinding(
    AutoBinding.UpdateStrategy.READ_WRITE,
        volume, propertyVolume,
    sliderVolume, propertySliderValue);
bindingVolumeSlider.bind();


The Problem of binding those properties against each other is the fact, that the binding is based on property names defined by strings. Refactoring of model classes won't affect those property definitions. The risk in refactoring is therefore very high because errors will occur only at runtime by accessing such a property or by automated tests calling those properties as well. On the other hand there don't exist any code references to those properties used anywhere in the code.

Therefore we pursued an architectural goal of integrating a compile save bean binding into our new client application. After some coffee and some brain power the idea came up to use parts of the testing framework Mockito [3] which itself provides the functionality of creating mock based unit tests using compile save statements like

 LinkedList mockedList = mock(LinkedList.class);
 
 //stubbing
 when(mockedList.get(0)).thenReturn("first");


Where the methodcall 'get' reflects the real method call of a provided class object.

Starting with this idea we developed the following prototype showing a simple way to integrate compile/refactoring save UI binding using the two frameworks JGoodies Binding and Mockito.

We start by creating two dummy objects only used to bind UI elements to some properties of them:

    public class DummyPojo {

        private String m_name;
        private int m_number;

        public String getName() {
            return m_name;
        }

        public void setName(String name) {
            m_name = name;
        }

        public int getNumber() {
            return m_number;
        }

        public void setNumber(int number) {
            m_number = number;
        }
    }

    public static class DummyPojo2 {

        private String m_street;

        public String getStreet() {
            return m_street;
        }

        public void setStreet(String street) {
            m_street = street;
        }
    }

Now we created a simple example which binds properties of those two objects to two different swing elements. Any modifications done to the swing components will be propagated to the objects thanks to the JGoodies Binding framework.

public BeanBindingPrototype() {

        DummyPojo spy = Mockito.mock(DummyPojo.class);
        DummyPojo2 mock2 = Mockito.mock(DummyPojo2.class);
        BeanProperty<DummyPojo, String> prop = registerPojoProperty(spy.getName());
        BeanProperty<DummyPojo2, String> prop2 = registerPojoProperty(mock2.getStreet());

        JFrame frame = new JFrame();

        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(2, 2));

        JTextField field = new JTextField(20);
        BeanProperty<JTextField, String> textProperty = BeanProperty.create("text");
        panel.add(new JLabel("Name:"));
        panel.add(field);

        JTextField field2 = new JTextField(20);
        panel.add(new JLabel("Street:"));
        panel.add(field2);

        frame.getContentPane().add(panel);

        final DummyPojo realObject = new DummyPojo();
        final DummyPojo2 realObject2 = new DummyPojo2();

        AutoBinding<DummyPojo, String, JTextField, String> binding = Bindings.createAutoBinding(
            UpdateStrategy.READ_WRITE, null, prop, field, textProperty);
        binding.bind();
        binding.unbind();
        binding.setSourceObject(realObject);
        binding.bind();

        AutoBinding<DummyPojo2, String, JTextField, String> binding2 = Bindings.createAutoBinding(
            UpdateStrategy.READ_WRITE, realObject2, prop2, field2, textProperty);
        binding2.bind();

        frame.pack();
        frame.setPreferredSize(new Dimension(200, 200));
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println("Name:" + realObject.getName());
                System.out.println("Street:" + realObject2.getStreet());
            }
        });
        frame.setVisible(true);
    }


The interesting part of this idea is the following:

DummyPojo spy = Mockito.mock(DummyPojo.class);
DummyPojo2 mock2 = Mockito.mock(DummyPojo2.class);
BeanProperty<DummyPojo, String> prop = registerPojoProperty(spy.getName());
BeanProperty<DummyPojo2, String> prop2 = registerPojoProperty(mock2.getStreet());

We create BeanProperties of the two object class properties 'name' and 'street' while referencing a real getter access method.

Those properties are created using Mockito:

 

public <T, S, V> BeanProperty<S, V> registerPojoProperty(T methodCall) {
        OngoingStubbingImpl<T> stub = (OngoingStubbingImpl<T>)Mockito.when(methodCall);
        List<Invocation> registeredInvocations = stub.getRegisteredInvocations();
        Invocation invocation = registeredInvocations.get(0);
        String methodName = invocation.getMethodName();
        for (String prefix : prefixes) {
            if (methodName.startsWith(prefix)) {
                int len = prefix.length();
                methodName = String.valueOf(methodName.charAt(len)).toLowerCase()
                        + methodName.substring(len + 1);
                break;
            }
        }

        BeanProperty<S, V> property = BeanProperty.create(methodName);

        stub.thenCallRealMethod();
        return property;
    }

Performing a Mockito 'when' operation we can extract an OngoingStubbing of the effective method called on that mock before. Within this OngoingStubbing we get all informations needed to extract the real methodname called and derived from that we can create dynamically a string based BeanProperty describing this methodcall.

Drawbacks of this implementations are the missing support for nested object property access like this one:

 obj.getAdress().getStreet()

The solution to this we'd like to solve in the next chapter.

So far best regards from the tegonal development team.

Download maven Project source code of prototype [tar.gz-File]