I would like to assign a value with the name of the #Service from application.properties tu |#Qualifier . I tried but it doesn't work .
In fact i have two services which implement the same interface and i would like to change the service from application.properties
Someone has any idea how to do this?
this is my code
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class Controler {
#Qualifier("${service.name}")
#Autowired
private InterfaceTest interfaceTest;
#GetMapping("/test")
public String test(){
return interfaceTest.test();
}
}
Thank you very much for your help
I think you can do that in the constructor of this controller by using Environment and ApplicationContext beans.
Just remove Autowired annotation from fields and accept other parameters through constructor as well.
public Controller(Environment environment, ApplicationContext applicationContext) {
String serviceName = environment.getProperty("service.name");
this.interfaceTest = applicationContext.getBean(serviceName, InterfaceTest.class);
}
Those bean qualifiers and other annotations of spring just except literals as far as I know.
Hope this helps.
Related
This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 3 years ago.
I am developing a spring boot application to send sms notification. This is my class for the purpose.
package org.otp.services;
import org.otp.Configurations;
import com.mashape.unirest.http.HttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
#Component
public class SmsService
{
private static final Logger LOG = LoggerFactory.getLogger(SmsService.class);
public String send(String mobile, String msg)
{
//Code
}
}
And this is the class which uses the above class for sending notification.
package org.otp.controllers;
import org.otp.Constants;
import org.otp.services.EmailService;
import org.otp.services.SmsService;
import org.otp.dto.MessageRequest;
import org.otp.dto.MessageResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
#Component
public class MessageController {
private static final Logger LOG = LoggerFactory.getLogger(MessageController.class);
#Autowired
SmsService smsService;
public void sendMessageToAlert(#RequestBody MessageRequest messageRequest)
{
String smsStatus = "FAIL";
MessageResponse messageResponse = new MessageResponse();
//1. Nullpointer
smsStatus = smsService.send(messageRequest.getMobileNo(),messageRequest.getMessage());
}
}
Main Class
package org.otp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
#SpringBootApplication
#EnableAsync
public class OtpServiceApplication implements ApplicationRunner
{
public static void main(String[] args) {
SpringApplication.run(OtpServiceApplication.class, args);
}
}
Problem is, I get a nullpointer exception in the (1) stating that my SmsService object is null. And my main class is in package org.otp so the two classes here falls under sub package so no need of component scan.
Therefore I am confused what to do to solve this. I have tried many answers here like adding a #Component annotation and #ComponentScan in main class but nothing works. Could someone please point out my mistake here.
Thanks in advance.
If your #Autowired annotation is not working and throws NPE ,it means that spring fails to create an instance of the component class in the application context . Try to:
Verify that the classes are in class path for scanning and also check to ensure that all auto-wired classes have the annotation #Component to enable them to be picked up during class path scanning.
Check the spring boot start up logs to verify if there are any errors
during bean creation.
Check to ensure all related classes used in the service layer are auto-wired properly and that the injected classes are annotated with #Component .
For further help please share the main application class along with your project structure.
Since you are using springboot , it is preferable to use the sprinboot stereotype annotations instead of the #Component annotation, if you are building a standard springboot web application.
#Service : for the service layer.
#Controller : for the controller layer . Also,DispatcherServlet will look for #RequestMapping on classes which are annotated using #Controller but not with #Component.
In Springboot application's main class add following annotation
#SpringBootApplication
#ComponentScan(
basePackages = {"org.otp.*"}
)
public class YourSpringMainClass{
public static void main(String[] args) {
SpringApplication.run(YourSpringMainClass.class, args);
}
}
While using annotations we should configured with #ComponentScan annotation to tell Spring the packages to scan for annotated components. This should be used in mail class(Which class wants to load first) in your case you are working with spring boot so you should use this annotation in Springboot application's main class. Like below
#SpringBootApplication
#ComponentScan(
basePackages = {"org.otp.*"}
)
public class YourSpringMainClass{
public static void main(String[] args) {
SpringApplication.run(YourSpringMainClass.class, args);
}
}
So. After reading the official docs and finding nothing wrong with what I am doing, I just ran out of ideas.
My application.properties:
vz.info.version=0.2.8
My properties Component
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
#Configuration
public class VZProperties {
#Value("${vz.info.version}")
#Getter
#Setter
private String apiVersion;
}
I am getting null all over the place for the apiVersion.
And Lombok does not seem to be the issue. What did I miss from the docs?
EDIT
I would like to call it like this:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.Lists;
import lombok.Getter;
import java.io.Serializable;
import java.util.List;
public class VZNFCTagResponse implements Serializable{
private static final long serialVersionUID = -2824767225275894898L;
#Autowired
private VZProperties properties;
public VZNFCTagResponse(List<VZNFCTagAction> tagList){
this.tags = tagList;
}
/*...*/
#JsonProperty
public String apiVersion(){
return this.properties.getApiVersion();
}
}
And after having checked to get it running via injecting Environment, the property isn't there, either.
Your class VZNFCTagResponse is not registered as Spring Beans.
Annotate it as #Component and use DI for inject him.
The only way to avoid making it into a component and still benefit from DI is to mark it #Configurable and enable load-time weaving. Can't you just inject it into the component that creates VZNFCTagResponse and pass the version as a constructor parameter?
I'd like to be able to instantiate a request-scoped bean which is also immutable by using constructor parameters.
Something like the following (which of course doesn't work):
RequestContextFactory.java
package org.springframework.samples.mvc.requestscope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.annotation.RequestScope;
#Configuration
public class RequestContextFactory {
#Bean
#RequestScope
public RequestContext getRequestContext(TestBean bean) {
return new RequestContext(bean);
}
}
MyController.java
package org.springframework.samples.mvc.requestscope;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class MyController {
#Autowired
RequestContextFactory requestContextFactory;
#RequestMapping("/my")
public #ResponseBody String simple(TestBean bean) {
RequestContext requestContext = requestContextFactory.getRequestContext(bean);
return "Hello world!";
}
}
Spring complains that it cannot autowire a TestBean bean to create RequestContext.
How can I achieve immutability of a request-scoped bean which needs constructor parameters only known in the controller?
I'd like to be able to inject RequestContext into other beans (either request scope or other scopes). Is this an antipattern? Should something like RequestContext (or any other object with request lifecycle) be in the signature of all call hierarchy under the controller?
Note:
I thought of as a solution like for example having a RequestContext with default constructor and an init(...) method which can be called only once (would throw the second time). I don't like it.
I consider injection of beans as a List of automatically detected beans: I introduce several beans implementing the same interface and inject all of them as a List in a later bean.
I've not been able to find official documentation related to this feature. My single source is http://www.coderanch.com/t/605509/Spring/Java-config-autowired-List
Considering this feature, I have an issue with Bean overring: I would like to override a bean defined throught a no-arg method with a bean defined with the List of detected beans. However, spring behave like the second bean definition does not exist.
It can be reproduced with the following test:
import java.util.Date;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class SpringTest {
#Test
public void shouldtestSpringDifferentMethodNames() {
AnnotationConfigApplicationContext ctx2 = new AnnotationConfigApplicationContext(AConfig.class, CConfig.class);
Assert.assertEquals("overriden", ctx2.getBean("bean"));
}
#Configuration
public static class AConfig {
#Bean
public Object bean() {
return "not overriden";
}
}
#Configuration
public static class CConfig extends AConfig {
#Bean
public Date anotherBean() {
return new Date();
}
#Bean
public Object bean(List<? extends Date> someDate) {
return "overriden";
}
}
}
If this is an expected behavior, how can I achieve such an overriding?
documentation for list autowire can be found at spring documentation
overriding of beans by id or name is not official spring feature - look for that question for more details
This has been considered as a bug by the Spring team: https://jira.springsource.org/browse/SPR-10988
A recent piece of documentation can be found at: http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-autowired-annotation (Thanks Alexander Kudrevatykh for the 2.5 source)
Ive Added Spring annotation's to my code
but when connecting via visual vm the method "myExample()" isn't showing in the JMX bean list
My code :
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Component;
#Component
#ManagedResource
public class MyClass {
#Autowired
private Example exampleService;
#ManagedAttribute
public String myExample() {
return exampleService.getSomething().toString();
}
}
any idea why this is happening ?
You should use #ManagedOperation instead. #ManagedAttribute is for a getter / setter methods only.