My application context XML is simple:
<context:component-scan base-package="com.depressio.spring" />
In that package, I have my configuration:
package com.depressio.spring
#Configuration
#ComponentScan(basePackages = "com.depressio")
public class DepressioConfiguration
{
#Inject private ApplicationContext context;
}
Within com.depressio, there's a repository (DAO):
package com.depressio.dao;
#Repository
public class ParameterDAO
{
public Parameter getParameter(long ID) { ... }
}
... and a service where injection is working just fine (no NPE when parameterDAO is used):
package com.depressio.resource;
#Service
#Path("/depressio/parameters")
public class ParameterResource
{
#Inject private ParameterDAO parameterDAO;
#Path("{id}")
public Response getParameter(long parameterID)
{
return Response.ok(parameterDAO.getParameter(parameterID).legacyFormat()).build();
}
}
However, the legacyFormat() method call there constructs another object. Within that object, I have to inject a different DAO (also annotated with #Repository, though). That injection isn't working.
So, we have the original Parameter object:
package com.depressio.domain;
public class Parameter
{
...
public LegacyParameter legacyFormat()
{
return new LegacyParameter(this);
}
}
... and the LegacyParameter where the injection isn't working:
package com.depressio.domain.legacy;
public class LegacyParameter
{
#Inject private LegacyDAO legacyDAO;
....
public LegacyParameter(Parameter newParameter)
{
// NullPointerException when using the injected legacyDAO.
}
}
I've tried a few things, including:
Using an no-args constructor for LegacyParameter, then calling a populate method so I'm not using the injected DAO until after the object is constructed. This didn't work.
Injecting the LegacyDAO into the ParameterResource and passing it in. This worked, but isn't ideal since I have to pass it around a whole lot (which injection should help avoid, no?). It did prove that LegacyDAO is injectible... just not into LegacyParameter apparently.
Adding a #Service, #Component, or #Named annotation on LegacyParameter. All end up with the NullPointerException on the line I try to reference the injected legacyDAO.
What am I missing?
As Sotirios has pointed out, it can't work since you create a regular Java object and do not give Spring a chance to enhance it.
Either let Spring create objects for which you want to enjoy the Spring 'magic' (like setting #Inject dependencies etc).
Or create your own objects and set the dependencies yourself (yourObject.setDao(dao)).
That said, there are exceptional cases in which you still want to create your objects 'on the fly' by yourself but rely on Spring to inject dependencies to these objects. In this case you should call Spring explicitly:
LegacyParameter p = new LegacyParameter(...);
applicationContext.getAutowireCapableBeanFactory().autowireBean(p);
I don't think you really need it in your case.
(see this link inject bean reference into a Quartz job in Spring? for an example when this is really required).
In addition, I would advice to simplify your configuration.
Why do you use both xml-based and java-based configuration that do actually the same? In your example you could keep only one of them and have the same effect.
Related
I know that there are questions similar to this one, but none of them have helped me. I'm following along this tutorial, and the part I can't wrap my mind around is:
#SpringBootApplication
public class Application {
private static final Logger log =
LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
#Bean
public CommandLineRunner demo(CustomerRepository repository) {
return (args) -> {
// save a couple of customers
...
// more lines, etc...
What I don't understand is where the repository passed into demo comes from. I know that the Autowired annotation can do something like that, but it isn't used at all here.
The more specific reason I ask is because I'm trying to adapt what they do here to an application I'm working on. I have a class, separate from all of the persistence/repository stuff, and I want to call repository methods like save and findAll. The issue is that the repository is an interface, so I can't instantiate an object of it to call the methods. So do I have to make a new class that implements the interface and create an object of that? Or is there an easier way using annotations?
When creating a #Bean, adding the repository in the parameters of the bean is enough to wire the repos in your bean. This works pretty much like adding #Autowired annotation inside a class that is annotated as #Component or something similar.
Spring works mostly with interface, since that is simplier to wire vs wiring concrete classes.
Can you try #Repository before the declaration of class? Worked for me in a Spring MVC structure.
#Repository
public class EntityDAOImpl implements EntityDAO{
...
}
The thing to wrap your head around is a Spring Boot application at startup time aims to resolve its dependancy tree. This means discovering and instantiating Beans that the application defines, and those are classes annotated with #Service, #Repository, etc.
This means the default constructor (or the one marked with #Autowire) of all beans is invoked, and after all beans have been constructed the application starts to run.
Where the #Bean annotation comes into play is if you have a bean which does not know the values of it's constructor parameters at compile time (e.g. if you want to wire in a "started at" timestamp): then you would define a class with an #Configuration annotation on it, and expose an #Bean method in it, which would return your bean and have parameters that are the beans dependencies. In it you would invoke the beans constructor and return the bean.
Now, if you want a certain method of some class to be invoked after the application is resolved, you can implement the CommandLineRunner interface, or you can annotate a method with #PostConstruct.
Some useful links / references:
https://docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/creating-bean-definitions.html
https://www.baeldung.com/spring-inject-prototype-bean-into-singleton
Running code after Spring Boot starts
Execute method on startup in Spring
I "inherited" a large Spring application with a spring-ws service in it.
The service is the typical Spring-WS code:
package service;
#Endpoint
public class ServiceEndpoint {
#Resource EntityDao entityDao;
#PayloadRoot(localPart=...)
#ResponsePayload
public ResponseWrapperClass getServiceMethod(#RequestPayload RequestWrapperClass request) {
return new ResponseProcessorClass(request).generateResponse();
}
}
The service is massive, and the entityDao injected with the #Resource annotation is used widely in the class.
Because the specific method I'm working on is a bit complex, I have encapsulated it in a separate class in a subpackage.
The ResponseProcessorClass looks like this:
package service.business;
#Component
public class ResponseProcessorClass {
#Resource EntityDao entityDao;
public ResponseWrapperClass generateResponse() {
entityDao.getSomeData(); //encapsulates hibernate logic -> Null Pointer Exception
}
}
As you can see by my comments above, I get a Null Pointer Exception when using the #Resource annotation in my new class.
I haven't used this annotation before, but for what I understood from the documentation the type should be inferred and injected. I could not find any configuration in any XML file for it either.
Could anyone tell me why am I getting the NPE?
Spring can only inject Spring managed beans into Spring managed beans. Therefore, if you create the object yourself, Spring can't do anything about it. This
return new ResponseProcessorClass(request).generateResponse();
is the problem. You are expecting Spring to inject a field of the ResponseProcessorClass object you created.
Try injecting a prototype bean instead of creating it yourself. This depends on your ResponseProcessorClass class.
I am reading the spring 3.0.x reference documentation to understand Spring Autowired annotation:
3.9.2 #Autowired and #Inject
I am not able to understand the below examples. Do we need to do something in the XML for it to work?
EXAMPLE 1
public class SimpleMovieLister {
private MovieFinder movieFinder;
#Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
EXAMPLE 2
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
#Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
How can the two classes be autowired implementing the same interface and using the same class?
Example:
class Red implements Color
class Blue implements Color
class myMainClass{
#Autowired
private Color color;
draw(){
color.design();
}
}
Which design method will be called? How do I make sure the design method of Red class will be called and not Blue?
TL;DR
The #Autowired annotation spares you the need to do the wiring by yourself in the XML file (or any other way) and just finds for you what needs to be injected where and does that for you.
Full explanation
The #Autowired annotation allows you to skip configurations elsewhere of what to inject and just does it for you. Assuming your package is com.mycompany.movies you have to put this tag in your XML (application context file):
<context:component-scan base-package="com.mycompany.movies" />
This tag will do an auto-scanning. Assuming each class that has to become a bean is annotated with a correct annotation like #Component (for simple bean) or #Controller (for a servlet control) or #Repository (for DAO classes) and these classes are somewhere under the package com.mycompany.movies, Spring will find all of these and create a bean for each one. This is done in 2 scans of the classes - the first time it just searches for classes that need to become a bean and maps the injections it needs to be doing, and on the second scan it injects the beans. Of course, you can define your beans in the more traditional XML file or with an #Configuration class (or any combination of the three).
The #Autowired annotation tells Spring where an injection needs to occur. If you put it on a method setMovieFinder it understands (by the prefix set + the #Autowired annotation) that a bean needs to be injected. In the second scan, Spring searches for a bean of type MovieFinder, and if it finds such bean, it injects it to this method. If it finds two such beans you will get an Exception. To avoid the Exception, you can use the #Qualifier annotation and tell it which of the two beans to inject in the following manner:
#Qualifier("redBean")
class Red implements Color {
// Class code here
}
#Qualifier("blueBean")
class Blue implements Color {
// Class code here
}
Or if you prefer to declare the beans in your XML, it would look something like this:
<bean id="redBean" class="com.mycompany.movies.Red"/>
<bean id="blueBean" class="com.mycompany.movies.Blue"/>
In the #Autowired declaration, you need to also add the #Qualifier to tell which of the two color beans to inject:
#Autowired
#Qualifier("redBean")
public void setColor(Color color) {
this.color = color;
}
If you don't want to use two annotations (the #Autowired and #Qualifier) you can use #Resource to combine these two:
#Resource(name="redBean")
public void setColor(Color color) {
this.color = color;
}
The #Resource (you can read some extra data about it in the first comment on this answer) spares you the use of two annotations and instead, you only use one.
I'll just add two more comments:
Good practice would be to use #Inject instead of #Autowired because it is not Spring-specific and is part of the JSR-330 standard.
Another good practice would be to put the #Inject / #Autowired on a constructor instead of a method. If you put it on a constructor, you can validate that the injected beans are not null and fail fast when you try to start the application and avoid a NullPointerException when you need to actually use the bean.
Update: To complete the picture, I created a new question about the #Configuration class.
Nothing in the example says that the "classes implementing the same interface". MovieCatalog is a type and CustomerPreferenceDao is another type. Spring can easily tell them apart.
In Spring 2.x, wiring of beans mostly happened via bean IDs or names. This is still supported by Spring 3.x but often, you will have one instance of a bean with a certain type - most services are singletons. Creating names for those is tedious. So Spring started to support "autowire by type".
What the examples show is various ways that you can use to inject beans into fields, methods and constructors.
The XML already contains all the information that Spring needs since you have to specify the fully qualified class name in each bean. You need to be a bit careful with interfaces, though:
This autowiring will fail:
#Autowired
public void prepare( Interface1 bean1, Interface1 bean2 ) { ... }
Since Java doesn't keep the parameter names in the byte code, Spring can't distinguish between the two beans anymore. The fix is to use #Qualifier:
#Autowired
public void prepare( #Qualifier("bean1") Interface1 bean1,
#Qualifier("bean2") Interface1 bean2 ) { ... }
Yes, you can configure the Spring servlet context xml file to define your beans (i.e., classes), so that it can do the automatic injection for you. However, do note, that you have to do other configurations to have Spring up and running and the best way to do that, is to follow a tutorial ground up.
Once you have your Spring configured probably, you can do the following in your Spring servlet context xml file for Example 1 above to work (please replace the package name of com.movies to what the true package name is and if this is a 3rd party class, then be sure that the appropriate jar file is on the classpath) :
<beans:bean id="movieFinder" class="com.movies.MovieFinder" />
or if the MovieFinder class has a constructor with a primitive value, then you could something like this,
<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
<beans:constructor-arg value="100" />
</beans:bean>
or if the MovieFinder class has a constructor expecting another class, then you could do something like this,
<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
<beans:constructor-arg ref="otherBeanRef" />
</beans:bean>
...where 'otherBeanRef' is another bean that has a reference to the expected class.
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).
Let's say we have a class:
public class MyClass {
#Autowired private AnotherBean anotherBean;
}
Then we created an object of this class (or some other framework have created the instance of this class).
MyClass obj = new MyClass();
Is it possible to still inject the dependencies? Something like:
applicationContext.injectDependencies(obj);
(I think Google Guice has something like this)
You can do this using the autowireBean() method of AutowireCapableBeanFactory. You pass it an arbitrary object, and Spring will treat it like something it created itself, and will apply the various autowiring bits and pieces.
To get hold of the AutowireCapableBeanFactory, just autowire that:
private #Autowired AutowireCapableBeanFactory beanFactory;
public void doStuff() {
MyBean obj = new MyBean();
beanFactory.autowireBean(obj);
// obj will now have its dependencies autowired.
}
You can also mark your MyClass with #Configurable annotation:
#Configurable
public class MyClass {
#Autowired private AnotherClass instance
}
Then at creation time it will automatically inject its dependencies. You also should have <context:spring-configured/> in your application context xml.
Just got the same need and in my case it was already the logic inside non Spring manageable java class which had access to ApplicationContext. Inspired by scaffman.
Solved by:
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(manuallyCreatedInstance);
I used a different approach. I had spring loaded beans that I wanted to call from my extended classes of a third-party library that created its own threads.
I used approach I found here https://confluence.jaytaala.com/display/TKB/Super+simple+approach+to+accessing+Spring+beans+from+non-Spring+managed+classes+and+POJOs
In the non-managed class:
{
[...]
SomeBean bc = (SomeBean) SpringContext.getBean(SomeBean.class);
[...]
bc.someMethod(...)
}
And then as a helper class in the main application:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class SpringContext implements ApplicationContextAware
{
private static ApplicationContext context;
public static <T extends Object> T getBean(Class<T> beanClass)
{
return context.getBean(beanClass);
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException
{
SpringContext.context = context;
}
}
I wanted to share my solution that follows the #Configurable approach as briefly mentioned in #glaz666 answer because
The answer by #skaffman is nearly 10 years old, and that does not mean not good enough or does not work
The answer by #glaz666 is brief and didn't really help me solve my problem but, did point me in the right direction
My setup
Spring Boot 2.0.3 with Spring Neo4j & Aop starts (which is irrelevant anyway)
Instantiate a bean when Spring Boot is ready using #Configurable approach (using ApplicationRunner)
Gradle & Eclipse
Steps
I needed to follow the steps below in order to get it working
The #Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false) to be placed on top of your Bean that is to be manually instantiated. In my case the Bean that is to be manually instantiated have #Autowired services hence, the props to above annotation.
Annotate the Spring Boot's main XXXApplicaiton.java (or the file that is annotated with #SpringBootApplication) with the #EnableSpringConfigured and #EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
Add the dependencies in your build file (i.e. build.gradle or pom.xml depending on which one you use) compile('org.springframework.boot:spring-boot-starter-aop') and compile('org.springframework:spring-aspects:5.0.7.RELEASE')
New+up your Bean that is annotated with #Configurable anywhere and its dependencies should be autowired.
*In regards to point #3 above, I am aware that the org.springframework.boot:spring-boot-starter-aop transitively pulls the spring-aop (as shown here mavencentral) but, in my case the Eclipse failed to resolve the #EnableSpringConfigured annotations hence, why I explicitly added the spring-aop dependency in addition to the starter. Should you face the same issue, just declare the dependency or go on adventure of figuring out
Is there a version conflict
Why the org.springframework.context.annotation.aspect.* is not available
Is your IDE setup properly
Etc etc.
This worked for me:
#Configuration
public class AppConfig {
#Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
See more information: https://docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/creating-bean-definitions.html
Found the following way useful for my use case. Sharing here for reference, credit goes to the blogger entirely. This creates a static field and populates that from Spring and then provides a public static method which returns the field populated above.
https://sultanov.dev/blog/access-spring-beans-from-unmanaged-objects/