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