Disabling annotation @Route("") in starter app exposes Vaadin internal file

In a new Vaadin 14.2.1 app downloaded from the Vaadin.com Starter page, choosing the Plain Java Servlet flavor, the app worked immediately. See screenshot attached.

I disabled the @Route("") annotation as I am not using the routing feature of Vaadin 14. When I run the app, the internal files of Vaadin and possibly my app are being served to the user as a directory listing. See screenshot attached in the following post below.

    package work.basil.example;
    
    import com.vaadin.flow.component.button.Button;
    import com.vaadin.flow.component.notification.Notification;
    import com.vaadin.flow.component.orderedlayout.VerticalLayout;
    import com.vaadin.flow.router.Route;
    import com.vaadin.flow.server.PWA;
    
    /**
     * The main view contains a button and a click listener.
     */
    //@Route("")
    @PWA(name = "Project Base for Vaadin", shortName = "Project Base")
    public class MainView extends VerticalLayout {
    
        public MainView() {
            Button button = new Button("Click me",
                    event -> Notification.show("Clicked!"));
            add(button);
        }
    }

Is this a feature or a bug, exposing internals?

Is the Routing feature mandatory in Vaadin 14?

17996661.png

Attached is screenshot of running app while @Route is commented-out.

Here is text of that browser window:

Directory: /
Name  ⇧	Last Modified	Size
icons/ 	Dec 13, 2019, 12:49:08 PM 	96 bytes 
client/ 	Dec 5, 2019, 2:34:52 PM 	 
clear.cache.gif 	Dec 5, 2019, 6:21:04 AM 	43 bytes 
client-EFB6081741306D23AA1BBFA6CFAA8504.cache.js 	Dec 5, 2019, 2:34:50 PM 	142,575 bytes 
client-EFB6081741306D23AA1BBFA6CFAA8504.cache.js.br 	Dec 5, 2019, 2:34:52 PM 	39,927 bytes 
client-EFB6081741306D23AA1BBFA6CFAA8504.cache.js.gz 	Dec 5, 2019, 2:34:52 PM 	46,724 bytes 
compile.properties 	Dec 5, 2019, 2:34:50 PM 	55 bytes 
flow-component-renderer.html 	Dec 5, 2019, 2:33:36 PM 	5,501 bytes 
flow-component-renderer.js 	Dec 5, 2019, 2:33:36 PM 	5,352 bytes 
dndConnector.js 	Dec 5, 2019, 2:33:48 PM 	3,125 bytes 
dndConnector-es6.js 	Dec 5, 2019, 2:33:48 PM 	29 bytes 
push/ 	Dec 5, 2019, 2:32:54 PM 	 
vaadinPush.js 	Dec 5, 2019, 2:32:54 PM 	142,222 bytes 
vaadinPush.js.gz 	Dec 5, 2019, 2:32:54 PM 	24,801 bytes 
vaadinPush-min.js 	Dec 5, 2019, 2:32:54 PM 	44,283 bytes 
vaadinPush-min.js.gz 	Dec 5, 2019, 2:32:54 PM 	13,294 bytes 
VAADIN/ 	Dec 5, 2019, 2:32:56 PM 	 
static/ 	Dec 5, 2019, 2:32:56 PM 	 
server/ 	Dec 5, 2019, 2:32:56 PM 	 
workbox/ 	Dec 5, 2019, 2:32:56 PM 	 
workbox-core.dev.js 	Dec 5, 2019, 2:32:56 PM 	57,939 bytes 
workbox-core.dev.js.map 	Dec 5, 2019, 2:32:56 PM 	59,798 bytes 
workbox-core.prod.js 	Dec 5, 2019, 2:32:56 PM 	7,118 bytes 
workbox-core.prod.js.map 	Dec 5, 2019, 2:32:56 PM 	7,302 bytes 
workbox-precaching.dev.js 	Dec 5, 2019, 2:32:56 PM 	38,102 bytes 
workbox-precaching.dev.js.map 	Dec 5, 2019, 2:32:56 PM 	39,394 bytes 
workbox-precaching.prod.js 	Dec 5, 2019, 2:32:56 PM 	5,573 bytes 
workbox-precaching.prod.js.map 	Dec 5, 2019, 2:32:56 PM 	5,742 bytes 
workbox-sw.js 	Dec 5, 2019, 2:32:56 PM 	1,465 bytes 
workbox-sw.js.map 	Dec 5, 2019, 2:32:56 PM 	1,605 bytes 
comboBoxConnector.js 	Nov 13, 2019, 12:41:42 PM 	13,587 bytes 
comboBoxConnector-es6.js 	Nov 13, 2019, 12:41:42 PM 	417 bytes 
contextMenuConnector.js 	Nov 21, 2019, 9:33:28 AM 	3,525 bytes 
contextMenuConnector-es6.js 	Nov 21, 2019, 9:33:28 AM 	319 bytes 
datepickerConnector.js 	Nov 15, 2019, 3:48:48 PM 	6,017 bytes 
gridConnector.js 	Nov 21, 2019, 9:54:30 AM 	37,231 bytes 
gridConnector-es6.js 	Nov 21, 2019, 9:54:30 AM 	590 bytes 
vaadin-grid-flow-selection-column.html 	Nov 21, 2019, 9:54:30 AM 	3,257 bytes 
vaadin-grid-flow-selection-column.js 	Nov 21, 2019, 9:54:30 AM 	3,757 bytes 
frontend/ 	Nov 14, 2019, 9:05:26 AM 	 
gridProConnector.js 	Nov 14, 2019, 9:05:26 AM 	1,345 bytes 
ironListConnector.js 	Jun 19, 2019, 6:58:06 AM 	6,093 bytes 
ironListConnector-es6.js 	Jun 19, 2019, 6:58:06 AM 	255 bytes 
ironListStyles.css 	Jun 19, 2019, 6:58:06 AM 	90 bytes 
ironListStyles.js 	Jun 19, 2019, 6:58:06 AM 	320 bytes 
menubarConnector.js 	Sep 30, 2019, 8:41:50 AM 	2,004 bytes 
selectConnector.js 	Oct 25, 2019, 11:37:26 AM 	785 bytes 
vaadin-big-decimal-field.js 	Nov 21, 2019, 11:19:10 AM 	1,874 bytes 
timepickerConnector.js 	Nov 15, 2019, 3:51:42 PM 	12,005 bytes 
webjars/ 	May 6, 2019, 10:40:04 AM 	 
mobile-drag-drop/ 	May 6, 2019, 10:40:04 AM 	 
2.3.0-rc.1/ 	May 6, 2019, 10:40:04 AM 	 
debug.css 	May 6, 2019, 10:40:06 AM 	1,154 bytes 
default.css 	May 6, 2019, 10:40:06 AM 	260 bytes 
icons.css 	May 6, 2019, 10:40:06 AM 	13,387 bytes 
index.d.ts 	May 6, 2019, 10:40:06 AM 	947 bytes 
index.js 	May 6, 2019, 10:40:06 AM 	31,187 bytes 
index.js.map 	May 6, 2019, 10:40:06 AM 	95,183 bytes 
index.min.js 	May 6, 2019, 10:40:06 AM 	10,426 bytes 
index.min.js.map 	May 6, 2019, 10:40:06 AM 	86,722 bytes 
constants.d.ts 	May 6, 2019, 10:40:06 AM 	570 bytes 
dom-utils.d.ts 	May 6, 2019, 10:40:06 AM 	1,192 bytes 
drag-data-store.d.ts 	May 6, 2019, 10:40:06 AM 	803 bytes 
drag-operation-controller.d.ts 	May 6, 2019, 10:40:06 AM 	1,283 bytes 
drag-utils.d.ts 	May 6, 2019, 10:40:06 AM 	580 bytes 
feature-detection.d.ts 	May 6, 2019, 10:40:06 AM 	255 bytes 
package.json 	May 6, 2019, 10:40:06 AM 	2,088 bytes 
scroll-behaviour.d.ts 	May 6, 2019, 10:40:06 AM 	309 bytes 
scroll-behaviour.js 	May 6, 2019, 10:40:06 AM 	7,715 bytes 
scroll-behaviour.js.map 	May 6, 2019, 10:40:06 AM 	18,358 bytes 
scroll-behaviour.min.js 	May 6, 2019, 10:40:06 AM 	2,456 bytes 
scroll-behaviour.min.js.map 	May 6, 2019, 10:40:06 AM 	16,582 bytes 
vaadin__vaadin-mobile-drag-drop/ 	May 6, 2019, 2:07:22 PM 	 
1.0.0/ 	May 6, 2019, 2:07:22 PM 	 
.babelrc 	May 6, 2019, 2:07:22 PM 	35 bytes 
bower.json 	May 6, 2019, 2:07:22 PM 	601 bytes 
index.js 	May 6, 2019, 2:07:22 PM 	1,676 bytes 
index.min.js 	May 6, 2019, 2:07:22 PM 	1,388 bytes 
LICENSE 	May 6, 2019, 2:07:22 PM 	10,756 bytes 
package.json 	May 6, 2019, 2:07:22 PM 	998 bytes 
README.md 	May 6, 2019, 2:07:22 PM 	847 bytes 
wct.conf.json 	May 6, 2019, 2:07:22 PM 	84 bytes 

17996669.png

Basil,

That is defined behaviour. If there is no @Route, it will use classnames.

See https://vaadin.com/docs/v14/flow/routing/tutorial-routing-annotation.html

I don’t know it that can be disabled.

I think the directory listing is a standard jetty thing, and this SO shows how to disable it: https://stackoverflow.com/questions/7217969/how-to-disable-directory-listing-for-jettys-webappcontext

In Vaadin 14 you can also register your routes dynamically: https://vaadin.com/docs/v14/flow/routing/tutorial-router-dynamic-routes.html

If you don’t want to use any of the inbuilt routing features at all, then you’d have to create and register your own servlet which defines your own custom UI public class MyCustomUI extends UI {...}. There overriding the init method, you can set your own history state change handler https://vaadin.com/docs/v14/flow/advanced/tutorial-history-api.html#handling-user-navigation that makes it possible to not have any routes but instead do something else.

There might be some other extension points too to not use the routing features or customize the behavior, but before going further, I would still like to know why (oh why) would you do that ? :slight_smile:

Pekka Hyvönen:

There might be some other extension points too to not use the routing features or customize the behavior, but before going further, I would still like to know why (oh why) would you do that ? :slight_smile:

Thanks for your helpful answers.

As for why one would want to avoid the Routing feature in Vaadin 14, I have found it to be quite problematic.

See:
https://duckduckgo.com/?q=%2Bbasil+%2Brouting+%2Bvaadin&t=ffab&atb=v197-1__&ia=web

Thanks for the clarification Basil.

We had not seen the issue with not retaining the UI object as such an important thing, which in hindsight was an mistake. Technically “recreating the UI object” in the @PreserveOnRefresh case does not really have any extra cost (from framework perspective) as it is just an object on server side.
Since V10, the UI is always created during the first round-trip, unless @PreserveOnRefresh is used. In V7 and V8 the bootstrap is always two-phased regardless of @PreserveOnRefresh, meaning that things are created or retained after the second round-trip.

But, I understand the cost for application developer convenience and being able to retain behavior similar to V7 & V8, I’ll try to see if we can make sure https://github.com/vaadin/flow/issues/6395 could get squeezed in into Flow 2.2 and thus 14.2.

I still would like to say that rather than forcing all applications to use the UI as some sort of a data store and instead of not using the framework routing at all, I would rather work on improving it than thinking about ways to circumvent it. One concrete thing we have not done, but foresaw needing, was https://github.com/vaadin/flow/issues/965 which would replace some parts of the old UI.init and whatever else was stored there. PageConfigurator does some parts of that, but not all. This has not been requested directly, but I think on some level the lack of this concept causes the inconveniences you have run into. And this is more than just having an object recreated.

I would like to confirm current confusion about UI scope. I’m glad I don’t rely on it as much as Basil does but I’d be glad to see issue #6395 triaged again. There hasn’t been extensive discussion about this or a clear explanation why the current path with UI scope was chosen for vaadin flow and how to handle these changes when coming from a V8 application that made use of the ui scope.

Kaspar Scherrer:
…I’m glad I don’t rely on it as much as Basil …

Without a reliable UI instance, how do you maintain per-window/tab state? What other strategy might you suggest for reliably creating/maintaining/disposing of such state that is neither per-app/service nor per-session since one session can have multiple separate windows/tabs?

Basil Bourque:
Without a reliable UI instance, how do you maintain per-window/tab state?

In my case, I simply don’t. I am lucky enough to not have an application that requires (or encourages) multiple tabs. Any state that I am tracking is view specific and can be stored in that view, instead of the UI. I don’t have any states that need to be kept between any view changes. I would’ve used the UI to prevent exposure of item id’s as discussed in and below [this SO thread]
(https://stackoverflow.com/a/57603924/3441504).

If I had the need of keeping states between views, then I’d be looking for a good alternative as well just like you seem to be doing. I want the UI to be able to store tab/window specific states between views again so any future Vaadin application I write doesn’t have these restrictions anymore.