我在一个配置文件中定义了一个poperties列表,但是在继续进一步计算之前,我想检查这些属性是否具有一致的值。目前,我只是做通过ifs。
private static void checkprops (Properties properties) throws Throwable {
if (!properties.getProperty("number").equals("one")
&& !properties.getProperty("number").equals("two")) {
throw new Exception("ERROR");
}
if (!properties.getProperty("check").equals("false")
&& !properties.getProperty("check").equals("true")) {
throw new Exception("ERROR");
}
if (properties.getProperty("totalnum").equals("null")) {
throw new Exception("ERROR");
}
}有什么方法可以做到这一点,更短,更容易阅读,因为我有一些属性,将有5-6个不同的选择。
发布于 2017-06-17 18:48:43
首先,我要指出,您的代码有一个错误:
if (properties.getProperty("totalnum").equals("null")) { ... }如果未定义该属性,getProperty()将返回null,因此您的代码在尝试访问equals()时将引发NullPointerException。它不返回值为"null“的字符串。你的台词都是这样的。
我使用反射来处理这个问题,使用一个配置类来声明public字段,这些字段可能会使用值检查进行注释。然后,方法将在该config类的实例上设置值,从属性映射中读取。
进一步读:
它的优点是配置以直观的、可说的格式显示有效值。缺点是“解编组”代码有点复杂。尽管这种方法非常强大。
配置可能如下所示:
static class Config {
@RegExp("^(one|two)$")
public String number;
public Boolean check;
@Required @Range(min=1, max=6)
public Integer totalnum;
}如果某个字段缺少@Required注释,则缺失的属性不会导致异常,因此将使用Config的初始化值。
解编组使用以下方法完成:
Config config = new Config();
setProperties(properties, config);当值丢失时,setProperties()会抛出几个异常,但类型或值不对。异常可以被捕获和区分,以显示正确的错误消息。
在您的应用程序中,您可以像简单对象一样访问配置:
if (config.totalnum == 3) {
// do something when totalnum is 3
}这是解编组代码:
private void setProperties(Properties properties, Props props) throws SecurityException, IllegalArgumentException, IllegalAccessException {
Class<?> clazz = props.getClass();
for (Field field : clazz.getDeclaredFields()) {
if ((field.getModifiers() & Modifier.PUBLIC) == 0) {
// ignore non-public properties
continue;
}
// the type of the field
Class<?> fieldType = field.getType();
// the field name of the class
String fieldName = field.getName();
// the raw value loaded from the .properties file
String value = properties.getProperty(fieldName);
// fields may be annotated with @Required
boolean required = (field.getAnnotation(Required.class) != null);
if (required && value == null) {
// field required but not defined in the properties, fail
throw new IllegalArgumentException(
String.format(
"Field %s is required",
fieldName
)
);
} else if (value == null) {
// ignore undefined field, default to class initialized value
continue;
}
// checks per type follow ...
if (fieldType == String.class) {
// fields may be annotated with RegExp to specify a matcher
RegExp regExp = field.getAnnotation(RegExp.class);
if (regExp != null && !Pattern.matches(regExp.value(), value)) {
throw new IllegalArgumentException(
String.format(
"Value for field %s does not match %s: %s",
fieldName,
regExp.value(),
value
)
);
}
field.set(props, value);
} else if (fieldType == Integer.class) {
// may throw NumberFormatException if not a valid integer
Integer intValue = Integer.parseInt(value);
// fields may be annotated with Range to specify an integer range
Range range = field.getAnnotation(Range.class);
if (range != null && !(intValue >= range.min() && intValue <= range.max())) {
throw new IllegalArgumentException(
String.format(
"Value for field %s out of range (%d..%d): %d",
fieldName,
range.min(),
range.max(),
intValue
)
);
}
field.set(props, intValue);
} else if (fieldType == Boolean.class) {
// strictly check valid boolean values
if (!Pattern.matches("^(true|false)$", value)) {
throw new IllegalArgumentException(
String.format(
"Value for field %s is not a valid boolean (true|false): %s",
fieldName,
value
)
);
}
field.set(props, Boolean.parseBoolean(value));
}
}
}虽然已经相当复杂,但这段代码相当简单。它还没有处理其他数字类型(如Long )或基本类型(如int )。这些可以使用进一步的if分支来实现。
这些是注释(在单独的类中定义):
@Retention(RUNTIME)
@Target(FIELD)
public @interface Range {
public int min() default Integer.MIN_VALUE;
public int max() default Integer.MAX_VALUE;
}
@Retention(RUNTIME)
@Target(FIELD)
public @interface RegExp {
public String value() default "^.*$";
}
@Retention(RUNTIME)
@Target(FIELD)
public @interface Required {
}发布于 2017-06-17 17:30:07
您可以创建一个实用程序方法,该方法将接受配置文件中的值和预期值作为参数,并返回bool,例如:
public boolean validateProp(T propVal, T... expectedVals) {
for(T expectedVal : expectedVals) {
if(propVal == null) {
if(expectedVal == null) {
return true;
}
}
else if(propVal.equals(expectedVal)) {
return true;
}
}
return false;
}这种情况下的一个示例调用是:
if(!validateProp(properties.getProperty("number"), "one", "two") {
throw new Exception("ERROR");
}发布于 2017-06-18 09:42:08
避免直接验证Properties对象的一个选项是将其映射到POJO,然后在其上使用Bean验证。
Bean验证是一种标准的Java,用于指定验证约束和检查对象(甚至是方法参数)是否有效,这可以帮助您避免编写许多用于建模错误的代码。参考实现是Hibernate Validator,但不管名称如何,您都可以使用独立的,而无需使用所有Hibernate的。
举个例子(这可能需要一些额外的工作):
public class Config {
@Pattern("^(one|two)$")
private String number;
@NotNull
private Boolean check;
@NotNull
@Min(1)
@Max(6)
private Integer totalnum;
public static Config fromProperties(Properties ps) {
Config conf = new Config();
conf.number = ps.getProperty("number");
// fails right away if "check" is null
conf.check = Boolean.valueOf(ps.getProperty("check"));
// fails right away if "totalnum" is null
conf.totalnum = Integer.valueOf(ps.getProperty("totalnum"));
return conf;
}
}以及呼叫代码:
Validator validator = Validation.buildDefaultValidatorFactory()
.getValidator();
Config config = Config.fromProperties(properties);
Set<ConstraintViolation<Config>> violations = validator.validate(config);
if (violations.isEmpty()) {
// good to go
} else {
// some code to print the errors
}在本例中,我使用@Pattern约束来匹配使用regex,但是,由于您提到一些属性有5-6个可能的值,所以最好定义您自己的注释,如
@Values({"one", "two", "three", "four"})
private String number;https://stackoverflow.com/questions/44606976
复制相似问题