I am having a simple RestController:
#RestController
#PropertySource("classpath:application.properties")
public class Word2VecRestController {
private final static Logger LOGGER = Logger.getLogger(Word2VecRestController.class);
// #Resource is not working as well
#Autowired
Environment env;
// This is working for some reason
// but it's null inside the constructor
#Value("${test}")
String test;
public Word2VecRestController() {
LOGGER.info(env.getProperty("test"));
System.out.println("");
}
#GetMapping("/dl4j/getWordVector")
public ResponseEntity<List<Double[]>> getWordVector(String word) {
return null;
}
}
The problem is, that env is always null. I've seen somewhere that I could try to use #Resource instead of #Autowired but that didn't help.
application.properties:
test=helloworld
I've tried to use
#Value("${test}")
String test;
but the problem here is that these are null during construction of the object where I need it.
Field injection is done by Spring after the constructor is called. This is why Environment is null in the Word2VecRestController constructor. You can try constructor injection if you need it in the constructor:
#RestController
#PropertySource("classpath:application.properties")
public class Word2VecRestController {
private final static Logger LOGGER = Logger.getLogger(Word2VecRestController.class);
#Autowired
public Word2VecRestController(Environment env, #Value("${test}") String test) {
LOGGER.info(env.getProperty("test"));
System.out.println("");
}
#GetMapping("/dl4j/getWordVector")
public ResponseEntity<List<Double[]>> getWordVector(String word) {
return null;
}
}
PS: if you use Spring Boot, you do not need the #PropertySource("classpath:application.properties"), this is automatically done for you.
Add
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
to enable the PropertySourcesPlaceholderConfigurer to your configuration. Important this must been a static method!
For example:
#Configuration
#PropertySource("classpath:application.properties")
public class SpringConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Related
I am trying to understand Spring/Spring-boot. My question is, can I use a Bean instantiated/declaired by #Bean to a #Autowired field? Below is my classes, what i have defined.
#SpringBootApplication
public class SpringBootTestApplication {
#Bean(name = "TestServiceInterfaceImplBean")
TestServiceInterface getTestService() {
return new TestServiceInterfaceImpl();
}
#Autowired
public ServiceCaller serviceCaller;
public static void main(String[] args) {
ApplicationContext appContext = new
AnnotationConfigApplicationContext(SpringBootTestApplication.class);
Arrays.asList(appContext.getBeanDefinitionNames()).forEach(beanName ->
System.out.println(beanName));
SpringApplication.run(SpringBootTestApplication.class, args);
}
}
#Component()
public class ServiceCaller {
#Autowired
#Qualifier(value = "TestServiceInterfaceImplBean")
TestServiceInterface testService;
public ServiceCaller(){
System.out.println("############################### ServiceCaller");
}
}
//Service Interface
public interface TestServiceInterface {}
//Interface Implementation Class
public class TestServiceInterfaceImpl implements TestServiceInterface {
public TestServiceInterfaceImpl() {
System.out.println("############################### TestServiceInterfaceImpl");
}
}
I know by tagging #Service/#Component to TestServiceInterfaceImpl and removing #Bean and the method getTestService(), i can have #Autowire successful but i am just tyring to understand whether i can Autowire a Bean?
In this case i am getting below exception. By looking at the exception i am not able to understand where and how the loop is created.
Exception:
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| springBootTestApplication (field public com.SpringBootTestApplication.service.ServiceCaller com.SpringBootTestApplication.SpringBootTestApplication.serviceCaller)
↑ ↓
| serviceCaller (field com.SpringBootTestApplication.service.TestServiceInterface com.SpringBootTestApplication.service.ServiceCaller.testService)
└─────┘
Action:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
You'd better move below part to a Configuration (#Configuration) class:
#Bean(name = "TestServiceInterfaceImplBean")
TestServiceInterface getTestService() {
return new TestServiceInterfaceImpl();
}
#Autowired
public ServiceCaller serviceCaller;
then do the test again. And another point, for ServiceCaller, you can even define its order after the Bean of TestServiceInterfaceImplBean created.
the 2 configuration class like:
#Configuration
#AutoConfigureAfter({ MyConfiguration2.class })
public class MyConfiguration {
public MyConfiguration() {
}
#Autowired
public ServiceCaller serviceCaller;
}
#Configuration
public class MyConfiguration2 {
public MyConfiguration2() {
}
#Bean(name = "TestServiceInterfaceImplBean")
public TestServiceInterface getTestService() {
return new TestServiceInterfaceImpl();
}
}
I have spring component class annotated with #Component and in it I have field ConcurrentHashMap map, which is init in constructor of component and used in spring stream listener:
#Component
public class FooService {
private ConcurrentHashMap<Long, String> fooMap;
public FooService () {
fooMap = new ConcurrentHashMap<>();
}
#StreamListener(value = Sink.INPUT)
private void handler(Foo foo) {
fooMap.put(foo.id, foo.body);
}
}
Listener handle messages sent by rest controller. Can you tell me why I always got there fooMap.put(...) NullPointerException because fooMap is null and not initialzied.
EDIT:
After #OlegZhurakousky answer I find out problem is with async method. When I add #Async on some method and add #EnableAsync I can't anymore use private modificator for my #StreamListener method. Do you have idea why and how to fix it?
https://github.com/schwantner92/spring-cloud-stream-issue
Thanks.
Could you try using #PostConstruct instead of constructor?
#PostConstruct
public void init(){
this.fooMap = new ConcurrentHashMap<>();
}
#Denis Stephanov
When I say bare minimum, here is what I mean. So try this as a start, you'll see that the map is not null and start evolving your app from there.
#SpringBootApplication
#EnableBinding(Processor.class)
public class DemoApplication {
private final Map<String, String> map;
public static void main(String[] args) {
SpringApplication.run(DemoRabbit174Application.class, args);
}
public DemoApplication() {
this.map = new HashMap<>();
}
#StreamListener(Processor.INPUT)
public void sink(String string) {
System.out.println(string);
}
}
With Spring everything has to be injected.
You need to declare a #Bean for the ConcurrentHashMap, that will be injected in you Component. So create a Configuration class like:
#Configuration
public class FooMapConfiguration {
#Bean("myFooMap")
public ConcurrentHashMap<Long, String> myFooMap() {
return new ConcurrentHashMap<>();
}
}
Then modify your Component:
#Component
public class FooService {
#Autowired
#Qualifier("myFooMap")
private ConcurrentHashMap<Long, String> fooMap;
public FooService () {
}
#StreamListener(value = Sink.INPUT)
private void handler(Foo foo) {
fooMap.put(foo.id, foo.body); // <= No more NPE here
}
}
I'm trying to load properties once in my springboot application.
Actually, I have created a class to do that :
#Configuration
#PropertySource(value = { "classpath:parameters.properties", "classpath:iot.properties" })
public class PropertiesHelper {
#Autowired
protected Environment env;
private static Environment properties;
#PostConstruct
public void init() {
properties = env;
}
public static String getProperty(final String propertyName) {
return properties.getProperty(propertyName);
}
}
This class work fine but this is not clean code (sonar hate my static variable).
So, how can I load in my springboot application all my properties correctly and only once ?
#PropertySource("classpath:parameters.properties")
#PropertySource("classpath:iot.properties")
public class PropertiesHelper {
#Value( "${Value.you.need}" )
private String valueYouNeed;
}
parameters.properties
Value.you.need=12345
Make it something like this, it should be work in your scenario.
An elegant solution
If you just want to eliminate the sonar alarm(sonar hate my static variable)
// application.properties
spring.profiles.active=test1010
// IOC config bean container
#Configuration
#Data
public class PropertiesConfig{
#Value("${spring.profiles.active:preline}")
private String profiles;
}
//Use
#Autowired
private PropertiesConfig propertiesConfig;
#GetMapping("/getPropertiesConfig")
public String getPropertiesConfig(){
return propertiesConfig.getProfiles();
}
I think the above scheme is a more elegant way~,Do you have a better solution?
I am implementing a custom AccessDecisionVoter and I have a JPA repository which I need to autowire in the custom AccessDecisionVoter implementation. #Autowire is simply not working for neither a Service or Jpa Repository inside this class.
Project Structure
Application.java
#SpringBootApplication
#ComponentScan(basePackages="com")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
DynamicAuthorizationVoter.java
#Component
public class DynamicAuthorizationVoter implements AccessDecisionVoter<FilterInvocation> {
#Autowired
private PrivilegeRepository privilegeRepo;
#Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
#Override
public boolean supports(Class clazz) {
return true;
}
#Override
public int vote(Authentication authentication, FilterInvocation object, Collection<ConfigAttribute> collection) {
String url = determineModule(object);
if (authentication == null || authentication instanceof AnonymousAuthenticationToken) {
return ACCESS_ABSTAIN;
}
return isAccessGranted(authentication, object.getRequestUrl())? ACCESS_GRANTED : ACCESS_DENIED;
}
String determineModule(FilterInvocation filterObject){
String url = filterObject.getRequestUrl();
return url;
}
boolean isAccessGranted(Authentication authObject, String url){
Set<Privilege> privileges = privilegeRepo.findByUrl(url);
String userRole;
for(GrantedAuthority authority : authObject.getAuthorities()){
userRole = authority.getAuthority();
for(Privilege priv : privileges){
if(priv.equals(userRole)){
return true;
}
}
}
return false;
}
}
PrivilegeRepository.java
public interface PrivilegeRepository extends JpaRepository<Privilege, Long> {
Set<Privilege> findByName(String name);
Set<Privilege> findByUrl(String url);
}
For #Autowire to work inside the DynamicAuthorizationVoter class, I changed the #Component to #Service, #Configuration and everything else I found here on SO but none of them works. This JPA Repository is #Autowired everywhere else.
I will appreciate all the help.
-Adil
Usually, if you don't see any error during deployment, autowired worked fine because it is required by default. See the #Autowired documentation
Anyway, try to use an #Autowired constructor instead of an #Autowired property.
private PrivilegeRepository privilegeRepo;
#Autowired
public DynamicAuthorizationVoter(PrivilegeRepository privilegeRepo){
this.privilegeRepo = privilegeRepo;
}
With that, you could add a breakpoint to this constructor and debug it to know if the autowire process works well.
Also, remember that to use the DynamicAuthorizationVoter instance you mustn't declare it as new. You must include the following code in the related class where you want to use it.
#Autowired
AccessDecisionVoter dynamicAuthorizationVoter;
Hope it helps,
In this #Configuration-annotated class, the #Autowired Environment class is always null.
The code-sample below is taken directly from:
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/PropertySource.html
#Configuration
#PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
#Autowired
Environment env;
#Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
// some futher contitional stuff/checks etc. on the properties
String someProp = env.getProperty(...);
if(someProp.equals(...)) {
...
}
return testBean;
}
}
If I make the class implement EnvironmentAware the Environment is set correctly (and my code works).
#Configuration
#PropertySource("classpath:/com/myco/app.properties")
public class AppConfig implements EnvironmentAware {
Environment env;
#Bean
public TestBean testBean() {
// ...
}
#Override
public void setEnvironment(final Environment environment) {
this.environment = environment;
}
}
Any thoughts why the #Autowired approach does not work in #Configuration-annotated classes as expected, since autowiring the Environment in other beans works.
I think you must add #Bean annotation to Environment class, because if You want #Autowired class who is not signed as #Bean then it is impossible
Try injecting values directly:
#Configuration
#PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
#Value("${testbean.name}")
private String testbeanName;
#Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(testbeanName);
return testBean;
}
}