Vaadin Flow / Spring Boot - Using @Autowired in Components

Hi everyone,

let’s say I have a MainView which looks like this

@Route("")
public class MainView extends VerticalLayout {

	private final MyService myService;
	private final MyOtherService myOtherService;
	
	public MainView(@Autowired MyService myService,
					@Autowired MyOtherService myOtherService) {
		this.myService = myService;
		this.myOtherService = myOtherService;
	}
	 // some methods
}

and a custom component which looks like this

public class MyComponent extends Component {
	// constructor and fields abbreviated
	
	public void doSomething() {
		myService.fetch();
		myOtherService.fetch();
	}
}

I’ve been using Vaadin Flow and Spring for a while, but still haven’t quite figured out what’s the preferred way to access a Spring bean (like a service class) inside a Vaadin Component. Do I have to inject it/them as a parameter every time I instantiate a component in my MainView?

MyComponent myComponent = new MyComponent(myService, myOtherService);

Or is there a better way, like autowiring / injecting it directly inside the MyComponent class?

Any help is much appreciated.

Kind regards,
David

You can create a fields in MyComponent and annotate them with @Autowired. But then, you cannot use them in the constructor yet (they would be null at ctor time (except if you annotate the ctor with @Autowired)). But they are available if your eg. create a method and annotate it with @PostConstruct (that method will be run after dependencies are injected).

@Route("")
public class MainView extends VerticalLayout {

	@Autowired
	private /* not final! */ MyService myService;
	
	@Autowired
	private /* not final! */ MyOtherService myOtherService;
	
	public MainView() {
		/* can be empty now */
	}
	
	@PostConstruct
	public void init() {
		myService.foo(...);
		myOtherService.bar(...);
	}
	 
}

T.

What Thomas did was switch from constructor injection to field injection. Both ways work, and it doesn’t answer the posed question.

Any Object that you instantiate using the new Syntax can not contain any autowirings (neither constructor- nor field injection). Because the views are managed by spring (correct me if I’m wrong. At least you never do new MainView() in your project), you can autowire spring-components within your Views. This is the place where you inject ALL Spring components that you will use within that view. If those spring-components are not used directly in the view itself but in a (Vaadin) Component within, like MyComponent, then you will have to pass the spring-components as parameters, just like you did.

Hi All,

The way I do it, specifically for my JPA repositories is create a @Service class that has all the repositories @Autowired. Then in the @Route views I @Autowired inject the service class and pass that class to any components that get created with the new syntax.

I also make the @Autowired repositories public in the @Service class, so I can just call service.customerRepo.save(<>) etc. (not sure if thats the best practise… :slight_smile: )

Hope that makes sense.

S.

Unfortunately, autowiring services into views doesn’t seem like a best practice, considering that your UI will no longer be serializable and therefore the session can no longer be persisted. I.e. your UI cannot survive a server restart or cannot be migrated in a high availability setup.
So it’s better to never save a reference to any services in your Components and use a utility method like this to access them:

public class Service
{
  public static <T> T get(Class<T> serviceType)
  {
    return WebApplicationContextUtils
        .getWebApplicationContext(VaadinServlet.getCurrent().getServletContext())
        .getBean(serviceType);
  }
}

Unless someone has found some Spring magic that somehow avoids that serialization issue.

I really, really like Patrick’s answer because that’d make it super easy to use any Spring Service in Vaadin Components.

But I am wondering, is there anything that speaks against using it?
Thinking about Session and UI Scopes here.

David M:
I really, really like Patrick’s answer because that’d make it super easy to use any Spring Service in Vaadin Components.

But I am wondering, is there anything that speaks against using it?
Thinking about Session and UI Scopes here.

In the meantime I actually did find some Spring magic that lets one keep autowiring (including the use of qualifiers) while avoiding the serialization issue, by injecting service references instead of the services directly.

So instead of

@Autowired
private MyService myService;

...

myService.doStuff();

you’d write

@Autowired
private ServiceRef<MyService> myService;

...

myService.get().doStuff();

Internally it uses the snippet from above, so it’s mostly a pretty DI wrapper around that. Although the option for a static method call in Components where no DI is possible, is still there.

I had this lying around for a few months and your post triggered me to finally [publish it as an add-on]
(https://vaadin.com/directory/component/serializable-service-references-for-vaadin-flow). So check it out if you’re interested :slight_smile:

As to your question: What specifically are you worried about when retrieving your services in this way? The only limit I can see is that VaadinServlet.getCurrent() needs to be called in either a Vaadin request thread or within UI#access(…) for it to work. But that doesn’t seem too bad of a restriction to me.

That looks great, thanks a lot!

You literally saved my day. Thank you very much!