Autowire by constructor fails

Hello. I’m trying to update my app to 10’th vaadin and can’t inject my data beans by constructor in components annotated @Route, such as the one below.

@Route()
public class MainView extends Div {

	@Autowired
    public MainView(RequestDataProvider requestDataProvider, UserService userService) {
	...

I’m getting error:

There was an exception while trying to navigate to 'test' with the exception message 'Unable to create an instance of 'useradmin.views.MainView'. Make sure the class has a public no-arg constructor.'

If I add the no-arg constructor spring creates bean and then vaadin creates it’s own copy of component. It seems to me vaadin doesn’t understand that i use spring) So it enables the default mechainsim of processing ui components.

The initializer i copypasted form the documentation and added context.register(SpringConfig.class); which refers to this simple configuration:

@Configuration
@EnableVaadin
@ComponentScan(basePackages = {"useradmin"})
public class SpringConfig {
}

You are missing Vaadin Spring add-on, or some annotation somewhere. I would recommend to use our Spring Boot project base starter https://vaadin.com/start/v10-project-base-spring and start developing your application on top of that.

Hello!

I have the same error message with Vaadin’s 10 sample project https://vaadin.com/start/v10-project-base-spring. I have used all default settings, nothing to change, default Apache Tomcat settings under Debian Linux. Sample project started well under IntelliJ IDEA environment, but I got ‘Unable to create an instance of ‘ru.mail.artem.spring.MainView’. Make sure the class has a public no-arg constructor.’ in browser after a creating war package and deploying it under Tomcat.

I have a solution. This is an original constructor from Vaadin Flow example which doesn’t work:

  public MainView(@Autowired ExampleTemplate template) {
        // This is just a simple label created via Elements API
        Button button = new Button("Click me",
                event -> template.setValue("Clicked!"));
        // This is a simple template example
        add(button, template);
        setClassName("main-layout");
    }

But all works fine with Apache Tomcat when I replace this constructor with:

public MainView() {
    add(new Button("Click me", e -> Notification.show("Hello Spring+Vaadin user!")));
}

Hello,

I have exactly the same problem using the given example and a Tomcat Server.

Please could someone bring any solution to this ?

Note that it works when you execute mvn spring-boot:run but not when you deploy the built war into Tomcat

@Artem Shabalin this is not a viable solution.

Hello,

I just set up the starterproject “Project Base with Spring” and deployed it on a tomcat and get this error.
Is there any solution or how do people work with that? Is no one using the starterprojects…?

There was an exception while trying to navigate to '' with the exception message 'Unable to create an instance of 'de.web.michail.spring.MainView'. Make sure the class has a public no-arg constructor.'
java.lang.IllegalArgumentException: Unable to create an instance of 'de.web.michail.spring.MainView'. Make sure the class has a public no-arg constructor.
	at com.vaadin.flow.internal.ReflectTools.createProxyInstance(ReflectTools.java:515)
	at com.vaadin.flow.internal.ReflectTools.createInstance(ReflectTools.java:447)
	at com.vaadin.flow.di.DefaultInstantiator.getOrCreate(DefaultInstantiator.java:65)
	at com.vaadin.flow.di.Instantiator.createRouteTarget(Instantiator.java:158)
	at com.vaadin.flow.router.internal.AbstractNavigationStateRenderer.lambda$getRouteTarget$1(AbstractNavigationStateRenderer.java:116)
	at java.base/java.util.Optional.orElseGet(Optional.java:358)
	at com.vaadin.flow.router.internal.AbstractNavigationStateRenderer.getRouteTarget(AbstractNavigationStateRenderer.java:115)
	at com.vaadin.flow.router.internal.AbstractNavigationStateRenderer.handle(AbstractNavigationStateRenderer.java:167)
	at com.vaadin.flow.router.Router.handleNavigation(Router.java:221)
	at com.vaadin.flow.router.Router.navigate(Router.java:192)
	at com.vaadin.flow.router.Router.initializeUI(Router.java:95)
	at com.vaadin.flow.server.BootstrapHandler.createAndInitUI(BootstrapHandler.java:1117)
	at com.vaadin.flow.server.BootstrapHandler.synchronizedHandleRequest(BootstrapHandler.java:396)
	at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40)
	at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1533)
	at com.vaadin.flow.server.VaadinServlet.service(VaadinServlet.java:227)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1135)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:844)

Application.java has to extend SpringBootServletInitializer:

public class Application extends SpringBootServletInitializer {
 // ...
}

extending SpringBootServletInitializer helped. Thank you very much!

@Vaadin: this should be fixed in Project Base for Vaadin Flow and Spring!?

I am running into the same issue! I do already have an Application class (@SpringBootApplication) which extends SpringBootServletInitializer.

locally everything works fine…

Have you found a solution to this? (that doesn’t involve SpringBootServletInitializer because I have this already)

For those still having issues with this here is an alternative solution:

@Route("")
public class MainView extends Div {
	
	@Autowired
	protected UserService userService;
	
	public MainView() {
		// dont do any calls to userService yet
		super();
	}
	
	public void init() {
		add(new Button("Click me", e -> Notification.show("Hello Spring+Vaadin user!")));

		// safe to call userService
		List<User> users = userService.getUsers(); // this should no longer fail as userService should be wired
	}
	
	@Override
	protected void onAttach(AttachEvent attachEvent) {
		// this is the key method to get the view to autowire
		
		ServletContext servletContext = VaadinServlet.getCurrent().getServletContext();
		WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext).getAutowireCapableBeanFactory()
				.autowireBean(this);
				
		// now lets continue with setup and safe to call any autowires
		init();
	}
	
}

Fernando Ruedas:
For those still having issues with this here is an alternative solution:

@Route("")
public class MainView extends Div {
	
	@Autowired
	protected UserService userService;
	
	public MainView() {
		// dont do any calls to userService yet
		super();
	}
	
	public void init() {
		add(new Button("Click me", e -> Notification.show("Hello Spring+Vaadin user!")));

		// safe to call userService
		List<User> users = userService.getUsers(); // this should no longer fail as userService should be wired
	}
	
	@Override
	protected void onAttach(AttachEvent attachEvent) {
		// this is the key method to get the view to autowire
		
		ServletContext servletContext = VaadinServlet.getCurrent().getServletContext();
		WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext).getAutowireCapableBeanFactory()
				.autowireBean(this);
				
		// now lets continue with setup and safe to call any autowires
		init();
	}
	
}

I had the same problem but Fernando’s solution worked for me.

I also found that I didn’t even need to add the 2 lines of code before init() is called…it works without explicitly calling autowireBean.

Also, I found that an equivalent/alternative way is to override beforeEnter instead of onAttach:

	@Override
	public void beforeEnter(BeforeEnterEvent event) {
		init();
	}

Hi Mahmoud,

I’m a little confused by your posting. You want to do dependency injection, but you’re not using Spring Boot. Yet you also mentioned wanting to use Spring beans. Can you clarify what you’re wanting to do? I’m definitely not a Vaadin expert, but I’m using Vaadin 14 and Spring Boot without any issues. At least no issues running on my local server which uses Tomcat 9.

Mahmoud

I didn’t know you can use the @Autowired annotation without including the Spring framework in your project. I’m using Vaadin 14 and Spring Boot. This runs without any errors or exceptions.

@SpringComponent
public class WodFactory {
    private final WodService wodService;

    @Autowired
    public WodFactory(WodService wodService) {
        this.wodService = wodService;
    }

Mahmoud

With regard to autowiring, I’m not doing anything differently in Vaddid 14 than Vaadin 8. I haven’t ported an app from 8 to 14, but I’ve written apps in both. But then again, I always use Spring Boot. I vaguely remember getting that same exception once, and I think it was because I forgot to add the @SpringBootApplication annotation to the class that contains main. I’m afraid I can’t be of much help with autowiring in a non-Spring app.

I have the same problem, that the autowiring in views is not working. And did not find anything clear yet on how to configure it properly.

I get

java.lang.IllegalArgumentException: Unable to create an instance of 'my.package.HomeView'. Make sure the class has a public no-arg constructor.

Anything new on this?

I have the same problem. Starter app works fine in development, but when the pom is setup for deployment as .war to Tomcat 9, I get the same problem. Similar error messages to the above. It’s as if Autowiring fails. The code is correct i.e the entry class has public static main(String args) and is annotated with @SpringBootApplication. I’ve even tried extending StringBootServletInitializer. Vaadin MainView is annotated with @Route(“”) and this class attempts to @Autowire an @Service component. As I say - it all works well in development mode using the embedded Tomcat server.

I Would certainly appreciate a clear Spring Boot + Postgres + Vaadin example of the pom configuration with production and development profiles. This is the pom.xml I’m using with the production vairant command line [mvn clean package -Pproduction]
:-

<?xml version="1.0" encoding="UTF-8"?> 4.0.0 org.springframework.boot spring-boot-starter-parent 2.3.3.RELEASE

com.example
springboot
0.0.1-SNAPSHOT
war
springboot
Demo project for Spring Boot

11 16.0.2 Vaadin Directory https://maven.vaadin.com/vaadin-addons false vaadin-prereleases https://maven.vaadin.com/vaadin-prereleases/ org.springframework.boot spring-boot-starter-web com.vaadin vaadin-spring-boot-starter org.springframework.boot spring-boot-devtools runtime true org.springframework.boot spring-boot-starter-data-jpa org.postgresql postgresql runtime org.projectlombok lombok true org.springframework.boot spring-boot-starter-validation org.springframework.boot spring-boot-starter-tomcat provided org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine com.vaadin vaadin-bom ${vaadin.version} pom import
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
  </plugin>
 
  <plugin>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-maven-plugin</artifactId>
    <version>${vaadin.version}</version>
    <executions>
      <execution>
        <goals>
          <goal>prepare-frontend</goal>
        </goals>

      </execution>
    </executions>
  </plugin>

</plugins>
production true
  <dependencies />

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <jvmArguments>-Dvaadin.productionMode</jvmArguments>
        </configuration>
      </plugin>
      <plugin>
        <groupId>com.vaadin</groupId>
        <artifactId>vaadin-maven-plugin</artifactId>
        <version>${vaadin.version}</version>
        <executions>
          <execution>
            <goals>
              <goal>build-frontend</goal>
            </goals>
            <phase>compile</phase>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</profile>

Thanks in adavance for any help.

An update on the above: I did manage to solve the problem by extending SpringBootServletInitializer and also removing any other code in the public static void main(String args) method, which I stuck in a CommandLineRunner annotated with @Component. as follows:-

This now works fine and Autowiring of other classes and interfaces works as expected. Remember the pom is configured for a .war packaging setup, and so I’m guessing there’s something going on in the Autoconfiguration process as far as instantiating the main entry Class that is different when packaged and/or deployed to a production tomcat server as opposed to packaging for a development environment (i.e when using Maven either I use the profile: production or not. It is possible to write code that when packaged in the development case the entry class is instantiated correctly and Autowiring works, but in the production packaging it fails, throws an exception and autowiring fails. Certainly the error messaging at this point is so verbose that its difficult to determine the source of the problem, but what’s clear is it’s not helped by some of the messaging (such as illustrated by others through out this thread), that the fault has something to with “zero argument constructors missing” etc… And so it would be helpful to clean up the manner in which Spring Boot with Vaadin fails.

Interestingly, I am using the VS Code IDE with the Java Extensions pack and with the pom.xml setup as above, and whether I choose to deploy to a standalone Tomcat or run and debug within the VS Code IDE environment, I can now do this with a) just .war packaging and b) always declaring the Tomcat dependency with scope: provided as below:-

org.springframework.boot spring-boot-starter-tomcat provided

If I understand this correctly, then it would seem that VS Code must be supplying the Tomcat server and it is happily running and debugging code from the .war development package (or perhaps it is directing Tomcat to read the contents of /target directory?) Eitherway, I don’t need to alter the pom.xml for deployment to a production Tomcat server, I just need to select the maven production profile i.e mvn clean package -Pproduction.

I hope this helps others with this problem.

Final point: it would appear the code and xml snippets I included in the above two messages have been scrambled by this forum’s messaging app. So if anyone wants them, then reply to the board and I’ll see if I can find a way to include them.