springpropertyeditor

How does Spring PropertyEditor know which Class propert to convert


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?


Solution

  • 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