diff --git a/flow-server/src/main/java/com/vaadin/flow/internal/ConstantPoolKey.java b/flow-server/src/main/java/com/vaadin/flow/internal/ConstantPoolKey.java index 49dfe0bc8f1..c9c3dd46ec0 100644 --- a/flow-server/src/main/java/com/vaadin/flow/internal/ConstantPoolKey.java +++ b/flow-server/src/main/java/com/vaadin/flow/internal/ConstantPoolKey.java @@ -40,7 +40,7 @@ */ public class ConstantPoolKey implements Serializable { private final JsonValue json; - private final String id; + private String id; /** * Creates a new constant pool key for the given JSON value. The value @@ -53,8 +53,6 @@ public class ConstantPoolKey implements Serializable { public ConstantPoolKey(JsonValue json) { assert json != null; this.json = json; - - id = calculateHash(json); } /** @@ -63,11 +61,14 @@ public ConstantPoolKey(JsonValue json) { * @return the id used to identify this value */ public String getId() { + if (id == null) { + id = calculateHash(json); + } return id; } /** - * Exports the this key into a JSON object to send to the client. This + * Exports this key into a JSON object to send to the client. This * method should be called only by the {@link ConstantPool} instance that * manages this value. It may be called multiple times. * @@ -76,9 +77,7 @@ public String getId() { * null */ public void export(JsonObject clientConstantPoolUpdate) { - assert id.equals(calculateHash(json)) : "Json value has been changed"; - - clientConstantPoolUpdate.put(id, json); + clientConstantPoolUpdate.put(getId(), json); } /** diff --git a/flow-server/src/test/java/com/vaadin/flow/component/ComponentEventBusTest.java b/flow-server/src/test/java/com/vaadin/flow/component/ComponentEventBusTest.java index 406b6a0d052..240086352a9 100644 --- a/flow-server/src/test/java/com/vaadin/flow/component/ComponentEventBusTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/component/ComponentEventBusTest.java @@ -21,10 +21,13 @@ import org.junit.Assert; import org.junit.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import com.vaadin.flow.component.ComponentTest.TestComponent; import com.vaadin.flow.dom.Element; import com.vaadin.flow.internal.JsonCodec; +import com.vaadin.flow.internal.MessageDigestUtil; import com.vaadin.flow.internal.nodefeature.ElementListenerMap; import com.vaadin.flow.shared.Registration; @@ -86,6 +89,11 @@ public boolean equals(Object obj) { } } + @Tag("button") + private class TestButton extends Component implements ClickNotifier { + + } + private void fireDomEvent(Component component, String domEvent, JsonObject eventData) { Element e = component.getElement(); @@ -482,4 +490,16 @@ public void eventUnregisterListener_outsideListenerTwiceThrows() { c.fireEvent(new ServerEvent(c, new BigDecimal(0))); storedEvent.get().unregisterListener(); } + + @Test // #7826 + public void addListener_eventDataExpressionsPresent_constantPoolKeyNotCreatedAfterEachExpression() { + final TestButton button = new TestButton(); + try (MockedStatic util = Mockito.mockStatic(MessageDigestUtil.class)){ + util.when(() -> MessageDigestUtil.sha256(Mockito.anyString())).thenReturn(new byte[]{1,1,1,1,1,1,1,1,1,1,1,}); + button.addClickListener(event -> { + }); + util.verifyNoInteractions(); + } + + } } diff --git a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/ConstantPoolPerformanceView.java b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/ConstantPoolPerformanceView.java new file mode 100644 index 00000000000..1d8afbcd0ad --- /dev/null +++ b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/ConstantPoolPerformanceView.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2021 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.flow.uitest.ui; + +import com.vaadin.flow.component.UI; +import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.html.H1; +import com.vaadin.flow.component.html.NativeButton; +import com.vaadin.flow.router.Route; + +@Route("performance/constant-pool") +public class ConstantPoolPerformanceView extends AbstractDivView { + + Div container = new Div(); + Div notification = new Div(); + public ConstantPoolPerformanceView() { + NativeButton btn = new NativeButton("refresh"); + btn.addClickListener(e->{ + container.removeAll(); + for (int i = 0; i <1000; i++) { + container.add(new H1("Headline " + i)); + container.add(new NativeButton("BTN " + i, e2 -> notification.setText("clicked"))); + } + UI.getCurrent().getPage().executeJs("setTimeout(function(){$0.click()},2000)", btn); + }); + add(btn,notification,container); + } + +} diff --git a/pom.xml b/pom.xml index 60ff3f82ab1..eca62d46853 100644 --- a/pom.xml +++ b/pom.xml @@ -249,6 +249,11 @@ mockito-core 3.12.4 + + org.mockito + mockito-inline + 3.12.4 + org.hamcrest hamcrest-all @@ -275,7 +280,7 @@ org.mockito - mockito-core + mockito-inline test