Discover Spring's PropertyEditor
Today, a netizen consulting a question let me have a deep understanding of spring's propertyeditor mechanism, although it is probably known before, but all know what it is, but do not know how it is implemented in spring's entire mechanism. Today, take advantage of the noon leisure time to see the spring source of this aspect. So here is mainly through the analysis of spring source to understand PropertyEditor
.
In fact, the Java.beans in the JDK is the PropertyEditor
following class, which is provided by AWT for rendering purposes. Spring uses this interface to implement a Bean's property converter. The bean properties that we configure in spring XML or other ways are string-type values, but corresponding to each specific property is of various types, spring uses various types to PropertyEditor
convert the properties, which is PropertyEditor
not directly implemented in spring PropertyEditor
interface is a PropertyEditorSupport
class that blocks some of the methods that spring does not need, such as paintValue
providing a default implementation for them, so spring PropertyEditor
is implemented on a PropertyEditorSupport
basis. Let's take a look at PropertyEditor
the implementations that spring provides, and the following captures the implementation classes found through the IDE tools:
This basically involves all of the types provided by the JDK, knowing what Spring provides PropertyEditor
and PropertyEditor
how these are embedded in spring.
Propertyeditorregistry
Here is PropertyEditor
An example of how spring will be embedded within the spring framework BeanWrapperImpl
. First look at BeanWrapperImpl
the class diagram:
You can see BeanWrapperImpl
PropertyEditorRegistry
the sub-class that is actually. PropertyEditorRegistry
is actually an interface, to do the specific thing is PropertyEditorRegistrySupport
. PropertyEditorRegistrySupport
there is a method in which createDefaultEditors
this method is initialized by default in spring PropertyEditor
. Here's a look at which spring defaults PropertyEditor
:
private void Createdefaulteditors () {this.defaulteditors = new Hashmap<class<?>, propertyeditor> (64); Simple editors, without parameterization capabilities. The JDK does not contain a default editor for any of these target types. This.defaultEditors.put (Charset.class, New Charseteditor ()); This.defaultEditors.put (Class.class, New Classeditor ()); This.defaultEditors.put (Class[].class, New Classarrayeditor ()); This.defaultEditors.put (Currency.class, New Currencyeditor ()); This.defaultEditors.put (File.class, New Fileeditor ()); This.defaultEditors.put (Inputstream.class, New Inputstreameditor ()); This.defaultEditors.put (Inputsource.class, New Inputsourceeditor ()); This.defaultEditors.put (Locale.class, New Localeeditor ()); This.defaultEditors.put (Pattern.class, New Patterneditor ()); This.defaultEditors.put (Properties.class, New Propertieseditor ()); This.defaultEditors.put (Resource[].class, New Resourcearraypropertyeditor ()); ThiS.defaulteditors.put (Timezone.class, New Timezoneeditor ()); This.defaultEditors.put (Uri.class, New Urieditor ()); This.defaultEditors.put (Url.class, New UrlEditor ()); This.defaultEditors.put (Uuid.class, New Uuideditor ()); Default instances of collection editors. Can is overridden by registering custom instances of those as custom editors. This.defaultEditors.put (Collection.class, New CustomCollectionEditor (Collection.class)); This.defaultEditors.put (Set.class, New CustomCollectionEditor (Set.class)); This.defaultEditors.put (Sortedset.class, New CustomCollectionEditor (Sortedset.class)); This.defaultEditors.put (List.class, New CustomCollectionEditor (List.class)); This.defaultEditors.put (Sortedmap.class, New Custommapeditor (Sortedmap.class)); Default editors for primitive arrays. This.defaultEditors.put (Byte[].class, New Bytearraypropertyeditor ()); This.defaultEditors.put (Char[].class, New Chararraypropertyeditor ()); The JDK does not conTain a default editor for char! This.defaultEditors.put (Char.class, new Charactereditor (false)); This.defaultEditors.put (Character.class, New Charactereditor (true)); Spring ' s custombooleaneditor accepts more flag values than the JDK ' s default editor. This.defaultEditors.put (Boolean.class, new Custombooleaneditor (false)); This.defaultEditors.put (Boolean.class, New Custombooleaneditor (true)); The JDK does not contain default editors for number wrapper types! Override JDK Primitive number editors with our own customnumbereditor. This.defaultEditors.put (Byte.class, New Customnumbereditor (Byte.class, false)); This.defaultEditors.put (Byte.class, New Customnumbereditor (Byte.class, true)); This.defaultEditors.put (Short.class, New Customnumbereditor (Short.class, false)); This.defaultEditors.put (Short.class, New Customnumbereditor (Short.class, true)); This.defaultEditors.put (Int.class, New Customnumbereditor (Integer.class, false)); This.defaulteditOrs.put (Integer.class, New Customnumbereditor (Integer.class, true)); This.defaultEditors.put (Long.class, New Customnumbereditor (Long.class, false)); This.defaultEditors.put (Long.class, New Customnumbereditor (Long.class, true)); This.defaultEditors.put (Float.class, New Customnumbereditor (Float.class, false)); This.defaultEditors.put (Float.class, New Customnumbereditor (Float.class, true)); This.defaultEditors.put (Double.class, New Customnumbereditor (Double.class, false)); This.defaultEditors.put (Double.class, New Customnumbereditor (Double.class, true)); This.defaultEditors.put (Bigdecimal.class, New Customnumbereditor (Bigdecimal.class, true)); This.defaultEditors.put (Biginteger.class, New Customnumbereditor (Biginteger.class, true)); Only register config value editors if explicitly requested. if (this.configvalueeditorsactive) {Stringarraypropertyeditor SAE = new Stringarraypropertyeditor (); This.defaultEditors.put (String[].class, SAE); This.defaultEditors.put (Short[].class, SAE); This.defaultEditors.put (Int[].class, SAE); This.defaultEditors.put (Long[].class, SAE); }}
After executing this, then you BeanWrapperImpl
have the above type of conversion function, perhaps the above can be converted to the type does not meet our needs, then you can inject propertyeditor into spring in another way.
Propertyeditorregistrar
This interface has only one method void registerCustomEditors(PropertyEditorRegistry registry)
, the implementation of this method can be added to the incoming registry custom, in general, the PropertyEditor
incoming registry
BeanWrapperImpl
entity, so it is equivalent to inject the custom PropertyEditor
into the BeanWrapperImpl
inside. The question now is how PropertyEditorRegistrar
to inject into spring, so you can PropertyEditor
add custom to spring. Spring provides a class that is designed to inject a third party PropertyEditor
into it, and this class is a CustomEditorConfigurer
first look at the class diagram of this class:
Find that it implements the BeanFactoryPostProcessor
interface, then the method will be BeanDefinition
called after construction, postProcessBeanFactory
and only the whole method is the only way to embed spring, then look at what this method does:
public void Postprocessbeanfactory (Configurablelistablebeanfactory beanfactory) throws Beansexception {if (this.prope Rtyeditorregistrars! = null) {for (Propertyeditorregistrar PropertyEditorRegistrar:this.propertyEditorRegistrars ) {Beanfactory.addpropertyeditorregistrar (Propertyeditorregistrar); }} if (this.customeditors! = null) {for (map.entry<string,?> entry:this.customEditors.entrySet ()) {String key = Entry.getkey (); Object value = Entry.getvalue (); Class requiredtype = null; try {requiredtype = Classutils.forname (key, This.beanclassloader); if (value instanceof propertyeditor) {if (logger.iswarnenabled ()) {Logger.warn ("Passing propertyeditor instances into Customeditorconfigurer are deprecated:" + "use Prop Ertyeditorregistrars or PropertyEditor class names instead. " + "Offending key [" + Key + "; Offending editor Instance: "+ value"; } beanfactory.addpropertyeditorregistrar (New Sharedpropertyeditorregistrar ( Requiredtype, (propertyeditor) value); } else if (value instanceof Class) {beanfactory.registercustomeditor (Requiredtype, (Cla SS) value); } else if (value instanceof String) {Class Editorclass = classutils.forname (String) VA Lue, This.beanclassloader); Assert.isassignable (Propertyeditor.class, Editorclass); Beanfactory.registercustomeditor (Requiredtype, Editorclass); } else {throw new IllegalArgumentException ("Mapped value [" + Value + "] for custom EDI Tor key ["+ key +"] is not of required type ["+ PropertyEditor.class.getName () + "] or a corresponding Class or String value indicating a propertyeditor implementation"); }} catch (ClassNotFoundException ex) {if (this.ignoreunresolvableeditors) { Logger.info ("Skipping editor [" + value + "] for required type [" + Key + "]:" + (Requiredtype! = null?) "Editor": "Required type") + "class not found."); } else {throw new Fatalbeanexception ((requiredtype! = null ? "Editor": "Required Type") + "class not Found", ex); } } } }}
It is found that the methods it calls are beanFactory
configured PropertyEditorRegistrar
and customEditors
injected into the Spring bean factory. We just inject a Bean into the spring container CustomEditorConfigurer
, and then the settings propertyEditorRegistrars
and customEditors
properties can inject the custom PropertyEditor
into spring. Of course you can also use CustomEditorConfigurer
a class to customize a class to implement an BeanFactoryPostProcessor
interface, and then follow CustomEditorConfigurer
a similar path, or you can achieve the purpose. Here is a custom PropertyEditor
approximate process:
public class CustomPropertyEditor extends PropertyEditorSupport {@Overridepublic void setAsText(String text) throws IllegalArgumentException { super.setAsText(text);}@Overridepublic Object getValue() { return super.getValue();}}
The above is a definition of a customization PropertyEditor
, which needs to be PropertyEditor
injected into spring:
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="com.xx.foo.FooPojo" value="com.xx.foo.CustomPropertyEditor"/> </map> </property></bean>
Spring invokes methods to set the literal setAsText
value of the property, and then it needs to be converted to the corresponding Property object according to the specification you specify.
The following gives an ClassEditor
implementation, you can imitate this to achieve:
public class Classeditor extends PropertyEditorSupport {private final ClassLoader classloader;/** * Create a de Fault classeditor, using the thread context ClassLoader. */public Classeditor () {this (null);} /** * Create A default classeditor, using the given ClassLoader. * @param classLoader the ClassLoader to use * (or {@code null} for the thread context ClassLoader) */public Classeditor (Cl Assloader classLoader) {This.classloader = (ClassLoader! = null? ClassLoader:ClassUtils.getDefaultClassLoader ());} @Overridepublic void Setastext (String text) throws IllegalArgumentException {if (Stringutils.hastext (text)) {s Etvalue (Classutils.resolveclassname (Text.trim (), This.classloader)); } else {setValue (null); }} @Overridepublic String Getastext () {Class clazz = (Class) GetValue (); if (clazz! = null) {return classutils.getqualifiedname (clazz); } else {return ""; }}}
Exploring Spring's PropertyEditor