I searched the documentation in Spring and also in Pro Spring. I don't understand how does CustomerEditorConfigurer knows where it should apply property conversion. Ex -
I have a Contact Class which has a date variable(jodatTime) I created a ContactPropertyEditor whcih extends PropertyEditorSupport and I am using setAsText() to convert the String date.
I then go in application and define CustomerEditorConfigurer where I am telling it to map jodaTime to ContactPropertyEditor. Now this does not have information which tells Spring that when a Contact class is created then do the conversion using ContactPropertyEditor.
So to test out my theory I created another class Contact2 with same property(Date) as Contact. When I run the conversion happens for Contact2 as well, which is little weird.
Here is the code sample Contact.java
public class Contact {
private String firstName;
private String lastName;
private DateTime birthDate;
private URL personalSite;
public String toString() {
return "First name: " + getFirstName()
+ " - Last name: " + getLastName()
+ " - Birth date: " + getBirthDate()
+ " - Personal site: " + getPersonalSite();
}
// Getter/setter methods omitted
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public DateTime getBirthDate() {
return birthDate;
}
public void setBirthDate(DateTime birthDate) {
this.birthDate = birthDate;
}
public URL getPersonalSite() {
return personalSite;
}
public void setPersonalSite(URL personalSite) {
this.personalSite = personalSite;
}
}
ContactPropertyEditor.java import java.beans.PropertyEditorSupport;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.stereotype.Component;
public class ContactPropertEditor extends PropertyEditorSupport{
private DateTimeFormatter dateTimeFormatter;
public ContactPropertEditor(String formatPattern){
System.out.println("In the constructor");
dateTimeFormatter=DateTimeFormat.forPattern(formatPattern);
}
public void setAsText(String text) throws IllegalArgumentException{
System.out.println("Setting the value of " + text);
setValue(DateTime.parse(text, dateTimeFormatter));
}
}
applicationContext.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" xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.dinesh"></context:component-scan>
<context:annotation-config />
<!-- This holds the property values and formats -->
<context:property-placeholder location="classpath:application.properties" />
<bean class="com.dinesh.PropertyEditor.ContactPropertEditor" id="contactPropertEditor">
<constructor-arg><value>"yyyy-MM-dd"</value></constructor-arg>
</bean>
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="org.joda.time.DateTime">
<ref local="contactPropertEditor" />
</entry>
</map>
</property>
</bean>
<bean id="clarence" class="com.dinesh.PropertyEditor.Contact"
p:firstName="Clarence" p:lastName="Ho" p:birthDate="1970-12-31"
p:personalSite="http://www.clarence.com" />
<bean id="contact2" class="com.dinesh.PropertyEditor.Customer2"
p:firstName="Clarence" p:lastName="Ho" p:birthDate="1970-12-31"
p:personalSite="http://www.clarence.com" />
Now as you can see all I am doing is telling org.springframework.beans.factory.config.CustomEditorConfigurer that my proprty conversion logic is contactPropertEditor class. I do not tell Spring that apply this on Contact.java class.
How is the magic happening.
In the Spring documentation it says something else which makes sense.
The Spring documentation has a Class called ExoticType() which has name property. A editor calss called ExoticTypeEditor is used to chaage the name to Upper case and application context xml is clear
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="example.ExoticType" value="example.ExoticTypeEditor"/>
</map>
</property>
Here I can see that I am telling CustomEditorConfigurer that apply conversion on class ExoticType using ExoticTypeEditor but it is not the case in Pro Spring 3 book. I tried to do the same in Contact Example but got an error.
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="com.dinesh.PropertyEditor.Contact">
<ref local="contactPropertEditor" />
</entry>
</map>
</property>
</bean>
Error : Cannot convert value of type [java.lang.String] to required type [org.joda.time.DateTime] for property 'birthDate': no matching editors or conversion strategy found
Any idea what am I missing?
When you register a PropertyEditor
in application context, you are providing the converter from String
to some type, in your case the JodaTime
type. The bean holding the type, (Contact
) don't matter. The application context will use your ContactPropertyEditor
editor any time that need to set a property of type JodaTime
as String
on any bean.
So ContactPropertyEdit
it's a bad name. It should be JodaTimePropertyEditor.
If you want a real ContactPropertyEditor
, it should convert Strings to Contacts. For example:
<bean id="someBeanHoldingAContact" class="someBeanClass">
<property name="contact" value="Hendrix, Jimi, 1942-11-27, http://www.jimihendrix.com" />
</bean>
and the ContactPropertyEditor should use the string value to create the contact.
The magic is in org.springframework.beans.BeanWrapperImp
class. See the javadoc