Spring source extension point four: custom property editor PropertyEditor

The power of Spring is not only that it provides great convenience for Java developers, but also that its open architecture allows users to have the greatest ability to extend Spring.

When we define bean in xml, the input content is all strings. Spring will parse these strings according to the registered property editor and instantiate them into the corresponding type.

One, source code related

1. Create a default propertyEditorRegister

Insert picture description here

Create a default PropertyEditorRegister in the prepareBeanFactory() method of the refresh() method of AbstractApplicationContext and put it into the beanFactory. This class is mainly responsible for injecting the following default property editors:

public void registerCustomEditors(PropertyEditorRegistry registry) {
    
    
		ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
		doRegisterEditor(registry, Resource.class, baseEditor);
		doRegisterEditor(registry, ContextResource.class, baseEditor);
		doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
		doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
		doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
		doRegisterEditor(registry, Path.class, new PathEditor(baseEditor));
		doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
		doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));

		ClassLoader classLoader = this.resourceLoader.getClassLoader();
		doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
		doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
		doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));

		if (this.resourceLoader instanceof ResourcePatternResolver) {
    
    
			doRegisterEditor(registry, Resource[].class,
					new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));
		}
	}
private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
    
    
		if (registry instanceof PropertyEditorRegistrySupport) {
    
    
			((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor);
		}
		else {
    
    
			registry.registerCustomEditor(requiredType, editor);
		}
	}

2. Call registerCustomEditors to complete the registration of PropertyEditor

When the spring source code instantiates the bean, after the BeanWrapperImpl is created, the registerCustomEditors() method is called to traverse all the propertyEditorRegister (including our custom propertyEditorRegister) classes to complete the injection of the property editor. as follows:
Insert picture description here

protected void initBeanWrapper(BeanWrapper bw) {
    
    
		bw.setConversionService(getConversionService());
		registerCustomEditors(bw);
	}

Insert picture description here

3. Call PropertyEditor to complete the analysis of properties

Insert picture description here

When populateBean fills in the properties, it will traverse each property value to obtain the corresponding property editor, and then call the setAsText() method of the corresponding property editor (PropertyEditor) to parse the corresponding value.

Second, the case

Address.java

package com.bobo.customeditor;

/**
 * @author bobo
 * @date 2020-10-21
 */

public class Address {
    
    
    private String province;
    private String city;
    private String area;

    public String getProvince() {
    
    
        return province;
    }

    public void setProvince(String province) {
    
    
        this.province = province;
    }

    public String getCity() {
    
    
        return city;
    }

    public void setCity(String city) {
    
    
        this.city = city;
    }

    public String getArea() {
    
    
        return area;
    }

    public void setArea(String area) {
    
    
        this.area = area;
    }

    @Override
    public String toString() {
    
    
        return "Address{" +
                "province='" + province + '\'' +
                ", city='" + city + '\'' +
                ", area='" + area + '\'' +
                '}';
    }
}

Person.java

package com.bobo.customeditor;

/**
 * @author bobo
 * @date 2020-10-21
 */

public class Person {
    
    
    private String name;
    private Address address;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Address getAddress() {
    
    
        return address;
    }

    public void setAddress(Address address) {
    
    
        this.address = address;
    }

    @Override
    public String toString() {
    
    
        return "Person{" +
                "name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}

AddressPropertyEditor

package com.bobo.customeditor;

import java.beans.PropertyEditorSupport;

/**
 * @author bobo
 * @date 2020-10-21
 */

public class AddressPropertyEdit extends PropertyEditorSupport {
    
    
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
    
    
        String[] split = text.split("-");
        Address address = new Address();
        address.setProvince(split[0]);
        address.setCity(split[1]);
        address.setArea(split[2]);
        setValue(address);
    }
}

AddressPropertyEditorRegister.java

package com.bobo.customeditor;


import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;

/**
 * @author bobo
 * @date 2020-10-21
 */

public class AddressPropertyEditorRegister implements PropertyEditorRegistrar {
    
    
    @Override
    public void registerCustomEditors(PropertyEditorRegistry registry) {
    
    
        registry.registerCustomEditor(Address.class,new AddressPropertyEdit());
    }
}

application-context.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.xsd">

    <bean id="person" class="com.bobo.customeditor.Person">
        <property name="name" value="bobo"/>
        <property name="address" value="广东省-深圳市-南山区"/>
    </bean>
    <!--第一种方式-->
    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="propertyEditorRegistrars">
            <list>
                <bean class="com.bobo.customeditor.AddressPropertyEditorRegister"></bean>
            </list>
        </property>
    </bean>
    <!--第二种方式-->
<!--    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">-->
<!--        <property name="customEditors">-->
<!--            <map>-->
<!--                <entry key="com.bobo.customeditor.Address">-->
<!--                    <value>com.bobo.customeditor.AddressPropertyEdit</value>-->
<!--                </entry>-->
<!--            </map>-->
<!--        </property>-->
<!--    </bean>-->
</beans>

test.java

package com.bobo;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    
    

    public static void main(String[] args) {
    
    
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
        System.out.println(context.getBean("person"));
    }
}

Run output:

Person{
    
    name='bobo', address=Address{
    
    province='广东省', city='深圳市', area='南山区'}}

Guess you like

Origin blog.csdn.net/u013277209/article/details/109201533