This is quite a common question in spring community. However even after referring many suggestions and answers, I couldn't get the below program to work correctly.
I need to inject a property of String type in Spring bean.
Here is the bean definition:
<bean id="AzoneMessageTransformer" class="com.test.wsg.RequestMessageTransformer">
<property name="converAndMarshal" value="false" />
</bean>
<bean id="BzoneMessageTransformer" class="com.test.wsg.RequestMessageTransformer">
<property name="converAndMarshal" value="false" />
<property name="authCode" >
<value>BZ</value>
</property>
</bean>
Here is the Spring bean:
public class RequestMessageTransformer implements InitializingBean {
private String authCode = null;
private boolean converAndMarshal = true;
public void setConverAndMarshal(boolean converAndMarshal) {
this.converAndMarshal = converAndMarshal;
}
public boolean isConverAndMarshal() {
return converAndMarshal;
}
public void setAuthCode(String authCode) {
this.authCode = authCode;
}
public String getAuthCode() {
return authCode;
}
}
Receiving the below error when context is getting initialized:
at java.lang.Thread.run(Thread.java:744)
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'authCode' of bean class [com.test.wsg.RequestMessageTransformer]: Bean property 'authCode' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1067)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:926)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:95)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:75)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1502)
Any help and suggestions for pointing out my mistake is much appreciated.
Thanks in advance!
authCode is string property, you should set property something like this
<bean id="BzoneMessageTransformer" class="com.test.wsg.RequestMessageTransformer">
<property name="converAndMarshal" value="false" />
<property name="authCode" value="BZ" />
</bean>
Related
Hi i got a little problem with my app.
I'm trying to get bean data from xml.
beans.xml
<bean id="s3Bean" class="com.example.demo.controller.S3Bean">
<property name="s3Host" value="${s3.host}" />
<property name="s3AccessKey" value="${s3.accessKey}"/>
<property name="s3SecretKey" value="${s3.secretKey}"/>
<property name="s3Bucket" value="${s3.bucket}"/>
</bean>
S3Bean.java
#ImportResource("classpath:beans.xml")
public class S3Bean {
private String s3Host;
private String s3AccessKey;
private String s3SecretKey;
private String s3Bucket;
public void setS3AccessKey(String s3AccessKey) {
this.s3AccessKey = s3AccessKey;
}
public void setS3SecretKey(String s3SecretKey) {
this.s3SecretKey = s3SecretKey;
}
public void setS3Bucket(String s3Bucket) {
this.s3Bucket = s3Bucket;
}
public void sets3Host(String s3Host) {
this.s3Host = s3Host;
}
}
Class also have getters.
In my controller im trying to get bean like that.
public S3Bean getS3Bean() {return S3Bean;}
public void setS3Bean(S3Bean s3Bean) {S3Bean = s3Bean;}
private S3Bean S3Bean;
...
S3Bean.getS3Host();
This get returns null pointer.
When im geting bean from application context it prints fine.
ApplicationContext ctx = new ClassPathXmlApplicationContext("/beans.xml");
S3Bean bean = ctx.getBean(S3Bean.class);
System.out.println(bean.toString());
Could you explain why the first way of getting property dosent working?
StackTrace
java.lang.NullPointerException: null
at com.example.demo.controller.hello.sayHello(hello.java:27) ~[classes/:na]
27 line is S3Bean.getS3Host();
I found out what was the problem. I didnt declared S3Bean in beans.xml.
<bean id="springBean.Impl" class="com.example.demo.controller.Impl">
<property name="S3Bean" ref="springBean.S3Bean"/>
</bean>
I have a class
public class DataStore {
public String name;
public String username;
public String password;
public String token;
public String connectionString;
public String type;
public String scheme;
public boolean usesBasicAuth;
public boolean usesBearerAuth;
}
I need to create an bean for it in another project. But i need to fill the fields somehow. The problem is I can not use <constructor-arg ... /> because there is no constructor.
The code below results in BeanCreationException: "Could not resolve matching constructor"
<bean id="dataStore"
class="com.fressnapf.sdk.dataaccess.services.DataStore">
<constructor-arg index="0" value="${spring.datastore.name}"/>
...
</bean>
Assuming, You have public (getters and setters for your) properties, and only the "default (no args) constructor", then You can change your configuration to:
<bean id="dataStore" class="com.fressnapf.sdk.dataaccess.services.DataStore">
<property name="connectionString" value="..."/>
<!-- ... -->
</bean>
Using property instead of constructor-arg.
Docs (Spring 4.2): https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/xsd-configuration.html
Yes, there is a constructor.
If you don't explicitly put one, Java will automatically add a default (non argument) constructor.
Use that one.
It will set all the instance variables to the default value of their type.
In your case: null for every String variable, false for every boolean.
I have found this subject that answered to what I was looking for :
how to pass values dynamically in config file
The thing is, when I try it, I have an Exception..
Error creating bean with name 'jobOperator' defined in class path resource [atlentic-Spring-Batch-common.xml]: Cannot resolve reference to bean 'jobExplorer' while setting bean property 'jobExplorer' [...]
Error creating bean with name 'connex' defined in class path resource [batch-calendar-context.xml]: Error setting property values;[...] Bean property 'dataSource' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
I'm trying to read a .ini file where I get DB info, then I would like to inject them into my XML datasource config.
Here is my xml,
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<beans:property name="driverClassName" value="${DB_DRIVER}" />
<beans:property name="url"
value="${DB_PROTOCOL}:#${DB_HOST}:${DB_PORT}:${DB_NAME}" />
<beans:property name="username" value="#{connex.user}" />
<beans:property name="password" value="#{connex.pass}" />
</beans:bean>
<beans:bean id="connex" class="com.sponge.bob.calendar.entity.CustomConnexion">
<beans:property name="dataSource" ref="dataSource" />
</beans:bean>
Then my CustomConnexiob.class where I use constructor to instantiate my attributs (it is not sexy, but I'm starting with SpringBatch) :
#Component
#Scope("step")
public class CustomConnexion {
public String user;
public String pass;
public String base;
#Autowired
private static final Logger LOGGER = LoggerFactory.getLogger(CustomConnexion.class);
public CustomConnexion() {
initConnexion();
}
public void initConnexion() {
IniReader reader = new IniReader();
setUser(reader.getProperty(Constants.MYCOMMON, Constants.USER));
setBase(reader.getProperty(Constants.MYCOMMON, Constants.BASE));
setPass(reader.getProperty(Constants.MYCOMMON, Constants.PASS));
}
/* getters and setters after this line (not printed here but they have the default name */
}
Is it possible to get this password and user dynamically using this way, I begin to lose my mind ?
Deinum,
thank you for your answer ! I tried to use UserCrendentialsDataSourceAdapter, but I didn't manage to make it work. But your observation about the scope make me try something I tried before writing this post.
Finally I used this :
<beans:bean id="connex" class="com.sponge.bob.calendar.entity.CustomConnexion">
</beans:bean>
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<beans:property name="driverClassName" value="${DB_DRIVER}" />
<beans:property name="url" value="${DB_PROTOCOL}:#${DB_HOST}:${DB_PORT}:${DB_NAME}" />
<beans:property name="username" value="#{connex.user}"/>
<beans:property name="password" value="#{connex.pass}"/>
</beans:bean>
and
#Component
#Scope("singleton") // <-- I changed this (it was "step" before)
public class CustomConnexion {
public String user;
public String pass;
public String base;
#Autowired
private static final Logger LOGGER = LoggerFactory.getLogger(CustomConnexion.class);
public CustomConnexion() {
initConnexion();
}
public void initConnexion() {
IniReader reader = new IniReader();
setUser(reader.getProperty(Constants.MYCOMMON, Constants.USER));
setBase(reader.getProperty(Constants.MYCOMMON, Constants.BASE));
setPass(reader.getProperty(Constants.MYCOMMON, Constants.PASS));
}
/* getters and setters after this line (not printed here but they have the default name */
}
my IniReader() just parse the .ini
I think you are getting username and password as null.
Remove calling initConnexion() from its constructor.
Add below annotation on top of initConnexion()
#PostConstruct
I am reading property files using below entry in my Spring xml.
<context:property-placeholder
location="classpath:resources/database1.properties,
classpath:resources/licence.properties"/>
I am injecting this values in variable using xml entry or using #Value annotation.
<bean id="myClass" class="MyClass">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="name" value="${database.name}" />
</bean>
I want to add a new property file(database2.properties) which has few same variable names as of database1.properties.
database1.properties:
database.driver=com.mysql.jdbc.Driver
database.url=jdbc:mysql://192.168.1.10/
database.name=dbname
database2.properties:
database.url=jdbc:mysql://192.168.1.50/
database.name=anotherdbname
database.user=sampleuser
You can see few property variables have same name like database.url, database.name in both the property files.
Is it possible to inject database.url of database2.properties?
Or I have to change variable names?
Thank you.
You can do it by configuring two PropertyPlaceholderConfigurer. Usually there's only one instance that serves out all the properties, however, if you change the placeholderPrefix you can use two instances, something like
<bean id="firstPropertyGroup" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:resources/database1.properties,
classpath:resources/licence.properties" />
<property name="placeholderPrefix" value="${db1."/>
</bean>
<bean id="secondPropertyGroup" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:resources/database2.properties" />
<property name="placeholderPrefix" value="${db2."/>"
</bean>
Then you would access your properties like ${db1.database.url} or ${db2.database.url}
There might be a solution, similar to what's that you want to achieve. Check the second answer to this question: Multiple properties access. It basically explains what to do in order to access the properties of the second file by using another expression, which is defined by you.
Otherwise, the simplest solution would be just changing the key values (the variable names).
You will sooner or later switch to Spring Boot. So with Spring Boot you can do have such POJO:
public class Database {
#NotBlank
private String driver;
#NotBlank
private String url;
#NotBlank
private String dbname;
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDbname() {
return dbname;
}
public void setDbname(String dbname) {
this.dbname = dbname;
}
}
and use #ConfigurationProperties to fill it:
#Bean
#ConfigurationProperties(locations="classpath:database1.properties", prefix="driver")
public Database database1(){
return new Database();
}
#Bean
#ConfigurationProperties(locations="classpath:database2.properties", prefix="driver")
public Database database2(){
return new Database();
}
Downside of this is that it's mutable. With Lombok library, you can eliminate nasty getters and setters.
I'm looking to populate a class with two HashMaps of types HashMap via spring injection. Unfortunately I'm getting the following error when I attempt to build my platform.
SEVERE: Exception sending context initialized event to listener instance of class de.hybris.platform.spring.HybrisContextLoaderListener
org.springframework.beans.FatalBeanException: Context hybris Global Context Factory couldn't be created correctly due to, Error creating bean with name 'EnumUtil' defined in class path resource [payment3dsi-spring.xml]: Cannot create inner bean 'util:map#4b13c655' of type [org.springframework.beans.factory.config.MapFactoryBean] while setting bean property 'stateCodes'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'util:map#4b13c655': Error converting typed String value for bean property 'sourceMap' with key [TypedStringValue: value [US-IL], target type [class java.lang.String]]; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type 'com.gsk.platform.payment3dsi.cardmanagement.CreditCardManagementServiceStub$StateProvinceCode'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.gsk.platform.payment3dsi.cardmanagement.CreditCardManagementServiceStub$StateProvinceCode]: no matching editors or conversion strategy found
I'm not sure why there are conversion errors? I should just be setting a key/value pair, no conversion needed. My bean looks like this:
<bean name="EnumUtil" class="com.gsk.platform.payment3dsi.util.EnumUtil" scope="tenant">
<property name="stateCodes">
<util:map map-class="java.util.HashMap" key-type="java.lang.String" value-type="com.gsk.platform.payment3dsi.cardmanagement.CreditCardManagementServiceStub.StateProvinceCode">
<entry key="US-IL" value="StateProvinceCode.Illinois" />
.
.
.....etc
</util:map>
</property>
<property name="countryCodes">
<util:map map-class="java.util.HashMap" key-type="java.lang.String" value-type="com.gsk.platform.payment3dsi.cardmanagement.CreditCardManagementServiceStub.CountryCode">
<entry key="US" value="CountryCode.UnitedStates" />
<entry key="CA" value="CountryCode.Canada" />
</util:map>
</property>
</bean>
My Enum class looks like the following:
package com.gsk.platform.payment3dsi.util;
import java.util.HashMap;
import java.util.Map.Entry;
import com.gsk.platform.payment3dsi.cardmanagement.CreditCardManagementServiceStub.CountryCode;
import com.gsk.platform.payment3dsi.cardmanagement.CreditCardManagementServiceStub.StateProvinceCode;
public class EnumUtil {
private HashMap<String, StateProvinceCode> stateCodes;
private HashMap<String, CountryCode> countryCodes;
private HashMap<String, StateProvinceCode> getStateCodes() {
return stateCodes;
}
private HashMap<String, CountryCode> getCountryCodes() {
return countryCodes;
}
public void setStateCodes(HashMap<String, StateProvinceCode> stateCodes) {
this.stateCodes = stateCodes;
}
public void setCountryCodes(HashMap<String, CountryCode> countryCodes) {
this.countryCodes = countryCodes;
}
public String getRegionCodeForStateCode(StateProvinceCode stateProvinceCode){
for(Entry<String, StateProvinceCode> entry : stateCodes.entrySet()){
if(entry.getValue().equals(stateProvinceCode)){
return entry.getKey();
}
}
return null;
}
public StateProvinceCode getStateCodeFromRegionCode(String regionCode){
return getStateCodes().get(regionCode);
}
public String getCountryIsoForCountryCode(CountryCode countryCode){
for(Entry<String, CountryCode> entry : countryCodes.entrySet()){
if(entry.getValue().equals(countryCode)){
return entry.getKey();
}
}
return null;
}
public CountryCode getCountryCodeFromCountryIso(String countryCode){
return getCountryCodes().get(countryCode);
}
}
And I'm attempting to use this class in my code in the following manner:
#Resource(name = "EnumUtil")
private EnumUtil enumUtil;
.
.
.
billingAddress.setStateProvinceCode(enumUtil.getStateCodeFromRegionCode(billingAddressData.getRegion().getIsocode()));
billingAddress.setCountryCode(enumUtil.getCountryCodeFromCountryIso(billingAddressData.getCountry().getIsocode()));
Any ideas on what the issue is here? I'm just looking to inject these two pre-populated maps into the class and not sure what the conversion error is from. Thanks!
I think you can try this option. It will be verbose though.
<property name="countryCodes">
<util:map map-class="java.util.HashMap" key-type="java.lang.String" value-type="com.gsk.platform.payment3dsi.cardmanagement.CreditCardManagementServiceStub.CountryCode">
<entry>
<key>US</key>
<value>
<bean class="com.gsk.platform.payment3dsi.cardmanagement.CreditCardManagementServiceStub.CountryCode">
<!-- Instantiate your country here --!>
</bean>
</value>
</entry>
.....
</util:map>
</property>