vaadin / flow

Vaadin Flow is a Java framework binding Vaadin web components to Java. This is part of Vaadin 10+.
Apache License 2.0
619 stars 167 forks source link

Hotswap exception when updating a route class with matching Route and RouteAlias #19972

Closed Artur- closed 1 month ago

Artur- commented 1 month ago

Description of the bug

When modifying this class from a starter project

@PageTitle("Hello World")
@Route(value = "", layout = MainLayout.class)
@RouteAlias(value = "", layout = MainLayout.class)
public class HelloWorldView extends HorizontalLayout {

    private TextField name;
    private Button sayHello;

    public HelloWorldView() {
        name = new TextField("Your name29");

by changing the "name29" text, the hotswap operation does not complete but throws the following exception. As a result, the view in the browser is not updated without a manual refresh

com.vaadin.flow.server.AmbiguousRouteConfigurationException: Navigation targets must have unique routes, found navigation targets 'com.example.application.views.helloworld.HelloWorldView' and 'com.example.application.views.helloworld.HelloWorldView' with the same route.
    at com.vaadin.flow.router.internal.RouteSegment.ambigousException(RouteSegment.java:806)
    at com.vaadin.flow.router.internal.RouteSegment.ambigousTarget(RouteSegment.java:801)
    at com.vaadin.flow.router.internal.RouteSegment.setRouteTarget(RouteSegment.java:487)
    at com.vaadin.flow.router.internal.RouteSegment.addSubRoute(RouteSegment.java:458)
    at com.vaadin.flow.router.internal.RouteSegment.addSubRoute(RouteSegment.java:267)
    at com.vaadin.flow.router.internal.RouteModel.addRoute(RouteModel.java:130)
    at com.vaadin.flow.router.internal.ConfigureRoutes.setRoute(ConfigureRoutes.java:175)
    at com.vaadin.flow.router.internal.AbstractRouteRegistry.lambda$setRoute$2df6994$1(AbstractRouteRegistry.java:406)
    at com.vaadin.flow.router.internal.AbstractRouteRegistry.lambda$configureWithFullTemplate$ccc9e4ad$1(AbstractRouteRegistry.java:457)
    at com.vaadin.flow.router.internal.AbstractRouteRegistry.configure(AbstractRouteRegistry.java:120)
    at com.vaadin.flow.router.internal.AbstractRouteRegistry.configureWithFullTemplate(AbstractRouteRegistry.java:456)
    at com.vaadin.flow.router.internal.AbstractRouteRegistry.setRoute(AbstractRouteRegistry.java:404)
    at com.vaadin.flow.server.startup.ApplicationRouteRegistry.setRoute(ApplicationRouteRegistry.java:130)
    at com.vaadin.flow.router.RouteConfiguration.setAnnotatedRoute(RouteConfiguration.java:231)
    at com.vaadin.flow.router.internal.RouteUtil.lambda$updateRouteRegistry$14(RouteUtil.java:520)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
    at java.base/java.util.stream.DistinctOps$1$2.accept(DistinctOps.java:174)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
    at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1715)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310)
    at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
    at com.vaadin.flow.router.internal.RouteUtil.lambda$updateRouteRegistry$923b90d8$1(RouteUtil.java:515)
    at com.vaadin.flow.router.internal.AbstractRouteRegistry.update(AbstractRouteRegistry.java:131)
    at com.vaadin.flow.router.internal.RouteUtil.updateRouteRegistry(RouteUtil.java:503)
    at com.vaadin.flow.router.internal.RouteRegistryHotswapper.onClassLoadEvent(RouteRegistryHotswapper.java:68)
    at com.vaadin.flow.hotswap.Hotswapper.onHotswapInternal(Hotswapper.java:194)
    at com.vaadin.flow.hotswap.Hotswapper.onHotswap(Hotswapper.java:136)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)

Expected behavior

It works

Minimal reproducible example

npm init vaadin@latest "Debug using HotswapAgent" in IntelliJ Modify the view

Versions

Hilla: 24.5-SNAPSHOT Flow: 24.5-SNAPSHOT Vaadin: 24.5-SNAPSHOT Copilot: 24.5-SNAPSHOT Frontend Hotswap: Disabled, using pre-built bundle OS: aarch64 Mac OS X 14.6.1 Java: JetBrains s.r.o. 21.0.3 Browser: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Java Hotswap: false IDE Plugin: ☑ 1.0.0.eap42

mcollovati commented 1 month ago

Does it fail even if @Route and @RouteAlias have different paths?

Artur- commented 1 month ago

An excellent question, and I wonder why they have the same path. It does seem to be related to that. If I remove the route alias, there is no exception. It still does not refresh the browser but that seems to be caused by something else

Artur- commented 1 month ago

19973 is the lack of update problem

Artur- commented 1 month ago

Does it fail even if @Route and @RouteAlias have different paths?

Seems like it only fails if the paths are the same

mcollovati commented 1 month ago

Having the same value for route and alias seems to be invalid. Unfortunately, currently, the exception is suppressed at startup. The route validation on startup should fail if it detects such a configuration. Also, starter projects should be fixed to prevent generating views with conflicting annotations

Artur- commented 1 month ago

I will fix the starters. The real problem we are seeing seems to be #19973

vaadin-bot commented 1 month ago

This ticket/PR has been released with Vaadin 24.5.0.beta2 and is also targeting the upcoming stable 24.5.0 version.

vaadin-bot commented 1 month ago

This ticket/PR has been released with Vaadin 23.5.7.

vaadin-bot commented 1 month ago

This ticket/PR has been released with Vaadin 24.4.13.