如何断言 HashMap 键与 ArchUnit 具有可比性?

How to assert HashMap keys to be Comparable with ArchUnit?

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

我想达到的目标:

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

我卡在了第 2 步

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

关于如何获得通用类型的任何想法 class?感谢支持。

你的ArchRule关键部分(可以直接根据fields() or codeUnits()) can be expressed with custom 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"));
            }
        }
    };
}