Compile Save UI Binding based on Mockito Part 2

Remember my previous blog entry about creating compile/refactoring save ui binding based on Mockito and BeansBinding?

Today we'd like to make some improvements to the previous prototype. Mainly we'd like to add support for binding nested properties like

obj.getAdress().getStreet();

On the other hand we'd like to encapsulate the usage of Mockito into simple a helper class which may be needed in different projects. Therefore we investigated the Mockito implementation to trace the problem of binding nested properties and encapsulated the required parts into an own class called 'ObjectBinder'. The ObjectBinder is defined using generics to create a wrapper of any object. The ObjectBinder may be used with the following method calls to create a BeanProperty based on a real method call to the object classes stub.

ObjectBinder<DummyPojo> binder = new ObjectBinder<BeanBindingPrototype2.DummyPojo>(
            DummyPojo.class);

binder.getModelTemplate().getName();
String path = binder.getBeanPropertyPath();
BeanProperty<DummyPojo, String> name = BeanProperty.create(path);


Using the so called ModelTemplate of the ObjectBinder creates a new Mock-Object of the provided class and starts the tracking. It is following the method calls to that object.

/**
 * @return type template used to declare gui bindings
 */
public O getModelTemplate() {
    MockSettingsImpl settings = (MockSettingsImpl)new MockSettingsImpl()
        .defaultAnswer(new EXReturnsDeepStubs(m_mockingCache));
    O mock = mockUtil.createMock(m_clazz, settings);
    mockingProgress.mockingStarted(mock, m_clazz, settings);
    return mock;
}

We use an own answer to keep track of all nested method called based on that mock.

    private static class EXReturnsDeepStubs extends ReturnsDeepStubs {

        private static final long serialVersionUID = 1880837724076720541L;

        private final MockingCache m_cache;
        private Map<Object, Object> m_follower = new HashMap<Object, Object>();

        public EXReturnsDeepStubs(MockingCache cache) {
            m_cache = cache;
        }

        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
            // Class<?> clz = invocation.getMethod().getReturnType();
            Object answer = super.answer(invocation);
            // if (new MockCreationValidator().isTypeMockable(clz)) {
            // return will be another mock
            Object mock = invocation.getMock();
            Object parent = m_follower.get(mock);
            if (parent != null) {
                m_cache.registerInvocation(parent, mock, invocation);
            }
            else {
                m_cache.registerInvocation(mock, invocation);
            }

            // register the following mock
            m_follower.put(answer, mock);
            // }

            return answer;
        }
    }

That is where we register every method invocation in a shared cache object instance:

    public static class MockingCache {

        public HashMap<Object, Stack<InvocationOnMock>> m_invocationCache = new HashMap<Object, Stack<InvocationOnMock>>();

        public void registerInvocation(Object mock, InvocationOnMock invocation) {
            Stack<InvocationOnMock> stack = m_invocationCache.get(mock);
            if (stack == null) {
                stack = new Stack<InvocationOnMock>();
                m_invocationCache.put(mock, stack);
            }
            stack.push(invocation);
        }

        public void registerInvocation(Object parent, Object mock, InvocationOnMock invocation) {
            Stack<InvocationOnMock> stack = m_invocationCache.get(parent);
            if (stack == null) {
                stack = new Stack<InvocationOnMock>();
            }
            stack.push(invocation);
            m_invocationCache.put(mock, stack);
            m_invocationCache.remove(parent);
        }

        public void clear() {
            m_invocationCache.clear();
        }

        public Stack<InvocationOnMock> retrieveMockInvocationStack(Object mock) {
            // m_invocationCache.get(mock);
            return m_invocationCache.remove(mock);
        }
    }

Now the whole trick of getting deep method invocation stack after calling a nested property is fetching the actual stack of the shared cache.

public Stack<InvocationOnMock> getLatestInvocationStack() {
    mockingProgress.stubbingStarted();
    @SuppressWarnings("rawtypes")
    OngoingStubbing stubbing = (OngoingStubbing)mockingProgress.pullOngoingStubbing();
    Object mock = stubbing.getMock();
    stubbing.thenCallRealMethod();
    return m_mockingCache.retrieveMockInvocationStack(mock);
}


The stack of the method invocation will also get converted into an appropriate BeanProperty using a simple conversion mechanism:

    public String getBeanPropertyPath() {
        // convert stacktrace into bean property
        Stack<InvocationOnMock> latestInvocationStack = getLatestInvocationStack();
        StringBuffer buf = new StringBuffer();
        for (InvocationOnMock invocation : latestInvocationStack) {
            String methodName = invocation.getMethod().getName();

            for (String prefix : PREFIXES) {
                if (methodName.startsWith(prefix)) {
                    int len = prefix.length();
                    methodName = String.valueOf(methodName.charAt(len)).toLowerCase()
                            + methodName.substring(len + 1);
                    break;
                }
            }

            if (buf.length() > 0) {
                buf.append('.');
            }
            buf.append(methodName);
        }
        return buf.toString();
    }

    public <S> BeanProperty<O, S> getBeanProperty() {
        return BeanProperty.create(getBeanPropertyPath());
    }

So now we've got a real BeanProperty of a nested method call using compile save method invocation. This BeanProperty can get used as in the first example binding this property to a property of a swing ui element like:

ObjectBinder<DummyPojo> binder = new ObjectBinder<BeanBindingPrototype2.DummyPojo>(
            DummyPojo.class);

binder.getModelTemplate().getParent().getStreet();
String path = binder.getBeanPropertyPath();
BeanProperty<DummyPojo, String> street = BeanProperty.create(path);

//bean property refering to swing element
BeanProperty<JTextField, String> textProperty = BeanProperty.create("text");
JTextField field = new JTextField(20);

DummyPojo realObject = new DummyPojo();
ParentPojo parent = new ParentPojo();
realObject.setParent(parent);

//binding nested beanproperty of real object to textfield property
AutoBinding<DummyPojo, String, JTextField, String> binding = Bindings.createAutoBinding(
    UpdateStrategy.READ_WRITE, realObject, name, field, textProperty);
binding.bind();

That's all. The drawbacks of this solution is still that we have to do a method call of the mocked template before fetching a bean property of the ObjectBinder. That means two sequential method call which are required in this order otherwise the mockito framework (clearly) will raise an exception.

In the next prototype I'd like to create a simple example of a base ui class that may be used to encapsulate the binding logic and provide a simple an easy interface to extending GUI classes.

The project is available on github.

The whole maven project can get downloaded from here.