首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >检查属性是否有正确的值

检查属性是否有正确的值
EN

Stack Overflow用户
提问于 2017-06-17 16:41:31
回答 3查看 402关注 0票数 0

我在一个配置文件中定义了一个poperties列表,但是在继续进一步计算之前,我想检查这些属性是否具有一致的值。目前,我只是做通过ifs。

代码语言:javascript
复制
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个不同的选择。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-06-17 18:48:43

首先,我要指出,您的代码有一个错误:

代码语言:javascript
复制
if (properties.getProperty("totalnum").equals("null")) { ... }

如果未定义该属性,getProperty()将返回null,因此您的代码在尝试访问equals()时将引发NullPointerException。它不返回值为"null“的字符串。你的台词都是这样的。

我使用反射来处理这个问题,使用一个配置类来声明public字段,这些字段可能会使用值检查进行注释。然后,方法将在该config类的实例上设置值,从属性映射中读取。

进一步读:

它的优点是配置以直观的、可说的格式显示有效值。缺点是“解编组”代码有点复杂。尽管这种方法非常强大。

配置可能如下所示:

代码语言:javascript
复制
static class Config {
    @RegExp("^(one|two)$")
    public String number;

    public Boolean check;

    @Required @Range(min=1, max=6)
    public Integer totalnum;
}

如果某个字段缺少@Required注释,则缺失的属性不会导致异常,因此将使用Config的初始化值。

解编组使用以下方法完成:

代码语言:javascript
复制
    Config config = new Config();
    setProperties(properties, config);

当值丢失时,setProperties()会抛出几个异常,但类型或值不对。异常可以被捕获和区分,以显示正确的错误消息。

在您的应用程序中,您可以像简单对象一样访问配置:

代码语言:javascript
复制
if (config.totalnum == 3) {
    // do something when totalnum is 3
}

这是解编组代码:

代码语言:javascript
复制
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分支来实现。

这些是注释(在单独的类中定义):

代码语言:javascript
复制
@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 {

}
票数 0
EN

Stack Overflow用户

发布于 2017-06-17 17:30:07

您可以创建一个实用程序方法,该方法将接受配置文件中的值和预期值作为参数,并返回bool,例如:

代码语言:javascript
复制
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;
}

这种情况下的一个示例调用是:

代码语言:javascript
复制
if(!validateProp(properties.getProperty("number"), "one", "two") {
    throw new Exception("ERROR");
}
票数 0
EN

Stack Overflow用户

发布于 2017-06-18 09:42:08

避免直接验证Properties对象的一个选项是将其映射到POJO,然后在其上使用Bean验证

Bean验证是一种标准的Java,用于指定验证约束和检查对象(甚至是方法参数)是否有效,这可以帮助您避免编写许多用于建模错误的代码。参考实现是Hibernate Validator,但不管名称如何,您都可以使用独立的,而无需使用所有Hibernate的

举个例子(这可能需要一些额外的工作):

代码语言:javascript
复制
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;
  }
}

以及呼叫代码:

代码语言:javascript
复制
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个可能的值,所以最好定义您自己的注释,如

代码语言:javascript
复制
  @Values({"one", "two", "three", "four"})
  private String number;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44606976

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档