Skip to content

Commit 8ede1c7

Browse files
fix: Use String type for Style.bind return value (#23888) (#23889)
Change `Style.bind(String, Signal<String>)` return type from `SignalBinding<?>` to `SignalBinding<String>` since the method always accepts a `Signal<String>` and we always know the value type is String. This provides better type safety and eliminates the need for casts when using the binding's `onChange` callbacks. Co-authored-by: Mikhail Shabarov <61410877+mshabarov@users.noreply.github.com>
1 parent 94cb7b3 commit 8ede1c7

File tree

5 files changed

+32
-7
lines changed

5 files changed

+32
-7
lines changed

flow-server/src/main/java/com/vaadin/flow/dom/Style.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ public interface Style extends Serializable {
233233
*
234234
* @since 25.0
235235
*/
236-
default SignalBinding<?> bind(String name, Signal<String> signal) {
236+
default SignalBinding<String> bind(String name, Signal<String> signal) {
237237
// experimental API, do not force implementation
238238
throw new UnsupportedOperationException();
239239
};

flow-server/src/main/java/com/vaadin/flow/dom/impl/BasicElementStyle.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public Stream<String> getNames() {
9898
}
9999

100100
@Override
101-
public SignalBinding<?> bind(String name, Signal<String> signal) {
101+
public SignalBinding<String> bind(String name, Signal<String> signal) {
102102
ElementUtil.validateStylePropertyName(name);
103103
String attribute = StyleUtil.stylePropertyToAttribute(name);
104104
Element owner = Element.get(propertyMap.getNode());

flow-server/src/main/java/com/vaadin/flow/dom/impl/ImmutableEmptyStyle.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public Stream<String> getNames() {
7070
* to a style property,
7171
*/
7272
@Override
73-
public SignalBinding<?> bind(String name, Signal<String> signal) {
73+
public SignalBinding<String> bind(String name, Signal<String> signal) {
7474
throw new UnsupportedOperationException(CANT_MODIFY_MESSAGE);
7575
}
7676
}

flow-server/src/main/java/com/vaadin/flow/internal/nodefeature/AbstractPropertyMap.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,12 +181,14 @@ public void updateFromClient(String key, Serializable value) {
181181
* @param writeCallback
182182
* the callback to propagate value changes back, or
183183
* <code>null</code> for a read-only binding
184+
* @param <T>
185+
* the type of the signal value
184186
* @throws com.vaadin.flow.signals.BindingActiveException
185187
* thrown when there is already an existing binding for the
186188
* given property
187189
*/
188-
public SignalBinding<?> bindSignal(Element owner, String name,
189-
Signal<?> signal, SerializableConsumer<?> writeCallback) {
190+
public <T> SignalBinding<T> bindSignal(Element owner, String name,
191+
Signal<T> signal, SerializableConsumer<?> writeCallback) {
190192
return super.bindSignal(owner, name, signal,
191193
(element, value) -> setPropertyFromSignal(name, value),
192194
writeCallback);

flow-server/src/test/java/com/vaadin/flow/dom/StyleBindTest.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import static org.junit.jupiter.api.Assertions.assertEquals;
3030
import static org.junit.jupiter.api.Assertions.assertFalse;
31+
import static org.junit.jupiter.api.Assertions.assertNotNull;
3132
import static org.junit.jupiter.api.Assertions.assertNull;
3233
import static org.junit.jupiter.api.Assertions.assertThrows;
3334
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -182,7 +183,7 @@ public void bind_onChange_receivesBindingContext() {
182183
UI.getCurrent().getElement().appendChild(element);
183184

184185
ValueSignal<String> signal = new ValueSignal<>("red");
185-
List<BindingContext<?>> contexts = new ArrayList<>();
186+
List<BindingContext<String>> contexts = new ArrayList<>();
186187

187188
element.getStyle().bind("background-color", signal)
188189
.onChange(contexts::add);
@@ -193,11 +194,33 @@ public void bind_onChange_receivesBindingContext() {
193194
signal.set("blue");
194195

195196
assertEquals(2, contexts.size());
196-
BindingContext<?> ctx = contexts.get(1);
197+
BindingContext<String> ctx = contexts.get(1);
197198
assertFalse(ctx.isInitialRun());
198199
assertEquals("red", ctx.getOldValue());
199200
assertEquals("blue", ctx.getNewValue());
200201
assertEquals(element, ctx.getElement());
201202
}
202203

204+
@Test
205+
public void bind_returnsTypedSignalBinding() {
206+
Element element = new Element("div");
207+
UI.getCurrent().getElement().appendChild(element);
208+
209+
ValueSignal<String> signal = new ValueSignal<>("red");
210+
211+
// Verify that bind returns SignalBinding<String>
212+
SignalBinding<String> binding = element.getStyle()
213+
.bind("background-color", signal);
214+
215+
// Verify that we can use the typed binding with String context
216+
binding.onChange(ctx -> {
217+
String oldValue = ctx.getOldValue(); // No cast needed
218+
String newValue = ctx.getNewValue(); // No cast needed
219+
assertNotNull(oldValue);
220+
assertNotNull(newValue);
221+
assertEquals(String.class, oldValue.getClass());
222+
assertEquals(String.class, newValue.getClass());
223+
});
224+
}
225+
203226
}

0 commit comments

Comments
 (0)