您的位置:首页 > 其它

jface databinding:构建一个改进版的通用型数值验证器StringToNumberValidator

2016-12-25 11:13 337 查看
jface已经提供了基于AbstractStringToNumberValidator的基本类型数值验证器IValidator



但是在项目实际使用中发现这些验证器有缺点:

空字符串被视为合法,可以通过验证,而一般情况下,我们会视空字符串为无效输入

数值解析错误时返回的信息为英文而且太详细,用户体验不好。其实如果用户输入了非数字导致解析错误时只要提示输入无效就可以了,没必要太详细,更不能是英文。

如上图每种数据类型验证都对应一个不同的类,这在项目中可能会增加不必要的代码复杂度,如果统一成一个类使用更加方便,也减少写代码的工作量。

针对这些问题,参考AbstractStringToNumberValidator的源码,我构建了一个通用型的数值验证器类StringToNumberValidator,支持Integer,Long,Float,Double,Byte,Short,BigInteger,BigDecimal等Number类型的通用验证器,基本的原理就是尝试用StringToNumberConverter来对字符串进行解析如果解析成功并数值范围符合要求就返回OK,否则返回ERROR,代码下如。

StringToNumberValidator.java

package testwb;

import java.math.BigDecimal;
import java.math.BigInteger;
import org.eclipse.core.databinding.conversion.StringToNumberConverter;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.internal.databinding.validation.NumberFormatConverter;
import org.eclipse.core.runtime.IStatus;

/**
* 通用型数值验证器<br>
* 支持Integer,Long,Float,Double,Byte,Short,BigInteger,BigDecimal等Number类型<br>
* 可用于beforeSetValidator,afterGetValidator和validateAfterConvert的数值验证器<br>
* 自动判断输入数据类型,如为String则调用 {@link #converter}进行类型转换<br>
* 空字符串被视为无效输入<br>
* 可根据需要重写 {@link #isInRange(Number)}实现数值范围验证<br>
* @author guyadong
*
*/
public class StringToNumberValidator implements IValidator {
/**
* 数据类型转换器
*/
private final StringToNumberConverter converter;
/**
* 根据目标数据类型构造对象
* @param toType 目标数据类型
*/
public StringToNumberValidator(Class<? extends Number> toType){
this.converter=createConverter(toType);
}

/**
* 根据目标数据类型创建对应的{@link StringToNumberConverter}对象
* @param toType
* @return
*/
private static final StringToNumberConverter createConverter(Class<? extends Number> toType) {
if (Integer.class.equals(toType) || Integer.TYPE.equals(toType)) {
return StringToNumberConverter.toInteger(false);
} else if (Long.class.equals(toType) || Long.TYPE.equals(toType)) {
return StringToNumberConverter.toLong(false);
} else if (Float.class.equals(toType) || Float.TYPE.equals(toType)) {
return StringToNumberConverter.toFloat(false);
} else if (Double.class.equals(toType) || Double.TYPE.equals(toType)) {
return StringToNumberConverter.toDouble(false);
} else if (Byte.class.equals(toType) || Byte.TYPE.equals(toType)) {
return StringToNumberConverter.toByte(false);
} else if (Short.class.equals(toType) || Short.TYPE.equals(toType)) {
return StringToNumberConverter.toShort(false);
}else if (BigInteger.class.equals(toType)) {
return StringToNumberConverter.toBigInteger();
}else if (BigDecimal.class.equals(toType)) {
return StringToNumberConverter.toBigDecimal();
}
throw new IllegalArgumentException("invalid type");
}
@Override
public final IStatus validate(Object value) {
boolean ok=false;
try{
// 输入值value为String时,调用converter进行数据类型转换,
// 否则直接对value进行强制类型转换
Number number = value instanceof String
?(Number) converter.convert(value)
:(Number) value;
// 为null时抛出异常,空字符串视为无效输入
if (null==number) throw new IllegalArgumentException("result is null");
if (isInRange(number)) {
// 验证通过,返回状态为OK
ok=true;
return ValidationStatus.ok();
}else
// 数值超范围,返回验证状态为ERROR
return ValidationStatus.error(getOutOfRangeMessage());
}catch(Exception e){
// 捕获所有Exception(converter转换异常或number为null),返回验证状态为ERROR
return ValidationStatus.error(getInvalidNumberMessage(e));
}finally{
result(ok);
}
}
/**
* 验证数值有效范围<br>
* 被 {@link #validate(Object)}调用
* @param number
* @return
*/
protected boolean isInRange(Number number) {    return true;}
/**
* 方法结束时调用
* @param ok 验证结果,为true时验证通过
*/
protected void result(boolean ok){}
/**
* {@link #isInRange(Number)}为false时,返回错误信息
* @return
*/
protected String getOutOfRangeMessage(){    return "数值不在允许的范围"; }
/**
* 数字无效时返回错误信息(converter返回错误或为null)
* @param e 异常中包含详细错误信息
* @return
*/
protected String getInvalidNumberMessage(Exception e){
//return e.getMessage();//使用这一行可以返回详细错误信息
return "无效数字";
}
public NumberFormatConverter getConverter() {
return converter;
}
/**
* 适合Lambda表达式创建实例的静态方法(需要java1.8支持)<br>
* 除toType为null抛出异常外,其他参数为null则调用父类方法
* @param toType 目标数据类型
* @param inRange 数据范围验证
* @param result 数据结果响应
* @param outOfRangeMessage 数值超范围错误信息
* @param invalidNumberMessage 无效数字错误信息
* @return
*/
public static StringToNumberValidator create(Class<? extends Number> toType,
Function<Number, Boolean> inRange,
Consumer<Boolean> result,
Supplier<String> outOfRangeMessage,
Function<Exception, String> invalidNumberMessage) {
return new StringToNumberValidator(toType) {
@Override
protected boolean isInRange(Number number) {
return null == inRange ? super.isInRange(number) : inRange.apply(number);
}
@Override
protected void result(boolean ok) {
if(null!=result)
result.accept(ok);
}
@Override
protected String getOutOfRangeMessage() {
return null==outOfRangeMessage?super.getOutOfRangeMessage():outOfRangeMessage.get();
}
@Override
protected String getInvalidNumberMessage(Exception e) {
return null==invalidNumberMessage?super.getInvalidNumberMessage(e):invalidNumberMessage.apply(e);
}
};
}
/**
* @param toType
* @param inRange
* @param result
* @param outOfRangeMessage
* @param invalidNumberMessage
* @return
* @see #create(Class, Function, Consumer, Supplier, Function)
*/
public static StringToNumberValidator create(Class<? extends Number> toType, Function<Number, Boolean> inRange,
Consumer<Boolean> result, String outOfRangeMessage,String invalidNumberMessage) {
return create(toType,
inRange,
result,
null==outOfRangeMessage?null:()->outOfRangeMessage,
null==invalidNumberMessage?null:(e)->invalidNumberMessage);
}
/**
* @param toType
* @param inRange
* @return
* @see #create(Class, Function, Consumer, Supplier, Function)
*/
public static StringToNumberValidator create(Class<? extends Number> toType, Function<Number, Boolean> inRange) {
return create(toType,
inRange,
null,
(Supplier<String>)null,
(Function<Exception, String>)null);
}
}


用法示例(以Float为例):

updateStrategyToModel.setAfterGetValidator(new StringToNumberValidator(Float.class){
// 重写isInRange方法实现自定义数值范围验证
@Override
protected boolean isInRange(Number number) {
// 输入必须小于100
return number.floatValue()<100;
}
// 重写getOutOfRangeMessage方法,返回数据范围要求
@Override
protected String getOutOfRangeMessage() {
return "输入必须<100";
}});
// 重写result方法实现其他控制
@Override
protected void result(boolean ok) {
// 数据验证无效时 disable OK按钮
getButton(IDialogConstants.OK_ID).setEnabled(ok);
}});


上面的代码同样可以使用create静态方法创建StringToNumberValidator对象,Lambda表达式实现的代码更简洁。

updateStrategy.setAfterGetValidator(StringToNumberValidator.create(Float.class,
(number)->number.floatValue()<100,
(ok)->{getButton(IDialogConstants.OK_ID).setEnabled(ok);},
"输入必须<100",null));


如下图,当输入为空字符串时,提示错误信息



如下图,当输入数值超过允许范围时,提示错误信息

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息