Spring: use properties read from a file - java

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.
}

Related

Not able to pass String to a constructor in Java using Spring

I'm trying to pass parameter to one of constructor of my BBFilter component, however it throws the exception that No beans of String type found. I have autowired the constructor as well. Am I doing anything wrong? Please advise
#Bean
public MyBean bbFilter() {
BBBean bbBean = new BBBean();
bbBean.setFilter(new BBFilter("plan1"));
}
BBFilter
#Component
public class BBFilter implements Filter {
private String planType;
#Autowired
public BBFilter(String planType) { --> Could not autowire. No beans of String type found
this.planType = planType;
}
}
I am assuming you are using Spring. The #Component annotation tells spring to automatically create an Instance of BBFilter as a Bean.
You also annotated the constructor with #Autowired. So Spring searches it's beans for fitting types and injects the automatically on construction. Since you probably didn't define any String bean it cannot autowire the String and throws an exception.
But since you want to create the Filter manually anyways you can simply remove both annotations from your BBFilter Class:
public class BBFilter implements Filter {
private String planType;
public BBFilter(String planType) {
this.planType = planType;
}
}
This should fix the exception but you also can no longer inject it anywhere else (per #Autowire) if needed.
Declare bean of BBFilter like
#Bean
public BBFilter bbFilter() {
return new BBFilter("plan1");
}
And use it in BBBean like this
#Bean
public MyBean bbFilter() {
BBBean bbBean = new BBBean();
bbBean.setFilter(bbFilter());
}
And remove #Component and #Autowired from BBFilter

Reading properties file using #Autowired Environment spring java Null pointer exception

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);
}
}

Trying to inject an object into JUnit test

I have had to adapt a project I've been working on to work differently, using an injected object (documentDao) to access the methods for adding/updating/etc. records in a database. Where necessary I simply injected this object into the constructor, but of course this won't work with JUnit tests (which can only have no-argument constructors), so I'm stuck on how to get the object into the test class.
The first code snippet shows a dumbed-down version of one of the test classes. The problem is that I need to create the documentDao object so I can pass it as an argument into the BackendApiController instantiation statement.
The second snippet is the first part of the DocumentDaoImpl class, which needs to be injected.
Any suggestions would be welcomed.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class ApiBackendTests {
#Configuration
#PropertySource(value = "classpath:system.properties")
static class ContextConfiguration {
}
private static BackendApiController backendApiController = new BackendApiController(documentDao);
#Test
public void retrieveSampleStatementList() {
String response = backendApiController.genericStatementList(x,y,z);
String eStatementId = "";
if (response.indexOf("_id") > 0) {
eStatementId = response.substring(response.indexOf("<_id>") + 5, response.indexOf("</_id>"));
}
// if this test is true, then at least one statement document was found in the above search.
assertTrue(response.indexOf("_id") > 0);
}
}
#Repository
public class DocumentDaoImpl<T> implements DocumentDao<T> {
public DocumentDaoImpl() {
}
#Inject
DBCollection dbCollection;
#Inject
GridFS gridFS;
#Autowired
ObjectMapper objectMapper;
#Override
public String insert(CommonDocument document) {
There's still not enough information to say anything for sure, but I believe you can try using #Autowired to wire up your needed component:
#Autowired
private DocumentDao documentDao;
You got the error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.roler.res.test.ApiBackendTests': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.roler.res.mongodb.dao.DocumentDao
That means Spring isn't aware of the DocumentDao bean yet. There are several ways to do that, but I think the easiest way is putting this in your configuration context:
<context:component-scan base-package="package.contain.your.dao"/>
It will tell Spring to scan the package in search for components with annotation.
UPDATE: since you don't use XML configuration, #ComponentScan is the way to go

Autowire a bean only if it is available

#Component
public class Test {
#Autowire
private MyBean myBean;
public void sampleMethod()
{
if(myBean == null) {
myBean = BeanFactory.getDefaultBean();
}
// ...
}
}
Is it possible to autowire MyBean if it is not defined in the spring configuration xml file? I understand that in this case, it would throw No bean found of type MyBean. Can we configure something to ignore that exception and fallback on the BeanFactory to get the DeafultBean.
Something like:
#Autowire(assignNullIfBeanNotFound = true)
Let's look at the javadoc (the annotation is named Autowired, and not Autowire):
public abstract boolean required
Declares whether the annotated dependency is required.
Defaults to true.
Isn't this idea of providing documentation for classes wonderful?

Can Spring Autowire beans created in a BeanFactoryPostProcessor

I have a standard bean with some properties that need to be autowired.
#Service
public class MyServiceImpl implements MyService {
#Autowired
private FirstRepository first;
public MyServiceImpl() {
}
I use a Java Config to find the beans:
#Configuration
#ComponentScan(basePackages = "com.company", excludeFilters = { #Filter(Configuration.class) })
public class MainConfig {
}
However, the FirstRepository Bean doesn't exist so I create it in a BeanFactoryPostProcessor:
public class RepoGeneratorPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
GenericBeanDefinition jpaR = new GenericBeanDefinition();
jpaR.setBeanClass(JpaRepositoryFactoryBean.class);
jpaR.setAutowireCandidate(true);
jpaR.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
jpaR.setLazyInit(false);
jpaR.setPropertyValues(new MutablePropertyValues().add("repositoryInterface", FirstRepository.class));
RootBeanDefinition definition = new RootBeanDefinition();
definition.setBeanClass(FirstRepository.class);
definition.setAutowireCandidate(true);
definition.setFactoryBeanName("&jpaR");
definition.setFactoryMethodName("getObject");
definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_NAME);
definition.setLazyInit(false);
definition.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
registry.registerBeanDefinition("jpaR", jpaR);
registry.registerBeanDefinition("first", definition);
}
When I start my application I get the following exception which seems to suggest that Spring can't find the FirstRepository bean.
org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.company.FirstRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
If I remove the #Autowired annotation I can see after start up that the FirstRepository bean is properly created.
Any suggestions?
This exception is saying that there is no bean defined for the FirstRepository class when the project is being built. Which I cannot see it here either.
The simplest solution would be to have a bean definition in your application-context.xml like this:
<bean id="firstRepository" class="your.package.FirstRepository" autowire="byName"/>
In this case, at the start up, there will be that bean definition.
I don't think you need the & before the beanname in
definition.setFactoryBeanName("&jpaR");
I used something like that in my project
definition.setFactoryBeanName("jpaR");
and it worked as expected
The & is needed if you need to get the factory bean of the bean named first.
&first should return jpaR.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-extension-factorybean

Categories