Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jquery/84.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 枚举参数的编译时验证_Java_Validation_Enums_Compile Time - Fatal编程技术网

Java 枚举参数的编译时验证

Java 枚举参数的编译时验证,java,validation,enums,compile-time,Java,Validation,Enums,Compile Time,有一个构造函数有三个enum类型的参数: public SomeClass(EnumType1 enum1,EnumType2 enum2, EnumType3 enum3) {...} enum类型的三个参数不允许与所有可能的值组合: 例如: EnumType1.VALUE_-ONE、EnumType2.VALUE_-SIX、EnumType3.VALUE_-Twent是有效的组合 但以下组合无效: EnumType1.VALUE_2,EnumType2.VALUE_6,EnumType3.

有一个构造函数有三个enum类型的参数:

public SomeClass(EnumType1 enum1,EnumType2 enum2, EnumType3 enum3)
{...}
enum类型的三个参数不允许与所有可能的值组合:

例如:

EnumType1.VALUE_-ONE、EnumType2.VALUE_-SIX、EnumType3.VALUE_-Twent是有效的组合

但以下组合无效:

EnumType1.VALUE_2,EnumType2.VALUE_6,EnumType3.VALUE_15

每个枚举类型都知道允许与哪些值组合:

EnumType1和其他两个实现isAllowedWith()方法,以检查是否存在以下情况:

public enum EnumType1 {

VALUE_ONE,VALUE_TWO,...;

    public boolean isAllowedWith(final EnumType2 type) {
    switch (this) {
        case VALUE_ONE:
            return type.equals(Type.VALUE_THREE);
        case VALUE_TWO:
            return true;
        case VALUE_THREE:
            return type.equals(Type.VALUE_EIGHT);
        ...
    }
}
我需要在编译时运行该检查,因为在我的项目中,组合在运行时总是正确的这一点非常重要

我想知道是否有可能使用用户定义的注释运行该检查


每个想法都值得赞赏:)

因此最简单的方法是1)定义文档以解释有效的组合和
2) 在构造函数中添加检查

如果构造函数抛出异常,则调用程序负责。基本上你会这样做:

public MyClass(enum foo, enum bar, enum baz)  
{  
    if(!validateCombination(foo,bar,baz))
    {  
        throw new IllegalStateException("Contract violated");
    }  
} 


private boolean validateCombination(enum foo, enum bar, enum baz)  
{  
    //validation logic
} 

现在这一部分是绝对关键的。如果将类标记为final,则可能会恢复并滥用部分构造的对象来破坏应用程序。对于标记为final的类,恶意程序无法扩展部分构造的对象并造成严重破坏。

好吧,我不知道编译时检查,但我认为这是不可能的,因为编译器如何知道将传递给构造函数的值(在运行时计算枚举变量的值的情况下)(例如,通过If条款)? 这只能在运行时使用为枚举类型实现的验证器方法进行验证

例如:

如果在代码中有如下内容:

EnumType1 enumVal;

if (<some condition>) {
  enumVal = EnumType2.VALUE_SIX;
} else {
  enumVal = EnumType2.VALUE_ONE;
}
enumtype1enumval;
如果(){
enumVal=EnumType2.VALUE_六;
}否则{
enumVal=EnumType2.VALUE\u一;
}

编译器无法知道哪些值将被分配给enumVal,因此在计算if块(只能在运行时执行)之前无法验证传递给构造函数的内容

为什么不使用嵌套枚举的概念呢

您将拥有包含其自身值的
EnumType1
和嵌套的
EnumType2
,而这一个是嵌套的
EnumType3

你可以用你有用的组合来组织整体。 最终可能会得到3个类(EnumType1、2和3),每个相关值中的每一个都包含具有允许的关联值的其他值

您的调用看起来是这样的(假设您想要与
EnumType2.VALUE\u十五
关联的
EnumType1.VALUE\u一
):

因此,您还可以有:
EnumType3.VALUE\u SIX.VALUE\u ONE
(其中六个由type3知道,一个由type1知道)

您的呼叫将更改为以下内容:

public SomeClass(EnumType1 enumType)
=>示例:

SomeClass(EnumType1.VALUE_ONE.VALUE_SIX.VALUE_TWENTY) //being a valid combination as said

为了更好地阐明这一点,请查看以下帖子:

另一个想法是编写一些自动化测试来捕捉这一点,并在打包/部署应用程序之前将它们作为一个强制性步骤挂接到构建过程中

如果你想一想你在这里想要捕捉的是什么,这是合法但错误的代码。虽然你可以在编译阶段捕捉到这一点,但这正是测试的目的


这将符合您不能使用非法组合构建任何代码的要求,因为构建仍然会失败。而且可以说,对其他开发人员来说,这比编写自己的注释处理器更容易理解…

我知道的唯一方法是使用注释

这就是我的意思。 现在,构造函数接受3个参数:

publicsomeclass(enumtype1enum1、enumtype2enum2、enumtype3enum3){}

因此,您将其命名为:

SomeClass obj=新的SomeClass(EnumTupe1.VALUE1、EnumTupe2.VALUE2、EnumTupe1.VALUE3)

将构造函数更改为私有。创建公共构造函数,该构造函数接受任何类型的参数。它可能只是一个伪参数

publicsomeclass(占位符p)

现在,当每个参数都带有特殊注释时,您必须调用此构造函数。我们将其称为
TypeAnnotation

SomeClass obj = new SomeClass(TypeAnnotation(
    type1=EnumType1.VALUE1, 
    type2=EnumTupe2.VALUE2,
    type3=EnumTupe1.VALUE3)
    p3);
调用更加冗长,但这是我们为编译时验证所要付出的代价

现在,如何定义注释

@记录 @保留({RetentionPolicy.RUNTIME,RetentionPolicy.SOURCE}) @目标(参数) @接口类型注释{ 枚举类型1类型1(); 枚举类型2类型3(); 枚举类型3类型3(); }

请注意,目标是参数,保留值是运行时和源

运行时允许在运行时读取此注释,而源代码允许创建可在运行时验证参数的注释处理器

现在,公共构造函数将调用3参数私有构造函数:

公共类(占位符p){ 这(readAnnotation(EnumType1.class)、readAnnotation(EnumType2.class)、readAnnotation(EnumType3.class)、) }

这里我没有实现
readAnnotation()
:它应该是一个静态方法,它接受堆栈跟踪,返回3个元素(给公共构造函数的调用者)并解析注释
TypeAnnotation

现在是最有趣的部分。您必须实现注释处理器。 查看说明和注释处理器示例

您必须将此注释处理器的使用添加到生成脚本和(可选)IDE中。在这种情况下,当违反兼容性规则时,您将得到真正的编译错误

我认为,这一解决办法似乎是可行的
SomeClass obj = new SomeClass(TypeAnnotation(
    type1=EnumType1.VALUE1, 
    type2=EnumTupe2.VALUE2,
    type3=EnumTupe1.VALUE3)
    p3);