Inject class from bean with property HashMaps of <String, Class> - java

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>

Related

How to define a bean in ApplicationContext.xml that has no constructor?

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.

Spring Setter Injection on shadowed fields

I want to shadow a variable and change its type from boolean to string in its child class. Yet, the setter injection fails. I know it is a bad practice to use shadowing, however I would like to know if it is possible and how.
Example what I would like to do:
public class A {
public boolean field;
#SuppressWarnings("javadoc")
public boolean isField() {
return field;
}
#SuppressWarnings("javadoc")
public void setField(boolean field) {
this.field = field;
}
}
I want to shadow the attribute 'field' to be a String in the subclass.
public class B extends A {
private String field;
#SuppressWarnings("javadoc")
public String getField() {
return field;
}
#SuppressWarnings("javadoc")
public void setField(String field) {
this.field = field;
}
}
I get an exception that the setter Injection does not work:
org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.lang.String] to required type [boolean] for property 'field'
<bean id="exampleBean" class="B" >
<property name="field" value="value"/>
</bean>
Though I haven't tested it. But you can try the following way.
<bean id="beanA" class="A">
<property name="field" value="false"></property>
</bean>
<bean id="beanB" parent="beanA" class="B">
<property name="field" value="anyValue"></property>
</bean>
Let me know If it works for you.
Edit-
Please go through the Bean definition inheritance doc.
I have tested the example for shadowed field that you are using. You must have to configure a bean for parent class as well, because if you only configure bean for child class, you would get exception below -
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'helloWorld' is defined
I don't know what you are trying to accomplish using so-called shadowed fields. But here I have created a working example which might help you. Check it out.
MainApp.java
package com.example;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String args[]){
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
HelloWorld hw = (HelloWorld) context.getBean("helloWorld");
System.out.println("Is message:" + hw.isMsg());
HelloCountry hc = (HelloCountry) context.getBean("helloCountry");
System.out.println("Message:" + hc.getMessage());
}
}
class HelloWorld {
private boolean message;
public void setMessage(boolean message){
this.message = message;
}
public boolean isMsg(){
return message;
}
}
class HelloCountry extends HelloWorld {
private String message;
public void setMessage(String message){
this.message = message;
}
public String getMessage(){
return message;
}
}
Beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- A parent class bean must be defined to create its instance -->
<bean id = "helloWorld" class = "com.example.HelloWorld">
<property name = "message" value = "false"/>
</bean>
<bean id = "helloCountry" class = "com.example.HelloCountry">
<property name = "message" value = "Hello Country!!!"/>
</bean>
</beans>
Output
Note-
You would get a below exception only when you pass any value other than boolean in your parent bean. In your case, your data type of child class field is matching with the injected bean value, but you must have to have a configured bean for parent class as well. In short this is how It works Dependency Injection in case of Inheritance.-
Caused by: org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'java.lang.String' to required type 'boolean' for property 'message';
Let me know If it was helpful.

NotWritablePropertyException - When context is initialized - Spring

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>

Using Spring/ Hibernate /Jackson. Getting error -- Could not read JSON: Could not initialize class exception

We are using the combination of Jackson, spring and hibernate in our application.
Below code I am listing is working fine
Controller
#RequestMapping(value = ServiceEndpoints.MyService, method = RequestMethod.POST)
#ResponseBody
public MyResponse updateEntity(final HttpServletRequest request, #RequestBody final MyEntity myEntity ) {
//Service Call
}
Entity
#Entity
public class MyEntity extends BaseEntity implements Serializable {
#Column
private String metaTags;
public String getMetaTags() {
return metaTags;
}
public void setMetaTags(String metaTags) {
this.metaTags = metaTags;
}
servlet-contect.xml
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean id="mappingJacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper">
<ref bean="jacksonObjectMapper" />
</property>
</bean>
</list>
</property>
</bean>
The above code works Fine. We get data from UI, it gets converted from JSON to entity and we are able to save the same.
But then i added a code to clean some charatcers from the Entity field as shown below
public void setMetaTags(String comments) {
this.metaTags = MyClassWithStaticMethods.OnesuchStaticMethod(metaTags);
}
I get the below exception
Could not read JSON: Could not initialize class MyClassWithStaticMethods (through reference chain: MyEntity["metaTags"]);
nested exception is org.codehaus.jackson.map.JsonMappingException: Could not initialize class MyClassWithStaticMethods (through reference chain: MyEntity["metaTags"])
Now i did go through some links like this one
http://cowtowncoder.com/blog/archives/2010/08/entry_411.html
but this link is not really related to my problem.
Can any one please help
The issue was multiple versions of the same jar which was in turn used by "MyClassWithStaticMethods" (Thanks #Abhijith Nagarajan for asking to look into it).
My method was using guava API and another part of the application was using the old google-collections. These two were creating the problem.
Regards

ConversionNotSupportedException when using RuntimeBeanRefrence for a list of objects

We are currently using spring framework and are using following XML :-
<bean id="A" class="com.foo.baar.A" >
<property name="attributes">
<set value-type="com.foo.bar.B">
<ref bean="X" />
<ref bean="Y" />
</set>
</property>
</bean>
<bean id="X" class="com.foo.bar.X" />
<bean id="Y" class="com.foo.bar.Y" />
where class X and class Y extend class B
class A has setter as follows :-
public void setAttributes(List<B> attributes) {
this.attributes = attributes;
}
Now, I have to eliminate the above XML and I am setting the beans programatically as following :-
List<Object> beanRefrences = new ArrayList<Object>();
for(String attribute : attributes) {
Object beanReference = new RuntimeBeanReference(attribute);
beanRefrences.add(beanReference);
}
mutablePropertyValues.add(propertyName, beanRefrences);
With above code, I am getting following error :-
nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.util.ArrayList' to required type 'java.util.List' for property 'attributes';
nested exception is java.lang.IllegalStateException: Cannot convert value of type [org.springframework.beans.factory.config.RuntimeBeanReference] to required type [com.foo.bar.B] for property 'attributes[0]': no matching editors or conversion strategy found
Can anyone give me pointers on how to make it work correctly?
After taking a look at Spring's implementation of BeanDefinitionValueResolver one can see that a traditional, ordinary List is not sufficient. You need to use a ManagedList:
List<Object> beanRefrences = new ManagedList<>();
for(String attribute : attributes) {
Object beanReference = new RuntimeBeanReference(attribute);
beanRefrences.add(beanReference);
}
mutablePropertyValues.add(propertyName, beanRefrences);

Categories

Resources