Skip to content

Commit ae26609

Browse files
committed
feat: add executeJs helper
1 parent 6a14325 commit ae26609

File tree

5 files changed

+156
-1
lines changed

5 files changed

+156
-1
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*-
2+
* #%L
3+
* Json Migration Helper
4+
* %%
5+
* Copyright (C) 2025 Flowing Code
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
package com.flowingcode.vaadin.jsonmigration;
21+
/*
22+
* Copyright 2000-2025 Vaadin Ltd.
23+
*
24+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
25+
* use this file except in compliance with the License. You may obtain a copy of
26+
* the License at
27+
*
28+
* http://www.apache.org/licenses/LICENSE-2.0
29+
*
30+
* Unless required by applicable law or agreed to in writing, software
31+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
32+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
33+
* License for the specific language governing permissions and limitations under
34+
* the License.
35+
*/
36+
37+
import com.vaadin.flow.component.page.PendingJavaScriptResult;
38+
import com.vaadin.flow.function.SerializableConsumer;
39+
import elemental.json.JsonValue;
40+
import java.io.Serializable;
41+
42+
/**
43+
* A pending result from a JavaScript snippet sent to the browser for evaluation. This interface
44+
* utilizes Elemental JSON in order to abstract away breaking changes introduced in Vaadin version
45+
* 25.
46+
*
47+
* @see PendingJavaScriptResult
48+
* @author Vaadin Ltd
49+
*/
50+
public interface ElementalPendingJavaScriptResult extends Serializable {
51+
52+
/**
53+
* Adds an untyped handler that will be run for a successful execution and a
54+
* handler that will be run for a failed execution. One of the handlers will
55+
* be invoked asynchronously when the result of the execution is sent back
56+
* to the server. It is not possible to synchronously wait for the result of
57+
* the execution while holding the session lock since the request handling
58+
* thread that makes the result available will also need to lock the
59+
* session.
60+
* <p>
61+
* Handlers can only be added before the execution has been sent to the
62+
* browser.
63+
*
64+
* @param resultHandler
65+
* a handler for the JSON representation of the value from a
66+
* successful execution, not <code>null</code>
67+
* @param errorHandler
68+
* a handler for an error message in case the execution failed,
69+
* or <code>null</code> to ignore errors
70+
*/
71+
void then(SerializableConsumer<JsonValue> resultHandler,
72+
SerializableConsumer<String> errorHandler);
73+
74+
/**
75+
* Adds an untyped handler that will be run for a successful execution. The
76+
* handler will be invoked asynchronously if the execution was successful.
77+
* In case of a failure, no handler will be run.
78+
* <p>
79+
* A handler can only be added before the execution has been sent to the
80+
* browser.
81+
*
82+
* @param resultHandler
83+
* a handler for the JSON representation of the return value from
84+
* a successful execution, not <code>null</code>
85+
*/
86+
default void then(SerializableConsumer<JsonValue> resultHandler) {
87+
then(resultHandler, null);
88+
}
89+
90+
}

src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigration.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
*/
2020
package com.flowingcode.vaadin.jsonmigration;
2121

22+
import com.vaadin.flow.component.page.PendingJavaScriptResult;
2223
import com.vaadin.flow.dom.DomEvent;
2324
import com.vaadin.flow.dom.Element;
2425
import com.vaadin.flow.server.Version;
2526
import elemental.json.JsonObject;
2627
import elemental.json.JsonValue;
28+
import java.io.Serializable;
2729
import java.lang.reflect.Method;
2830
import lombok.SneakyThrows;
2931

@@ -114,6 +116,22 @@ public static void setPropertyJson(Element element, String name, JsonValue json)
114116
invoke(Element_setPropertyJson, element, name, json);
115117
}
116118

119+
/**
120+
* Asynchronously runs the given JavaScript expression in the browser in the context of this
121+
* element.
122+
*
123+
* @param element the {@code Element} on which to run the JavaScript expression
124+
* @param expression the JavaScript expression to invoke
125+
* @param parameters parameters to pass to the expression
126+
* @return a pending result that can be used to get a value returned from the expression
127+
* @see Element#executeJs(String, Serializable...)
128+
*/
129+
public static ElementalPendingJavaScriptResult executeJs(Element element, String expression,
130+
Serializable... parameters) {
131+
PendingJavaScriptResult result = element.executeJs(expression, parameters);
132+
return helper.convertPendingJavaScriptResult(result);
133+
}
134+
117135
/**
118136
* Gets additional data related to the event.
119137
*

src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020
package com.flowingcode.vaadin.jsonmigration;
2121

22+
import com.vaadin.flow.component.page.PendingJavaScriptResult;
2223
import elemental.json.JsonValue;
2324

2425
import java.lang.reflect.Method;
@@ -29,5 +30,7 @@ interface JsonMigrationHelper {
2930
JsonValue convertToJsonValue(Object object);
3031

3132
Object invoke(Method method, Object instance, Object... args);
32-
33+
34+
ElementalPendingJavaScriptResult convertPendingJavaScriptResult(PendingJavaScriptResult result);
35+
3336
}

src/main/java/com/flowingcode/vaadin/jsonmigration/JsonMigrationHelper25.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121

2222
import java.lang.reflect.Method;
2323
import java.util.Arrays;
24+
import com.vaadin.flow.component.page.PendingJavaScriptResult;
25+
import com.vaadin.flow.function.SerializableConsumer;
2426
import elemental.json.Json;
2527
import elemental.json.JsonArray;
2628
import elemental.json.JsonObject;
2729
import elemental.json.JsonValue;
30+
import lombok.AllArgsConstructor;
2831
import lombok.NoArgsConstructor;
2932
import lombok.SneakyThrows;
3033
import tools.jackson.databind.JsonNode;
@@ -135,4 +138,28 @@ private static BaseJsonNode convertToJsonNode(JsonValue jsonValue) {
135138
}
136139
}
137140

141+
142+
@Override
143+
public ElementalPendingJavaScriptResult convertPendingJavaScriptResult(
144+
PendingJavaScriptResult result) {
145+
return new PendingJavaScriptResultImpl(result);
146+
}
147+
148+
@SuppressWarnings("serial")
149+
@AllArgsConstructor
150+
private static final class PendingJavaScriptResultImpl
151+
implements ElementalPendingJavaScriptResult {
152+
private final PendingJavaScriptResult delegate;
153+
154+
@SuppressWarnings({"unchecked", "rawtypes"})
155+
@Override
156+
public void then(SerializableConsumer<JsonValue> resultHandler,
157+
SerializableConsumer<String> errorHandler) {
158+
SerializableConsumer<JsonNode> wrappedHandler =
159+
node -> resultHandler.accept(convertToJsonValue(node));
160+
delegate.then((SerializableConsumer) wrappedHandler, errorHandler);
161+
}
162+
163+
}
164+
138165
}

src/main/java/com/flowingcode/vaadin/jsonmigration/LegacyJsonMigrationHelper.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@
1919
*/
2020
package com.flowingcode.vaadin.jsonmigration;
2121

22+
import com.vaadin.flow.component.page.PendingJavaScriptResult;
2223
import java.lang.reflect.Method;
2324
import elemental.json.JsonValue;
25+
import lombok.AllArgsConstructor;
2426
import lombok.NoArgsConstructor;
2527
import lombok.SneakyThrows;
28+
import lombok.experimental.Delegate;
2629

2730
@NoArgsConstructor
2831
class LegacyJsonMigrationHelper implements JsonMigrationHelper {
@@ -43,4 +46,18 @@ public Object invoke(Method method, Object instance, Object... args) {
4346
return method.invoke(instance, args);
4447
}
4548

49+
@Override
50+
public ElementalPendingJavaScriptResult convertPendingJavaScriptResult(
51+
PendingJavaScriptResult result) {
52+
return new PendingJavaScriptResultImpl(result);
53+
}
54+
55+
@SuppressWarnings("serial")
56+
@AllArgsConstructor
57+
private static final class PendingJavaScriptResultImpl
58+
implements ElementalPendingJavaScriptResult, PendingJavaScriptResult {
59+
@Delegate
60+
private final PendingJavaScriptResult delegate;
61+
}
62+
4663
}

0 commit comments

Comments
 (0)