webforj / webforj

webforJ is a robust and flexible web framework that allows you to easily create a modern and engaging user interface using Java.
https://documentation.webforj.com
MIT License
38 stars 8 forks source link

[BUG] Setting a component to a slot with an existing component causes app termination #758

Closed bbrennanbasis closed 1 month ago

bbrennanbasis commented 1 month ago

Description

Using the setPrefixComponent() method in webforJ 24.11 on a component with an existing prefix component causes app termination.

This behavior does not match with the description of the method from the javadocs, "If a prefix component is already set, then the old prefix component will be destroyed and replaced with the new one."

To reproduce

Add the following snippet to a program and click the [test] button.

    Button btn = new Button("test");

    Icon oldPrefix = TablerIcon.create("abc");
    Icon newPrefix = TablerIcon.create("alien");

    btn.setPrefixComponent(oldPrefix);

    btn.addClickListener(e ->{
      btn.setPrefixComponent(newPrefix);
    });

Expected behavior

I expected to see the abc icon replaced with the alien icon after pressing the button.

Actual behavior

When you use setPrefixComponent() again (pressing the button), the app terminates and outputs an error message. I've copied that message in the Browser console output section.

Workaround

Manually destroying the old prefix component before using setPrefixComponent() again produces the expected behavior.

btn.getPrefixComponent().destroy();
btn.setPrefixComponent(newPrefix);

Additional context This issue also occurs when using the setPrefixComponent() method.

Browser console output VM603:1 java.util.ConcurrentModificationException at java.base/java.util.ArrayList.forEach(ArrayList.java:1598) at com.webforj.component.SlotRegistry.removeSlot(SlotRegistry.java:107) at com.webforj.component.SlotRegistry.replaceComponentsInSlot(SlotRegistry.java:77) at com.webforj.component.SlotAssigner.assignComponentToSlot(SlotAssigner.java:195) at com.webforj.component.SlotAssigner.reAssign(SlotAssigner.java:141) at com.webforj.component.DwcComponent.setPrefixComponent(DwcComponent.java:1082) at com.webforj.component.button.DwcButton.setPrefixComponent(DwcButton.java:189) at main.java.samples.test.lambda$run$f54ec5f9$1(test.java:24) at com.webforj.dispatcher.EventDispatcher.dispatchEvent(EventDispatcher.java:155) at com.webforj.dispatcher.EventDispatcher.dispatchEvent(EventDispatcher.java:169) at com.webforj.component.button.sink.ButtonClickEventSink.handleEvent(ButtonClickEventSink.java:38) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at com.basis.startup.LoadLibrary.invokeMethodInContext(LoadLibrary.java:4) at com.basis.util.common.security.aa$b.invokeMethod(aa$b.java:21) at com.basis.bbj.processor.program.type.JavaType$JavaMethod.invoke(JavaType.java:2) at com.basis.bbj.processor.program.type.SignatureHandler.dispatch(SignatureHandler.java:362) at com.basis.bbj.processor.program.type.JavaType$JavaSignature.dispatch(JavaType.java:5) at com.basis.bbj.processor.program.type.SignatureHandler.handleSignature(SignatureHandler.java:10) at com.basis.bbj.processor.instruction.a.k.a(k.java:109) at com.basis.bbj.processor.instruction.a.k.a(k.java:15) at com.basis.bbj.processor.instruction.ed.a(ed.java:5) at com.basis.bbj.processor.instruction.c.bw.O(bw.java:2432) at com.basis.bbj.processor.instruction.c.bw.L(bw.java:2815) at com.basis.bbj.processor.instruction.c.bw.a(bw.java:502) at com.basis.bbj.generated.invoke.InvokeMethod.invoke(InvokeMethod.java:91) at com.basis.bbj.generated.CustomObjectInterpreterBridgeImpl.invokeMethod(CustomObjectInterpreterBridgeImpl.java:17) at com.basis.bbj.generated.CustomObjectHelper.invokeMethod(CustomObjectHelper.java:5) at com.basis.bbj.generated.dynamic.customobject.LUM6L2JieC9wbHVnaW5zL0RXQ0ovZGVwbG95bWVudHMvd2ViZm9yai1oZWxsby13b3JsZC0xLjAtU05BUFNIT1QvYmJqL1dlYmZvcmpIZWxwZXIuYmJq.BBjEventProxy.onEvent(Unknown Source) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at com.basis.startup.LoadLibrary.invokeMethodInContext(LoadLibrary.java:4) at com.basis.util.common.security.aa$b.invokeMethod(aa$b.java:21) at com.basis.bbj.processor.program.type.JavaType$JavaMethod.invoke(JavaType.java:2) at com.basis.bbj.processor.program.type.SignatureHandler.dispatch(SignatureHandler.java:362) at com.basis.bbj.processor.program.type.JavaType$JavaSignature.dispatch(JavaType.java:5) at com.basis.bbj.processor.program.type.SignatureHandler.handleSignature(SignatureHandler.java:10) at com.basis.bbj.processor.o$h.dispatch(o$h.java:6) at com.basis.bbj.processor.instruction.c.a$a.a(a$a.java:68) at com.basis.bbj.processor.instruction.c.a$a.visitUserObjectCallback(a$a.java:38) at com.basis.bbj.iris.facade.event.UserObjectCallbackHelper$UserObjectCallback.accept(UserObjectCallbackHelper.java:2) at com.basis.bbj.processor.instruction.c.a$a.a(a$a.java:35) at com.basis.bbj.processor.instruction.c.a.a(a.java:3) at com.basis.bbj.processor.instruction.c.bw.O(bw.java:2432) at com.basis.bbj.processor.instruction.c.bw.L(bw.java:2815) at com.basis.bbj.processor.instruction.c.bw.run(bw.java:291) at com.basis.util.common.BasisThread.run(BasisThread.java:47)