【问题标题】:How to assert HashMap keys to be Comparable with ArchUnit?如何断言 HashMap 键与 ArchUnit 可比?
【发布时间】:2021-12-28 13:19:20
【问题描述】:

背景:https://dev.to/carey/java-map-keys-should-always-be-comparable-2c1b

我想要达到的目标:

  1. 查找使用 HashMap 的代码。
  2. 找出 HashMaps 键的类型。
  3. 检查键类型是否实现了 Comparable 接口。
  4. (可选)检查该类型是否存在于某个包中。

我卡在第 2 步

noClasses().that()
        .containAnyFieldsThat(have(rawType(HashMap.class)))
        .should()...

任何想法如何获得泛型类的类型?感谢支持。

【问题讨论】:

    标签: java archunit


    【解决方案1】:

    你的ArchRule的关键部分(可以直接基于fields()codeUnits())可以用自定义ArchConditions来表达:

    @ArchTest
    static final ArchRule fields_of_type_HashMap_should_have_Comparable_key = fields()
        .that().haveRawType(HashMap.class)
        .should(haveComparableFirstTypeParameter());
    
    @ArchTest
    static final ArchRule code_units_should_have_parameters_of_type_HashMap_with_Comparable_key = codeUnits()
        .should(new ArchCondition<JavaCodeUnit>("have parameters of type HashMap with Comparable key") {
            @Override
            public void check(JavaCodeUnit javaCodeUnit, ConditionEvents events) {
                javaCodeUnit.getParameters().forEach(parameter -> {
                    if (parameter.getRawType().isEquivalentTo(HashMap.class)) {
                        haveComparableFirstTypeParameter().check(parameter, events);
                    }
                });
            }
        });
    
    @ArchTest
    static final ArchRule methods_with_return_type_HashMap_should_have_return_types_with_Comparable_key = methods()
        .that().haveRawReturnType(HashMap.class)
        .should(new ArchCondition<JavaMethod>("have return type with Comparable key") {
            @Override
            public void check(JavaMethod method, ConditionEvents events) {
                class ReturnType implements HasType, HasDescription {
                    @Override
                    public JavaType getType() { return method.getReturnType(); }
                    @Override
                    public JavaClass getRawType() { return method.getRawReturnType(); }
                    @Override
                    public String getDescription() { return "Return type <" + getType().getName() + "> of " + method.getDescription(); }
                }
                haveComparableFirstTypeParameter().check(new ReturnType(), events);
            }
        });
    
    private static <T extends HasType & HasDescription> ArchCondition<T> haveComparableFirstTypeParameter() {
        return new ArchCondition<T>("have Comparable first type parameter") {
            @Override
            public void check(T typed, ConditionEvents events) {
                JavaType fieldType = typed.getType();
                if (fieldType instanceof JavaParameterizedType) {
                    JavaType keyType = ((JavaParameterizedType) fieldType).getActualTypeArguments().get(0);
                    boolean satisfied = keyType.toErasure().getAllRawInterfaces().stream()
                            .anyMatch(rawInterface -> rawInterface.isEquivalentTo(Comparable.class));
                    String message = String.format("%s has a first type parameter %s that %s Comparable",
                            typed.getDescription(), keyType.getName(), satisfied ? "is" : "is not");
                    events.add(new SimpleConditionEvent(typed, satisfied, message));
                } else {
                    events.add(SimpleConditionEvent.violated(typed, typed.getDescription() + " is not parameterized"));
                }
            }
        };
    }
    

    【讨论】:

    • 太棒了,非常感谢!但是,这仅涵盖类的字段,因此例如方法中的局部变量会丢失。我试过codeUnits() 但这也找不到它们。是否有用于任意变量声明的ArchRuleDefinition
    • codeUnits() 仅限 comprise methods()constructors() 和静态初始化器; ArchUnit 目前不分析局部变量。但是,建议的规则可以推广到方法/构造函数参数和方法返回类型;我会相应地编辑我的答案。
    • 谢谢!我会在haveComparableFirstTypeParameter() 中添加一个检查来处理像public &lt;K, V&gt; Map&lt;K, V&gt; createHashMap() 这样的通用返回类型:``` JavaClass erasedType = keyType.toErasure(); List classHierarchy = erasedType.getClassHierarchy(); boolean isGenericType = classHierarchy.size() == 1; boolean isRelevant = isGenericType ||使满意; ```
    • 我提出了一个稍微改变的(检查 keyType instanceof JavaTypeVariable)版本,以包含在默认的 ArchUnit 规则github.com/TNG/ArchUnit/issues/769
    猜你喜欢
    • 2021-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-26
    • 1970-01-01
    相关资源
    最近更新 更多