I have a Spring Boot Java application and am trying to inject a #Service into a class. I'm using #Autowired but it's not doing it. I successfully do so in other classes, but not this one.
The service class:
#Service
#Transactional
public class TaskService {
...
}
The class where it works is a Vaadin "view" annotated with a Vaadin #Route annotation. I'm assuming there is something going on behind the scenes with the #Route annotation that allows this to work.
#Route("main")
public class TaskListView extends HorizontalLayout {
private final TaskService taskService;
public TaskListView(#Autowired TaskService taskService) {
this.taskService = taskService;
}
...
}
The class where it does not work is also a Vaadin "view", but does not have a #Route annotation, because it is not intended to be navigable to, but rather used as a sub-component of a view (i.e. would be directly instantiated inside a parent view).
public class EditNotesForm extends VerticalLayout {
#Autowired
private TaskService taskService;
...
}
The first class uses constructor injection, while the second uses property injection. I can't see why this should make a difference, as I have used both techniques successfully in other applications.
From the Vaadin website:
The only difference between using the router in a standard application and a Spring application is that, in Spring, you can use dependency injection in components annotated with #Route. These components are instantiated by Spring and become Spring-initialized beans. In particular, this means you can autowire other Spring-managed beans.
One way to access Spring components from your regular Vaadin components is by creating static get methods to retrieve your Spring components. Here is one way that can be done... but not the only.
#Component
public class StaticHelper {
private static StaticHelper instance;
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public void registerInstance() {
instance = this;
}
public static <T> T getBean(Class<T> class) {
return instance.applicationContext.getBean(class);
}
}
So in your example...
private TaskService taskService = StaticHelper.getBean(TaskService.class);
Since EditNotesFormdoesn't have the Route annotation, spring can't autodiscover it and therefore it can't inject any dependency.
Since you want to instantiate it manually, you'll need to provide yourself all dependencies.
But if you still want to benefit from automatic dependency injection, take a look at https://www.baeldung.com/spring-beanfactory
Related
what is the main difference between injecting objects with #Autowired and injecting without it ?
I know that spring will initialize the bean , but what it is really offering ?
There are several ways to configure Spring beans and inject dependencies using Spring. One way is by using constructor injection, where the constructor of your Spring bean has arguments which are the dependencies that should be injected:
#Component
public class MyBean {
private final SomeDependency something;
#Autowired
public MyBean(SomeDependency something) {
this.something = something;
}
}
However, since Spring 4.3, it is not necessary anymore to use #Autowired on such a constructor (click link for Spring documentation). So you can write it without the #Autowired:
#Component
public class MyBean {
private final SomeDependency something;
public MyBean(SomeDependency something) {
this.something = something;
}
}
This will work exactly the same as the code above - Spring will automatically understand that you want the dependency to be injected via the constructor. The fact that you can leave out #Autowired is just for convenience.
So, to answer your question: there is no difference.
#Autowired (so the injection) in some situation cannot be used, an example is if your autowired bean not ready because of some async stuff but in the target bean you want to use that.
So in this situation do not use inject (#Autowired) it is better to inject the ApplicationContext and in the exact moment get your bean from there by name or by class (there is a lot off possibilities there).
You can consider the #Autowired with the #Lazy annotation too.
I am getting the following error in a Spring Boot project on which I work:
The bean 'auditLogDao' could not be injected as a '{redactedpathwithcorporatename}.AuditLogDao' because it is a JDK dynamic proxy that implements:
org.springframework.data.jpa.repository.JpaRepository
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on #EnableAsync and/or #EnableCaching.
I have tried a variety of solutions on StackOverflow without success, specifically:
Checking that I am indeed calling the interface, not the implementation.
Adding #Component to the top of SwitchUserFilter
Changing #Resource to #Autowired.
AuditLogDao.java
public interface AuditLogDao extends JpaRepository<AuditLog, String> {}
AuditLogService.java
public interface AuditLogService {
AuditLog save(final AuditLog auditLog);
}
AuditLogServiceImplementation.java
public class AuditLogServiceImplementation implements AuditLogService{
#Resource private AuditLogDao auditLogDao;
#Override
public AuditLog save(AuditLog auditLog) {
return auditLogDao.save(auditLog);
}
}
The file where I actually want to use the service to save information
SwitchuserFilter.java
public class SwitchUserFilter
extends org.springframework.security.web.authentication.switchuser.SwitchUserFilter {
#Resource AuditLogService logService;
'''
logService.save(auditLog);
'''
}
I am relatively new to Spring Boot, so an explanation of why it fixes the problem would be appreciated.
I believe the following code will solve your problem. Add it to the AuditLogServiceImplementation and remove the #Resource annotation from the auditLogDao.
#Autowired
private ListableBeanFactory beanFactory;
#EventListener({ContextRefreshedEvent.class})
void contextRefreshedEvent() {
auditLogDao = beanFactory.getBean(AuditLogDao.class);
}
You can do a similar trick in the filter too, whatever more comfortable for you.
I don't know what is the exact problem, but it's some kind of circular-dependency-like issue.
So by manually importing any bean which is affected in this loop, you can resolve the loop. You will set this one particular dependency AFTER Spring had created all of the other beans.
I have an spring boot app that has a mongo repository and is using spring data to connect to it. This means there's an "entity" class and then a "repository" class.
However, to actually use the repository I need spring to #Autowire my repo to a variable inside another class (we'll call it X) that might want to use it. But if the X class is itself not a spring bean, it's just a regular pojo created by "new X" somewhere then it can't make use of Autowiring and therefore cant use the repo.
This seems like a show stopper... No one could ever make use of a repo outside of some very specific situations like calling the repo directly from your RestController or whatever without any intervening logic. Yet I am sure people are using this.
So my question is how to structure code so that it can be used? Do I need to do a bunch of processing and then return back up to the controller to interact with the databases? Is there a way to create some kind of other "intermediate helper bean" to mediate the connection? What should that look like?
disclaimer: I am fairly new to spring
Perhaps I can post some excerpts that can clarify your situation.
//nothing spring specific
public class MyPojo {
//properties
}
in a different package:
#Repository
public class MyRepositoryImpl implements MyRepository {
//CRUD implementation or whatever
}
in a different package:
#Service
public class MyServiceImpl implements MyService {
#Autowired //constructor-injection
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
private final MyRepository myRepository;
public void myBusinessLogic() {
MyPojo pojo = new MyPojo(); //not dependent on Spring
myRepository.doSomething();
//place calls to X here as needed
}
}
And finally:
#Controller
public class MyController {
#Autowired
public MyController(MyService myService) {
this.myService = myService;
}
private final MyService myService;
#GetMapping("/myPage")
public String doIt() {
myService.myBusinessLogic();
return "myPage";
}
}
Where MyRepository and MyService are interfaces that would contain the contract for their respective implementations.
Single Responsibility Principle
A major point to note is that your POJO isn't going to "use the repo" as you mention in your question. It represents an entity and shouldn't care about any specific repository. And this seems related to your issue - a POJO shouldn't be making calls to a repository (your "X" class in this case). Seems like the design should be revisited if that is the case.
As you say, you can only autowire fields in objects that themselves are autowired. This is inherent to bean injection. You should annotate X with for instance #Component and inject it where you need it.
I just start learning Spring framework (i use version 4.3.0) and i thought that we need #Autowired to tell the framework when a class need injection.
However, i try this today:
#Component
public class CDPlayer implements MediaPlayer{
private CompactDisc cd;
//there are no #Autowired here
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
}
and it work perfectly fine with automatic wiring configuration:
#Configuration
#ComponentScan
public class CDPlayerConfigAuto {
}
So when i do really need to use #Autowired?
Since Spring 4.3 this is not necesary if your class has only one constructor.
So as of 4.3, you no longer need to specify an explicit injection
annotation in such a single-constructor scenario. This is particularly
elegant for classes which otherwise do not carry any container
annotations at all.
You can see here: (Implicit constructor injection for single-constructor scenarios)
https://spring.io/blog/2016/03/04/core-container-refinements-in-spring-framework-4-3
This is a new feature in Spring Boot 4.3. If you have only one constructor in the class, this constructor will be used to autowire the arguments. If you have more constructors or if you want to use setter or field injection, then you still need the #Autowired annotation.
I have a problem with injecting a bean into a helper class. It works basically like this: I create an object in the page constructor that does some work, returns some data and I show these on the page. In this helper object, a service should be injected via #Autowired annotation. However, I always get a null pointer exception when I use it. I also tried #SpringBean but it didn't help. On the other hand, when I inject this service directly into the page with #SpringBean, it's accessible and works fine. Do you know where the problem is?
This is the page:
public class Page extends BasePage {
public Page() {
HelperObject object = new HelperObject(new Application("APP_NAME"));
String result = object.getData();
add(new Label("label", result));
}
}
Helper object:
public class HelperObject {
private Application app;
#Autowired
private Service service;
public HelperObject(Application app) {
this.app = app;
}
public String getData() {
// use service, manipulate data, return a string
}
}
You can inject dependencies into non-Spring-non-Wicket-new-created objects using #SpringBean by calling InjectorHolder.getInjector().inject(this); in its constructor.
For example:
class MyPojo {
#SpringBean
MyDumbDAO dao;
MyPojo() {
InjectorHolder.getInjector().inject(this);
}
void justDoIt() {
dao.duh(); // dao is there!
}
}
Note that it will only work if called within a Wicket-managed request. If not (ie, if it's a Quartz job, or a Filter executed before Wicket's), the Application instance will not be available, and the injector won't know how to get the dependencies.
Another solution is to use Spring's #Configurable. It uses AspectJ to intercept creation of annotated objects, and inject its dependencies, even if you instantiate them directly with new (or some other framework, like Hibernate, creates them internally). But this requires runtime or build-time (works better for me) bytecode manipulation, which may be too much magic for some people.
#SpringBean only injects dependencies into classes that inherit from Wicket's Component. #Autowired only injects dependencies into classes created by Spring itself. That means you can't automatically inject a dependency into an object you create with new.
(Edit: you can also add a #SpringBean injection to your class by injecting in the constructor:
InjectorHolder.getInjector().inject(this);)
My normal workaround for this is to use my application class to help. (I'm a little puzzled by your use of new Application(...). I assume this isn't actually org.apache.wicket.Application.) For example:
public class MyApplication extends AuthenticatedWebApplication implements
ApplicationContextAware {
private ApplicationContext ctx;
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.ctx = applicationContext;
}
public static MyApplication get() {
return (MyApplication) WebApplication.get();
}
public static Object getSpringBean(String bean) {
return get().ctx.getBean(bean);
}
public static <T> T getSpringBean(Class<T> bean) {
return get().ctx.getBean(bean);
}
....
}
In my Spring application context:
<!-- Set up wicket application -->
<bean id="wicketApplication" class="uk.co.humboldt.Project.MyApplication"/>
My helper object then looks up the service on demand:
public class HelperObject {
private Service getService() {
return MyApplication.getSpringBean(Service.class);
}
The best practice would be to create your objects via a factory bean (that has those properties injected by Spring, and have that factory inject those properties to objects it spawns - pure IoC).
You should really avoid using SpringContext all over the place (or any other similar solution for that matter).
Here is a partial list of reasons:
Your code gets coupled with Spring way too much (low-cohesion).
You mix plumbing code with the business-logic.
Your code is less readable.
It's less maintainable (e.g., changing the name of the service bean would lead to code modification - this violates SRP & OCP).
It's less testable (e.g., you need the Spring framework to test it).