I have following situation. There is POJO which has autowired implementation of an interface, using some spring magic as shown bellow. However this dependency doesn't get resolved if creation of channels is managed via spring bean. It only works if POJO factory creates channels. Example bellow.
#Controller
public class Test{
#RequestMapping(value = "/load", method = RequestMethod.GET)
public #ResponseBody String testConfiguration() {
// this is pojo and here it works, channels within have wired interface implementation
StaticFactory.getChannels(null);
// if i call same method within spring managed bean (#Service)
// then it doesnt work
System.out.println("channels created");
return "alive";
}
}
Created Channels are POJO but they have autowired interface implementation, which should be enabled with the following in constructor:
public DummyChannel() {
// enables dependency injection of spring managed beans into POJO
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
public class StaticFactory {
public static List<SmppChannel> getChannels(Map<ChannelMode, Integer> channelsDefinition) {
List<SmppChannel> dummyChannels = new ArrayList<>();
DummyChannel d = new DummyChannel();
System.out.println("here");
dummyChannels.add(new DummyChannel());
return dummyChannels;
}
}
Now, this thing works if i have non-spring managed Factory. Regardless if mentioned factory is static or not when it creates channels, they have properly wired interface implementation.
However, if i copy paste exactly same code form the factory into Spring managed Bean annotated with #Service, wired dependency is null in created channel.
Could somebody tell me what am i missing here, why things get injected when the factory of channels is not managed by the Spring ?
Edit Solution: // Okay, so the problem is in the fact that DummyChannels enable autowiring support in constructor while Spring beans are still not loaded. It is working if i do this within method that should access autowired service rather then the constructor of DummyChannel.
Have you enabled annotation-config and component-scan in your xml or java configuration? Is the class that you want to inject annotated with #Service or #Resource?
Are you building a Web Service with JAX-WS? If yes, then I think your class (the one doing the autowiring) must implement SpringBeanAutowiringSupport so that Spring's IoC container can handle the injection.
Related
Originally, there was a service instance to access the database and now we want to add a readonly instance. So I add the serviceReadonly in my configuration.
#Configuration
public class Config {
#Bean Service service() {...};
#Bean Service serviceReadonly() {...};
#Bean Proxy proxy() {return new Proxy(serviceReadonly())}; // replace the original Proxy(service())
}
But, the service is also autowired to Proxy
#Component
public class Proxy {
#Autowired
public Proxy(Service service) {this.service = service;}
}
I am confused which Service is injected in my API? service or serviceReadonly?
#Component
public class API {
#Autowired
public API(Proxy proxy) {this.proxy = proxy;}
}
The Proxy and API classes are in another shared library and avoiding change to the library is preferred. Also, the service is autowired to other components.
Short answer: #Bean Service service()
Explanation: Excerpt from the Spring documentation here
Autowiring by property name. Spring looks for a bean with the same
name as the property that needs to be autowired. For example, if a
bean definition is set to autowire by name, and it contains a master
property (that is, it has a setMaster(..) method), Spring looks for a
bean definition named master, and uses it to set the property.
I assume it will be #Bean Service service() because the Spring would find the bean with same name as the property i.e. Service as defined in official Spring guide.
You may also need to look into #Qualifier annotation. It is because if there is not exactly one bean of the constructor argument type in the container, a fatal error is raised, as mentioned in Spring documentation here. Have you checked if you receive this error of NoUniqueBeanDefinitionException? In that case you can use #Qualifer annotation to specify the bean you want.
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 am coding both a library and service consuming this library. I want to have a UsernameProvider service, which takes care of extracting the username of the logged in user. I consume the service in the library itself:
class AuditService {
#Autowired
UsernameProvider usernameProvider;
void logChange() {
String username = usernameProvider.getUsername();
...
}
}
I want to have a default implementation of the UsernameProvider interface that extracts the username from the subject claim of a JWT. However, in the service that depends on the library I want to use Basic authentication, therefore I'd create a BasicAuthUsernameProvider that overrides getUsername().
I naturally get an error when there are multiple autowire candidates of the same type (DefaultUsernameProvider in the library, and BasicAuthUsernameProvider in the service), so I'd have to mark the bean in the service as #Primary. But I don't want to have the library clients specify a primary bean, but instead mark a default.
Adding #Order(value = Ordered.LOWEST_PRECEDENCE) on the DefaultUsernameProvider didn't work.
Adding #ConditionalOnMissingBean in a Configuration class in the library didn't work either.
EDIT: Turns out, adding #Component on the UsernameProvider implementation classes renders #ConditionalOnMissingBean useless, as Spring Boot tries to autowire every class annotated as a Component, therefore throwing the "Multiple beans of type found" exception.
You can annotate the method that instantiates your bean with #ConditionalOnMissingBean. This would mean that the method will be used to instantiate your bean only if no other UserProvider is declared as a bean.
In the example below you must not annotate the class DefaultUserProvider as Component, Service or any other bean annotation.
#Configuration
public class UserConfiguration {
#Bean
#ConditionalOnMissingBean
public UserProvider provideUser() {
return new DefaultUserProvider();
}
}
You've not posted the code for DefaultUsernameProvider but I guess its annotated as a #Component so it is a candidate for auto wiring, and the same with the BasicAuthUsernameProvider. If you want to control which of these is used, rather than marking them both as components, add a #Configuration class, and create your UsernameProvider bean there:
#Configuration
public class ProviderConfig {
#Bean
public UsernameProvider() {
return new BasicAuthUsernameProvider();
}
}
This bean will then be auto wired wherever its needed
I have a library which produces beans into a Spring context for use by clients. The beans I produce are configured by Spring. I need to add a new bean to my context in order to satisfy a dependency of a new bean I'm publishing. However, I believe some of my clients already have an instance of this bean and are autowiring it by type. So I have something like this:
// Code in my Library
#Component
public class PublicUtilityClass {
// This is all new code in my library
private NewDependency newDependency;
public void newCapability() {
newDependency.doNewThing();
}
#AutoWired
public void setNewDependency(NewDependency newDependency) {
this.newDependency = newDependency;
}
// Other library code omitted.
}
How can I use Spring to instantiate NewDependency and inject it into PublicUtilityClass without impacting customers who already have a NewDependency bean in their context?
You should look at #Qualifier annotation. Qualifier allows you to have multiple instance of your bean
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.