vaadin / flow

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

Adding Java tags/attributes for Vaadin-Form-Item causes exception #4347

Closed martinisraelsen closed 6 years ago

martinisraelsen commented 6 years ago

Adding a tag/java attribute for a Vaadin-Form-Item in the Bakery-App causes a exception to be thrown:

Constructor threw exception; nested exception is java.lang.IllegalArgumentException: A component specified to use a confirm-dialog element cannot use an element with tag name vaadin-form-item

Step to reproduce:

Not sure if this is a flow issue or bakery-app issue, however it also occurs in our own app which uses several patterns from bakery-app.,

Seen in Flow 10.0.1

Full stack trace.txt

martinisraelsen commented 6 years ago

Update: It seems to only happen when the form is polymer template. Recreating the same form using Java class does not result in the exception.

Legioth commented 6 years ago

This is actually caused by a bug in Designer which makes it to use the wrong types for the @Id instance field that it creates in the Java code. That issue is tracked in https://github.com/vaadin/designer/issues/1807.

It might be possible to fix the problem by manually changing the @Id instance field to have the right type, e.g. FormItem in the example you're describing.

martinisraelsen commented 6 years ago

@Legioth Thanks for the comment. Just FYI - in this case the Java type looks correct. The designer is inserting FormItem, yet the exception still occurs.

@Id("myformitem") private FormItem myFormItem;

Legioth commented 6 years ago

In that case, there's something else that makes it attempt creating an bc.ui.components.ConfirmDialog instance as the Java component for an element that is defined as < vaadin-form-item> in the template.

Could there be multiple instance fields with the same @Id value? Could there be something on the Spring side that makes it create a bean of type ConfirmDialog even though Flow asks for an instance of FormItem?

It might be possible to find out more details by adding a breakpoint on the line that throws the actual exception and then checking the values of the id and field arguments to the TemplateInitializer.attachExistingElementById method that should a bit further down in the call stack. Could also be good to verify that the element local variable in that method is actually corresponding to the right element from the template.

martinisraelsen commented 6 years ago

@Legioth I tried to remove the ConfirmDialog completely and then got another exception:

Caused by: java.lang.IllegalArgumentException: A component specified to use a account-form element cannot use an element with tag name vaadin-form-item at com.vaadin.flow.component.Component.mapToElement(Component.java:167) ~[flow-server-1.0.0.jar:na] at com.vaadin.flow.component.Component.<init>(Component.java:112) ~[flow-server-1.0.0.jar:na] at com.vaadin.flow.component.polymertemplate.AbstractTemplate.<init>(AbstractTemplate.java:36) ~[flow-server-1.0.0.jar:na] at com.vaadin.flow.component.polymertemplate.PolymerTemplate.<init>(PolymerTemplate.java:96) ~[flow-server-1.0.0.jar:na] at com.vaadin.flow.component.polymertemplate.PolymerTemplate.<init>(PolymerTemplate.java:112) ~[flow-server-1.0.0.jar:na] at bc.ui.views.admin.accounts.AccountForm.<init>(AccountForm.java:91) ~[classes/:na] at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_171] at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_171] at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_171] at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_171] at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:170) ~[spring-beans-5.0.6.RELEASE.jar:5.0.6.RELEASE] ... 182 common frames omitted

So I created a completely new view in the "blank" spring-starter project with a single form item and the exception happens there too, but with a different message:

There was an exception while trying to navigate to 'formitemview' with the exception message 'Error creating bean with name 'bc.spring.FormItemView': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [bc.spring.FormItemView]: Constructor threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.vaadin.flow.component.formlayout.FormLayout$FormItem': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.vaadin.flow.component.Component[]' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}'

I've attached a simple app to demonstrate it. Launch and go to localhost:8080. The view will show. Next remove the comments for

@Id("nameFormItem") private FormItem vaadinFormItem; and go to localhost:8080 and the exception will occur.

Vaadin10-Spring-Starter.zip

Legioth commented 6 years ago

That new error message is more helpful. The problem is that FormItem is incompatible with @Id because it doesn't have a no-arg constructor. I created https://github.com/vaadin/vaadin-form-layout-flow/issues/53 to track this issue since this ticket is full of debugging information that turned out to not be directly relevant.

You should be able to work around the problem for now by creating your own simple MyFormItem extends FormItem class that defines a no-args constructor, and then changing your @Id definition to use that class instead.