Indirect Vaadin Class initialization causes fields to not appear
See original GitHub issueDescription
In certain situations, fields simply do not appear.
Expected outcome
This is what I expect to see:
Actual outcome
This is what I actually see:
Note the TextField
is not visible. It appears in the HTML DOM but note there is a difference in the <vaadin-text-field>
element.
Minimal reproducible example
https://github.com/archiecobbs/vaadin-flow-bugs/tree/InvisibleTextField
The key is this code:
private Component buildNameField() throws Exception {
//return new com.vaadin.flow.component.textfield.TextField(); // this works!
return (Component)Class.forName("com.vaadin.flow.component.textfield.TextField").newInstance(); // this doesn't!
}
What I’ve found is that if my class file has a reference to TextField
, which would cause that class to be loaded when my class is resolved, the problem does not occur. On the other hand if, as is shown in the code above, my class causes the loading of TextField
to be delayed until the last possible moment, then this bug occurs.
Obviously this is a bug, caused by some kind of class initialization race condition in Vaadin.
The code above is of course a contrived example. In the real world the problem was discovered while trying to use a internal tool kit that automatically constructs Vaadin forms based on specifications.
Steps to reproduce
$ git clone git@github.com:archiecobbs/vaadin-flow-bugs.git
$ cd vaadin-flow-bugs
$ git checkout InvisibleTextField
$ mvn package jetty:run
Then point your web browser at http://localhost:8090/demo/
Environment
Vaadin 22.0.9 MacOS 12.1 Firefox 98.0.1 Java 8
Browsers Affected
- Chrome
- Firefox
- Safari
- Edge
- IE 11
- iOS Safari
- Android Chrome
Haven’t tested the others.
Issue Analytics
- State:
- Created 2 years ago
- Comments:10 (7 by maintainers)
Top GitHub Comments
@TatuLund,
You are responding with facts - thanks - but I think you’re missing a larger point here.
I don’t think you guys appreciate how frustrating you make things for Java developers sometimes. I’ve seen this since the Vaadin 6.x/7.x days. Vaadin is too focused on HTML/CSS and not enough focused on Java/enterprise.
This bug is a perfect example. You have created a completely undocumented “booby trap”. The manifestation of this bug is completely mysterious - it’s virtually impossible to debug for anyone who is unaware of the internals of how the Maven plugin works.
The only Vaadin widgets that will ever work in your application are the ones the Maven plugin is able to detect.
Why wouldn’t you mention something so important in your standard documentation? Did it not ever occur to you that someday someone might import a library that creates a
TextField
, instead of creating one directly?Moreover, why wouldn’t you have Vaadin throw a
RuntimeException
if ever someone tries to create aTextField
when the templates and other resources used byTextField
were not included in the build??? This seems so simple and obvious and would save developers countless hours of hair pulling. Instead, you just go ahead and create an empty, useless HTML tag that does nothing and serves only to confuse and frustrate.To me these things are just basic and obvious and I just have to shake my head. I guess we just come from different perspectives.
You should probably include a paragraph or two describing how the build process works. This must certainly describe how the only widgets that will actually work at runtime are the ones that the Maven plugin can detect.
Moreover, the
@Uses
mechanism does not address imported libraries. We need to solve this problem somehow. Here are a couple of options:@Uses
tags. This would be simplest for the user. The build would be slower but probably not by much - the dependent JAR files are probably already being read during the build for other reasons anyway.META-INF/vaadin/uses.xml
or something that allows imported libraries to explicitly list what they use, and scan for these during the build. This is more work for users but would be faster than #1. Add documentation to the manual that library code JAR files should include such a file.Of course you could do both #1 and #2.
In any case, you should immediately implement the
RuntimeException
mentioned above to stop the bleeding:I noted that with spring-boot you can start the server with
mvn spring-boot:start
which will not execute the test compile, but usingmvn jetty:start
will not leave the server up after maven exits