Let’s look at how the custom property editor do the job for us. Before that I’ll first demo if we didn’t use PropertyEditor, Spring will not understand what exactly the type and how can convert. Therefore exception are throw.
public class Holiday { private String id; private Calendar holiday; public Holiday() { //empty constructor } public String getId() { return id; } public void setId(String id) { this.id = id; } public Calendar getHoliday() { return holiday; } public void setHoliday(Calendar holiday) { this.holiday = holiday; } }
PropertyEditorTest
public class PropertyEditorTest { private Calendar todayHoliday; public static void main(String[] args) { GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(); ctx.load("classpath:/test-applicationcontext.xml"); ctx.refresh(); Holiday holiday = ctx.getBean(Holiday.class); PropertyEditorTest test = new PropertyEditorTest(); test.todayHoliday = holiday.getHoliday(); System.out.println(test.todayHoliday.get(Calendar.MONDAY)); System.out.println(test.todayHoliday.get(Calendar.DAY_OF_MONTH)); System.out.println(test.todayHoliday.get(Calendar.YEAR)); } }
ApplicationContext.xml
<bean id="holiday" class="com.eweol.init.Holiday"> <property name="id"> <value>Independent</value> </property> <property name="holiday"> <value>31-08-2014</value> </property> </bean>
Result
.ConversionNotSupportedException: Failed to convert property value of type ‘java.lang.String’ to required type ‘java.util.Calendar’ for property ‘holiday’; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [java.util.Calendar] for property ‘holiday’: no matching editors or conversion strategy found
Generally all input from the application context are consider string, spring does not know how to convert from string to calendar. So we need to provide a property editor to let spring have sufficient information to do the conversion for us.
public class StringToCalenderPropertyEditor extends PropertyEditorSupport { private static DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); public String getAsText() { Calendar value = (Calendar) getValue(); Date dateTime = new Date(value.getTimeInMillis()); return (value != null ? formatter.format(dateTime) : ""); } public void setAsText(String text) throws IllegalArgumentException { Date date = null; try { date = formatter.parse(text); } catch (ParseException e) { e.printStackTrace(); date = new Date(); } Calendar cal = Calendar.getInstance(); cal.setTime(date); setValue(cal); } }
Modified the applicationContext
<bean id="holiday" class="com.eweol.init.Holiday"> <property name="id"> <value>Independent</value> </property> <property name="holiday"> <value>31-08-2014</value> </property> </bean> <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="java.util.Calendar"> <bean class="com.example.StringToCalenderPropertyEditor"/> </entry> </map> </property> </bean>
Result
7
31
2014
You can find the spring conversion tutorial here
Spring version 4.x
Spring 4.x slightly change the behaviour of CustomEditorConfigurer. If you run above code with spring version 4.0 library. You may see the error like this.
BeanCreationException: Error creating bean with name 'customEditorConfigurer' defined in class path resource .... TypeMismatchException: Failed to convert property value of type 'java.util.LinkedHashMap' to required type 'java.util.Map' for property 'customEditors'; ....
In Spring 3.2.x – customEditors are Map<String, ?>
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="com.octworks.ioc.propertyeditor.Name"> <bean class="com.codeomitted.HolidayPropertyEditor"/> </entry> </map> </property> </bean>
Spring 4.x it change to Map<Class<?>, Class<? extends PropertyEditor>>, the solution is to remove the inner bean as part of the entry value.
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="com.xx.xx.Name" value="com.xx.xx.NameEditor"/> <entry key="java.util.Calendar"value="com.xx.xx.HolidayPropertyEditor" /> </map> </property> </bean>
Alternative
Alternative we can use custom propertyEditorRegistrar implementation.
Step 1. Create your own registrar, CustomNameEditorRegistrar
public class CustomNameEditorRegistrar implements PropertyEditorRegistrar { public void registerCustomEditors(PropertyEditorRegistry registry) { registry.registerCustomEditor(Name.class, new NamePropertyEditor()); } }
Step 2. Register to customEditorConfigurer
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="propertyEditorRegistrars"> <list> <bean class="com.codeomitted.CustomNameEditorRegistrar"/> </list> </property> </bean>
Done
well done