0

背景: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()...

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

4

1 回答 1

1

你的关键部分ArchRule(可以直接基于fields()or codeUnits())可以用 custom 表示ArchCondition

@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"));
            }
        }
    };
}
于 2021-12-28T15:29:03.020 回答