Spring之PropertyEditorRegistrySupport的讲解与使用

Spring之PropertyEditorRegistrySupport的讲解与使用,第1张

文章目录
      • 介绍
      • 使用
        • 使用默认属性编辑器
          • 源码浅述
          • 使用例子
        • 注册自定义属性编辑器

介绍

PropertyEditorRegistrySupport类实现了PropertyEditorRegistry接口。
其维护的是一系列java.beans包下的PropertyEditor;提供对默认属性编辑器和自定义属性编辑器的管理;该类主要作为BeanWrapperImpl基类。
其继承主要的继承关系如下图:

从类图来看,BeanWrapperImpl继承了PropertyEditorRegistrySupport类,所以学习BeanWrapperImpl的过程中,是有必要弄明白PropertyEditorRegistrySupport是个什么类,并且知道它是怎么玩的。

PropertyEditorRegistrySupport提供了如下方法:

方法描述
void setConversionService(@Nullable ConversionService conversionService)指定一个ConversionService用于转换属性值,作为JavaBeans 的PropertyEditors的替代方法。
ConversionService getConversionService()获取ConversionService
void registerDefaultEditors()defaultEditorsActive属性设置为true;标记该类注册默认的属性编辑器,可以通过getDefaultEditor(requiredType)方法来获取默认的属性编辑器。
void useConfigValueEditors()configValueEditorsActive属性设置为true;标记该类注册默认StringArrayPropertyEdito,其可以将字符串按照特定分隔符分割转换成数组。
void overrideDefaultEditor(Class requiredType, PropertyEditor propertyEditor)使用传入的propertyEditor覆盖requiredType类型的默认编辑器。这与注册自定义编辑器不同,因为该编辑器仍然是默认编辑器。 ConversionService将覆盖这样的默认编辑器,而自定义编辑器通常会覆盖ConversionService
PropertyEditor getDefaultEditor(Class requiredType)根据指定类型获取其对应的默认属性编辑器。
void registerCustomEditor(Class requiredType, PropertyEditor propertyEditor)注册指定类型的自定义属性编辑器。
void registerCustomEditor(@Nullable Class requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor)注册指定类型指定属性名的自定义属性编辑器。如果指定了propertyPath属性,并且没有额外注册requiredType对应的自定义属性编辑器,那么调用findCustomEditor()方法时就必须传入propertyPath
PropertyEditor findCustomEditor(@Nullable Class requiredType, @Nullable String propertyPath)根据类型和属性名来查找属性编辑器;
boolean hasCustomEditorForElement(@Nullable Class elementType, @Nullable String propertyPath)判断是否包含elementType类型对应的propertyPath属性值的属性编辑器。
使用 使用默认属性编辑器 源码浅述

如果要使用默认编辑器,我们需要通过getDefaultEditor(Class requiredType)方法来获取默认注册的属性编辑器,所以我们看该方法的源码:

从上面的源码可以看出,如果我们需要使用默认属性编辑器还需要将defaultEditorsActive属性设置成true,否则直接返回null
另外如果调用了overrideDefaultEditor()方法注册了覆盖特定类型的属性编辑器,则会优先从overriddenDefaultEditors中获取,如果overriddenDefaultEditors没有获取到,就会从defaultEditors集合中获取,defaultEditors在第一次调用getDefaultEditor()的时候进行创建加载。

接下来进入到createDefaultEditors();中看下:
org.springframework.beans.PropertyEditorRegistrySupport#createDefaultEditors

private void createDefaultEditors() {
		this.defaultEditors = new HashMap<>(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(Path.class, new PathEditor());
		this.defaultEditors.put(Pattern.class, new PatternEditor());
		this.defaultEditors.put(Properties.class, new PropertiesEditor());
		this.defaultEditors.put(Reader.class, new ReaderEditor());
		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());
		this.defaultEditors.put(ZoneId.class, new ZoneIdEditor());

		// Default instances of collection editors.
		// Can be 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);
		}
	}

如果开启了默认属性编辑器(defaultEditorsActive设置成了true),那么会调用上面的createDefaultEditors()方法,在该方法中,如上所看到的,会向defaultEditors集合中注册一系列类型的属性编辑器。


使用例子

如果要使用PropertyEditorRegistrySupport的默认属性编辑器,需要将defaultEditorsActive属性设置成true
但由于registerDefaultEditors()方法是protected权限:

所以本例子,我们通过反射来进行更改此属性。

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        PropertyEditorRegistrySupport registrySupport = new PropertyEditorRegistrySupport();

        // 将defaultEditorsActive设置成true,来使用默认编辑器
        Field defaultEditorsActive = PropertyEditorRegistrySupport.class.getDeclaredField("defaultEditorsActive");
        defaultEditorsActive.setAccessible(true);
        defaultEditorsActive.set(registrySupport, true);
        //使用值配置编辑器(String[]、short[]、int[]、long[])类型的转换
        registrySupport.useConfigValueEditors();

        //bool类型属性编辑器
        System.out.println("-------------默认boolean属性编辑器------------");
        PropertyEditor booleanEditor = registrySupport.getDefaultEditor(boolean.class);
        booleanEditor.setAsText("true");
        System.out.println("true->" + booleanEditor.getAsText());
        booleanEditor.setAsText("True");
        System.out.println("True->" + booleanEditor.getAsText());
        booleanEditor.setAsText("yes");
        System.out.println("yes->" + booleanEditor.getAsText());
        booleanEditor.setAsText("on");
        System.out.println("on->" + booleanEditor.getAsText());
        booleanEditor.setAsText("1");
        System.out.println("1->" + booleanEditor.getAsText());
        booleanEditor.setAsText("false");
        System.out.println("false->" + booleanEditor.getAsText());
        booleanEditor.setAsText("False");
        System.out.println("False->" + booleanEditor.getAsText());
        booleanEditor.setAsText("no");
        System.out.println("no->" + booleanEditor.getAsText());
        booleanEditor.setAsText("off");
        System.out.println("off->" + booleanEditor.getAsText());
        booleanEditor.setAsText("0");
        System.out.println("0->" + booleanEditor.getAsText());

        System.out.println("-------------字符串转数组(\"苹果,香蕉,橘子\")------------");
        registrySupport.getDefaultEditor(String[].class).setAsText("苹果,香蕉,橘子");
        String[] fruits = (String[]) registrySupport.getDefaultEditor(String[].class).getValue();
        for (int i = 0; i < fruits.length; i++) {
            System.out.println(i + ":" + fruits[i]);
        }
    }

输出结果:


注册自定义属性编辑器

除了PropertyEditorRegistrySupport给我们提供了默认常用类型的属性编辑器之外,我们还可以给特定类型自定义属性编辑器。
本例子中,我们有一个Address类,其中有省\市\区三个字段;我们还有一个用于将形如"湖南省|长沙市|望城区"的字符串转换成Address类对象的自定义属性编辑器:AddressPropertyEditor

package com.baiyang.bean;


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

    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 getDistrict() {
        return district;
    }

    public void setDistrict(String district) {
        this.district = district;
    }

    @Override
    public String toString() {
        return "Address{" +
                "province='" + province + '\'' +
                ", city='" + city + '\'' +
                ", district='" + district + '\'' +
                '}';
    }
}
package com.baiyang.bean;

import org.springframework.util.StringUtils;

import java.beans.PropertyEditorSupport;

/**
 * User: Yang Peng
 * DateTime:2022/5/13 16:26
 */
public class AddressPropertyEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        if (StringUtils.isEmpty(text)) {
            return;
        }
        String[] arrs = text.split("\|");
        Address address = new Address();
        if (arrs.length >= 1) {
            address.setProvince(arrs[0]);//省
        }
        if (arrs.length >= 2) {
            address.setCity(arrs[1]);//市
        }
        if (arrs.length > 2) {
            address.setDistrict(arrs[2]);//区
        }
        setValue(address);
    }
}

接下来我们通过下面的代码来注册我们自定义的AddressPropertyEditor并转换测试:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    PropertyEditorRegistrySupport registrySupport = new PropertyEditorRegistrySupport();

    // 将defaultEditorsActive设置成true,来使用默认编辑器
    Field defaultEditorsActive = PropertyEditorRegistrySupport.class.getDeclaredField("defaultEditorsActive");
    defaultEditorsActive.setAccessible(true);
    defaultEditorsActive.set(registrySupport, true);
    //使用值配置编辑器(String[]、short[]、int[]、long[])类型的转换
    registrySupport.useConfigValueEditors();

    registrySupport.registerCustomEditor(Address.class, new AddressPropertyEditor());
    PropertyEditor addressEditor = registrySupport.findCustomEditor(Address.class, null);
    System.out.println("-------湖南省------");
    addressEditor.setAsText("湖南省");
    System.out.println(addressEditor.getAsText());
    System.out.println("-------湖南省|长沙市------");
    addressEditor.setAsText("湖南省|长沙市");
    System.out.println(addressEditor.getAsText());
    System.out.println("-------湖南省|长沙市|望城区------");
    addressEditor.setAsText("湖南省|长沙市|望城区");
    System.out.println(addressEditor.getAsText());
}

输出结果:

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/915996.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存