I need to read properties file based on the input passed using the spring framework in a maven project. My property files and application context are present under src/main/resources
I am trying to use the environment api to inject the properties file.
Code:
#Component
#Configuration
#PropertySource("classpath:GeoFilter.properties")
public class CountryGeoFilter {
#Autowired
public Environment environment;
#Bean
public GeoFilterStore getCountryGeoFilter(String country) throws
CountryNotFoundException, IOException {
GeoFilterStore countryFilterStore = new GeoFilterStore();
String value = environment.getProperty(country);
if (value == null) {
throw CountryNotFoundException.getBuilder(country).build();
}
String[] seperateValues = value.split(":");
countryFilterStore.setGameStore(isTrueValue(seperateValues[0]));
countryFilterStore.setVideoStore(isTrueValue(seperateValues[1]));
return countryFilterStore;
}
private boolean isTrueValue(String possibleTrueValue) {
return !possibleTrueValue.equals("No") &&
!possibleTrueValue.equals("N/A");
}
}
But i keep getting null pointer exception at line "String value = environment.getProperty(country);"
My applicationContext.xml(src/main/resources)
<bean
class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:GeoFilter.properties" />
</bean>
I have also set the contextparam in my web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
I am initiating and calling the function in the following manner
CountryGeoFilter objGeo = new CountryGeoFilter();
GeoFilterStore response = objGeo.getCountryGeoFilter(country);
return response;
I am very new to spring and not sure where i am going wrong. Any help would be greatly appreciated.
EDIT:
I updated the initiating code to use context
ApplicationContext context = new
AnnotationConfigApplicationContext(CountryGeoFilter.class);
CountryGeoFilter testGeoFilter =
context.getBean(CountryGeoFilter.class);
testGeoFilter.getCountryGeoFilter(country);
Now i am getting the following exception
Exception in thread "main"
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'getCountryGeoFilter' defined in ..
Unsatisfied dependency expressed through method
'getCountryGeoFilter' parameter
0; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'java.lang.String' available: expected at
least 1 bean which qualifies as autowire candidate. Dependency
annotations: {}
I've added a basic working solution to this below. Essentially, remove #Bean on your getCountryGeoFilter() method, and change how you are invoking it. I've provided a sample invocation in an #RestController class.
Also, this configuration did not make use of any XML configurations.
TestClass.java
#Component
#Configuration
#PropertySource("classpath:test.properties")
public class TestClass {
#Autowired
Environment environment;
public String test (String property) {
final String value = environment.getProperty(property);
System.out.println("========> Property: " + value);
// TODO: Something with the prop val
return value;
}
}
test.properties
prop1=prop_1_value
prop2=prop_2_value
TestController.java
#RestController
#RequestMapping("/test")
public class TestController {
private TestClass testClass;
TestController(TestClass testClass) {
this.testClass = testClass;
}
#RequestMapping("/{propName}")
public String test(#PathVariable String propName) {
return testClass.test(propName);
}
}
Related
I have the following class :
public class ProducerWrapper<K, V> {
Producer<K, V> producer;
ThreadPoolExecutor threadPoolExecutor;
#Autowired
public ProducerWrapper(Properties p, int poolsize) {
......
log.info("Created kafka producer");
}
....
I try to inject it in a different service :
#Service
public class mainService{
#Qualifier("ProducerX")
#Autowired
private ProducerWrapper<Long,CustomObject1> p1;
#Autowired
#Qualifier("ProducerY")
private ProducerWrapper<Long,CustomObject2> p2;
And I created the following configuration :
#Configuration
#ComponentScan("main_package..")
public class MyConf {
#Bean(name = "ProducerX")
public ProducerWrapper<Long, CustomObject1> createProducerWrapper() throws IOException {
FileInputStream propertiesFile = new FileInputStream("producerx.properties");
properties = new Properties();
properties.load(propertiesFile);
return new ProducerWrapper<>(properties,5);
}
#Bean(name = "ProducerY")
public ProducerWrapper<Long, CustomObject2> createProducerWrapper() throws IOException {
FileInputStream propertiesFile = new FileInputStream("producery.properties");
properties = new Properties();
properties.load(propertiesFile);
return new ProducerWrapper<>(properties,5);
}
}
As you can see I have a different properties file for each producer. The error I'm getting is the following :
Error creating bean with name 'ProducerWrapper' defined in file [..../ProducerWrapper.class]: Unsatisfied dependency expressed through constructor parameter 1;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'int' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Parameter 1 of constructor in com.xx.xx.ProducerWrapper required a bean of type 'int' that could not be found.
If I remove the autowired annotation on top of the constructor, I'm getting a different error that the default constructor can't be found by Spring.
In addition, in the logs I see the following message that indicates that everything in the constructor was run :
2020-06-24 12:14:49.331 INFO 30912 --- [ main] c.a.a.ProducerWrapper : Created kafka producer
What am I doing wrong ?
You have this signature:
#Autowired
public ProducerWrapper(Properties p, int poolsize) {
...
You have not provided the "poolsize" parameter to be autowired. i.e. there's no integer that exists in your config that can be autowired into this variable.
To resolve this: Create a PoolSize class that wraps an int value. Then create a PoolSize object in your config to be autowired.
It says in the error output:
...No qualifying bean of type 'int' available: expected at least 1 bean which qualifies as autowire candidate.
I found the solution in the following stackoverflow post
Bottom line :
The constructor in the ProducerWrapper class shouldn't have any annotation :
//None annotation above constructor
public ProducerWrapper(Properties p, int poolsize) {
......
log.info("Created kafka producer");
}
Create a configuration class for the beans just like I pasted in my main comment.
3.Remove the Service annoatipn from the ProducerWrapper
I am trying to configure beans for Hadoop/Hive environment. According to documentation I need Apache Hadoop Configuration class, which should be autowired. See: http://docs.spring.io/spring-hadoop/docs/2.4.0.RELEASE/reference/html/springandhadoop-store.html (section 6.2.2 Configuring the dataset support)
Yet, when I try to run my app, I get: NoSuchBeanDefinitionException: No qualifying bean of type [org.apache.hadoop.conf.Configuration] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
My class is very simple:
#SpringBootApplication
public class HiveTestApp implements CommandLineRunner {
private
#Autowired
org.apache.hadoop.conf.Configuration hadoopConfiguration;
...
I am using Cloudera cluster, here are dependencies:
dependencies {
compile(
'org.springframework.boot:spring-boot-starter-web',
'org.springframework.data:spring-data-hadoop-hive:2.4.0.RELEASE-cdh5',
'org.apache.hive:hive-jdbc:1.1.0-cdh5.4.3',
)
Now, I might be wrong, but I can remember in the past I used autowired config, and it worked fine. Has anything changed in the latest version? Am I missing something?
OK here's the solution.
#Configuration
public class ApplicationConfiguration {
#Value("${com.domain.app.hadoop.fs-uri}")
private URI hdfsUri;
#Value("${com.domain.app.hadoop.user}")
private String user;
#Value("${com.domain.app.hadoop.hive.jdbc-uri}")
private String hiveUri;
#Autowired
private org.apache.hadoop.conf.Configuration hadoopConfiguration;
#Bean
public org.apache.hadoop.conf.Configuration hadoopConfiguration() {
return new org.apache.hadoop.conf.Configuration();
}
#Bean
public HdfsResourceLoader hdfsResourceLoader() {
return new HdfsResourceLoader(hadoopConfiguration, hdfsUri, user);
}
#Bean
public HiveTemplate hiveTemplate() {
return new HiveTemplate(() -> {
final SimpleDriverDataSource dataSource = new SimpleDriverDataSource(new HiveDriver(), hiveUri);
return new HiveClient(dataSource);
});
}
}
Configuration file below.
com.domain.app.hadoop:
fs-uri: "hdfs://hadoop-cluster/"
user: "hdfs-user"
hive.jdbc-uri: "jdbc:hive2://hadoop-cluster:10000/hive-db"
I've made Hadoop configuration object a bean, because I need to inject it in one of the classes. If you don't need a bean, you can just create new instance by yourself.
i'm new to the spring framework and i'm having some problems trying to read and use properties from a file.
To summarize, what i want to do is to define a class which stores all the properties read, a second class that uses those properties to do something and a third class that uses the results.
The class that stores the properties is:
#Configuration
public class PropertyClass {
#Value("${propertyName")
private Integer propertyName;
#Bean(name = "propertyName")
public Integer getPropertyName() {
return propertyName;
}
}
The class that reads and uses those properties:
#Component
public class PropertyReader {
private Integer myProperty;
#Autowire
#Qualifier("propertyName")
public void setMyProperty(
Integer myProperty) {
this.myProperty = myProperty;
}
public Integer getValue() {
//do something with myProperty
return result;
}
}
And the class that uses PropertyReader:
public class Utilizer {
private PropertyReader getPropertyReader() {
ApplicationContext context = new AnnotationConfigApplicationContext(PropertyReader.class);
PropertyReader reader = (BakerStorageClassConfigHelper)context.getBean("PropertyReader");
return reader;
}
}
I've registered the classes as beans in the application-config.xml file:
<bean class="property.class.package.PropertyClass" depends-on="Environment" />
<bean class="reader.class.package.PropertyReader" />
And i have an environment.xml file where the "Environment" bean is defined with location rules to find the property files.
Now what happens that in the class "Utilizer" when i try to get the "ApplicationContext" object an exception is thrown:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'PropertyReader':
Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire method: public void reader.class.package.PropertyReader.setMyProperty(java.lang.Integer);
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.Integer]
found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
I've tried to change the annotation of PropertyReader class to #Repository or #Service and tried to add a #ComponentScan with the PropertyClass package specified but none of that worked for me..
Could someone give me some advices?
Thank you!
I do not quite get why do you need to declare propertyName as Integer.
If what you need is just get the properties from file, then you can define a PropertiesFactoryBean and autowire it to any other beans you like.
Let's say you have a myValues.properties file containing values:
key1=value1
key2=value2
Define Bean:
#Bean(name = "myProperties")
public PropertiesFactoryBean detailQueriesFactoryBean()
{
PropertiesFactoryBean pfb = new PropertiesFactoryBean();
pfb.setLocation(new ClassPathResource("com/xxx/myValues.properties"));
return pfb;
}
Now wherever you need it, do:
#Autowired
#Qualifier("myProperties")
private Properties myValuesContainer;
public void myMethod(){
//this will get you "value1"
String value1 = myValuesContainer.getProperty("key1");
}
Hope this works for you.
--------------------- For your case----------------
If it is already in the application context, you can use #Value to inject value directly in your PropertyReader and add getter/setter for them. No need a PropertyClass, right?
Or you can add a #PostConstruct method to PropertyReader. Inside the method, you can retrieve the values you need from the existing context.
#PostContstruct
public void extractValues(){
//retrieve value from context and assign to whichever var.
}
My tomcat is refusing to launch my application due to this error
Error creating bean with na
me 'Individual_Controller': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Cou
ld not autowire field: private net.service.datastore.Indiv
idual_Service net.controller.Individual_Controller.S
ervice; nested exception is org.springframework.beans.factory.NoSuchBeanDefiniti
onException: No qualifying bean of type
[net.service.datastore.Individual_Service] found for dependency: expected at least 1 bean which qu
alifies as autowire candidate for this dependency. Dependency annotations: {#org
.springframework.beans.factory.annotation.Autowired(required=true)}
expected at least 1 bean which qualifies a
s autowire candidate for this dependency. Dependency annotations: {#org.springfr
amework.beans.factory.annotation.Autowired(required=true)}
this is my service class
public long createT(Individual individual);
public Individual updateT(Individual individual);
public void deleteT(String tin);
public List<Individual> getAllTs();
public Individual getT(String t);
public List<Individual> getAllTs(String individual);
this is my controller class that is calling the service layer
#Autowired
private Individual_Service service;
#RequestMapping("searchT")
public ModelAndView searchT(#RequestParam("searchName") String searchName) {
logger.info("Searching the T: "+searchName);
List<Individual> tList = service.getAllTs(searchName);
return new ModelAndView("serviceDescription", "tList", tList);
}
this is the complete controller class
#Controller
public class IndividualController {
private static final Logger logger = Logger.getLogger(IndividualController.class);
public IndividualController() {
System.out.println("Individual_Controller()");
}
#Autowired
private IndividualService service;
#RequestMapping("searchT")
public ModelAndView searchT(#RequestParam("searchName") String searchName) {
logger.info("Searching the T: "+searchName);
List<Individual> tinList = service.getAllTs(searchName);
return new ModelAndView("serviceDescription", "tList", tList);
}
complete service interface class for the individual_service
package net.service.datastore;
import java.util.List;
import net.model.Individual;
public interface IndividualService {
public long createT(Individual individual);
public Individual updateT(Individual individual);
public void deleteT(String t);
public List<Individual> getAllTs();
public Individual getT(String t);
public List<Individual> getAllTs(String individual);
}
Please what could be wrong?
Looks like no bean of class Individual_Service is loaded in Application Context. There can be multiple reasons for that.
If you are using xml based configuration , please make sure that xml file is either included in web.xml using ContextLoaderListner.
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring-bean.xml
</param-value>
</context-param>
or in dispatcher-servlet.xml / applicationContext.xml
<import resource="classpath:bean.xml" />
If you are using annotation based Approach , make sure the class is properly annotated with #Component or #Bean or #Service or any other annotation based on application requirement.
Make sure path in context:component-scan is covering the package of Individual_Service.java
<context:component-scan base-package="net.service.datastore.*" />
Hope one of these point resolve your issue.
If not can you please provide your web.xml , dispatcher-servlet.xml or Spring configuration class and Individual_Service.java .
There's some information missing to provide a complete answer.
But basically, you should make sure of the following:
Your IndividualService implementation class should be annotated with #Service
Your IndividualController class should be annotated with #Controller
The field IndividualService in IndividualController should be annotated with #Autowired (or #Inject)
Both classes should be scanned in your Spring context config class (or file)
Here is how it should look like :
IndividualService.java :
package com.company.myapp.service;
//...imports...
#Service
public class IndividualService {
//.. fields/methods...
}
IndividualController.java :
package com.company.myapp.controller;
//...imports...
#Controller
public class IndividualController{
#Autowired
private IndividualService individualService;
//.. other fields/methods...
}
MyAppConfiguration.java :
package com.company.myapp;
//...imports...
#Configuration
#EnableWebMvc
//...other Spring config annotation...
#ComponentScan(basePackages = "com.company.myapp")
public class MyAppSpringConfiguration{
//...other configuration...
}
To know which class is your Spring config class, you should have a look at your webapp descriptor file (web.xml), and see which contextConfigLocation is provided as param to the Spring servlet (DispatcherServlet). If your're user servlet 3+ without web.xml, look for a class that implements WebApplicationInitializer.
I have a requestScope bean, regular Java bean, and Spring configuration just like the code shown below. May I know how can I access the bean's property from regular Java code that is configured with Spring?
Managed Bean
#ManagedBean(name="requestBean")
public class RequestBean {
private String theID;
/** getter and setter of theID **/
}
Spring Bean
public class SpringBean {
private RequestBean theBean = null;
// how could I access the RequestBean.theID from this class ??
}
Spring configuration
<bean id="springBean" class="org.huahsin.SpringBean"/>
Maybe I do not understand the question, but I think it is simply by calling the getter:
public class SpringBean {
private RequestBean theBean = null;
...
public void aCallingMethod() {
if (theBean != null) {
theBean.getTheId(); // <-- here it is !!
}
}
}
EDIT
To inject the request bean into the Spring bean, either you use an #Autowired annotation:
public class SpringBean {
#Autowired
private RequestBean theBean = null;
...
}
Either you inject it in your XML file:
<bean id="springBean" class="org.huahsin.SpringBean">
<property name="theBean" ref="requestBean"/>
</bean>