From fdd6a9d9d00fbb0e94c96226744deab563b1cd63 Mon Sep 17 00:00:00 2001 From: vandeti Date: Sat, 4 Apr 2015 14:55:00 +0200 Subject: Less restrictive RPC interface detection in registerRpc (#10945) Change-Id: I664740523b35b64b0fd0c4fdc21597a2245537cd --- .../com/vaadin/server/AbstractClientConnector.java | 40 ++++++-- .../vaadin/server/AbstractClientConnectorTest.java | 112 +++++++++++++++++++++ 2 files changed, 141 insertions(+), 11 deletions(-) create mode 100644 server/tests/src/com/vaadin/server/AbstractClientConnectorTest.java diff --git a/server/src/com/vaadin/server/AbstractClientConnector.java b/server/src/com/vaadin/server/AbstractClientConnector.java index 87b61c9623..0655b482ed 100644 --- a/server/src/com/vaadin/server/AbstractClientConnector.java +++ b/server/src/com/vaadin/server/AbstractClientConnector.java @@ -180,22 +180,40 @@ public abstract class AbstractClientConnector implements ClientConnector, * RPC interface implementation. Also used to deduce the type. */ protected void registerRpc(T implementation) { + // Search upwards until an interface is found. It must be found as T + // extends ServerRpc Class cls = implementation.getClass(); - Class[] interfaces = cls.getInterfaces(); - while (interfaces.length == 0) { - // Search upwards until an interface is found. It must be found as T - // extends ServerRpc + Class serverRpcClass = getServerRpcInterface(cls); + + while (cls != null && serverRpcClass == null) { cls = cls.getSuperclass(); - interfaces = cls.getInterfaces(); + serverRpcClass = getServerRpcInterface(cls); } - if (interfaces.length != 1 - || !(ServerRpc.class.isAssignableFrom(interfaces[0]))) { + + if (serverRpcClass == null) { throw new RuntimeException( - "Use registerRpc(T implementation, Class rpcInterfaceType) if the Rpc implementation implements more than one interface"); + "No interface T extends ServerRpc found in the class hierarchy."); + } + + registerRpc(implementation, serverRpcClass); + } + + @SuppressWarnings("unchecked") + private Class getServerRpcInterface(Class implementationClass) { + Class serverRpcClass = null; + if (implementationClass != null) { + for (Class candidateInterface : implementationClass + .getInterfaces()) { + if (ServerRpc.class.isAssignableFrom(candidateInterface)) { + if (serverRpcClass != null) { + throw new RuntimeException( + "Use registerRpc(T implementation, Class rpcInterfaceType) if the Rpc implementation implements more than one interface"); + } + serverRpcClass = (Class) candidateInterface; + } + } } - @SuppressWarnings("unchecked") - Class type = (Class) interfaces[0]; - registerRpc(implementation, type); + return serverRpcClass; } /** diff --git a/server/tests/src/com/vaadin/server/AbstractClientConnectorTest.java b/server/tests/src/com/vaadin/server/AbstractClientConnectorTest.java new file mode 100644 index 0000000000..96ca82a0b3 --- /dev/null +++ b/server/tests/src/com/vaadin/server/AbstractClientConnectorTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.server; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import com.vaadin.shared.MouseEventDetails; +import com.vaadin.shared.communication.FieldRpc.BlurServerRpc; +import com.vaadin.shared.ui.ClickRpc; + +/** + * We test that AbstractClientConnector has a suitable isThis method which is + * needed to correctly perform an equals check between a proxy and it's + * underlying instance. + * + * @author Vaadin Ltd + */ +public class AbstractClientConnectorTest { + + @Test + public void registerRPCMultiInterfaceTest() { + AbstractClientConnector mock = mock(AbstractClientConnector.class); + MultiServerRpcMock implementation = new MultiServerRpcMock(); + Mockito.doCallRealMethod().when(mock).registerRpc(implementation); + try { + mock.registerRpc(implementation); + Assert.fail("expected exception"); + } catch (Exception expected) { + Assert.assertEquals( + expected.getMessage(), + "Use registerRpc(T implementation, Class rpcInterfaceType) if the Rpc implementation implements more than one interface"); + } + } + + @Test + public void registerRPCInterfaceTest() { + AbstractClientConnector mock = mock(AbstractClientConnector.class); + ServerRpcMock implementation = new ServerRpcMock(); + Mockito.doCallRealMethod().when(mock).registerRpc(implementation); + mock.registerRpc(implementation); + verify(mock, times(1)).registerRpc(implementation, ClickRpc.class); + } + + @Test + public void registerRPCInterfaceLastTest() { + AbstractClientConnector mock = mock(AbstractClientConnector.class); + ServerRpcLastMock implementation = new ServerRpcLastMock(); + Mockito.doCallRealMethod().when(mock).registerRpc(implementation); + mock.registerRpc(implementation); + verify(mock, times(1)).registerRpc(implementation, ClickRpc.class); + } + + private class ServerRpcLastMock implements Comparable, + ClickRpc { + private static final long serialVersionUID = -2822356895755286180L; + + @Override + public void click(MouseEventDetails mouseDetails) { + } + + @Override + public int compareTo(ServerRpcLastMock o) { + return 0; + } + + } + + private class ServerRpcMock implements ClickRpc { + private static final long serialVersionUID = 2822356895755286180L; + + @Override + public void click(MouseEventDetails mouseDetails) { + } + + } + + private class MultiServerRpcMock implements ClickRpc, BlurServerRpc { + + private static final long serialVersionUID = -7611999715560330373L; + + @Override + public void blur() { + + } + + @Override + public void click(MouseEventDetails mouseDetails) { + + } + + } + +} -- cgit v1.2.3