如何断言 HashMap 键与 ArchUnit 具有可比性?
How to assert HashMap keys to be Comparable with ArchUnit?
背景:https://dev.to/carey/java-map-keys-should-always-be-comparable-2c1b
我想达到的目标:
- 查找使用 HashMap 的代码。
- 找出 HashMaps 键的类型。
- 检查key类型是否实现了Comparable接口。
- (可选)检查该类型是否位于某个包中。
我卡在了第 2 步
noClasses().that()
.containAnyFieldsThat(have(rawType(HashMap.class)))
.should()...
关于如何获得通用类型的任何想法 class?感谢支持。
你的ArchRule
关键部分(可以直接根据fields()
or codeUnits()
) can be expressed with custom ArchCondition
s:
@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"));
}
}
};
}
背景:https://dev.to/carey/java-map-keys-should-always-be-comparable-2c1b
我想达到的目标:
- 查找使用 HashMap 的代码。
- 找出 HashMaps 键的类型。
- 检查key类型是否实现了Comparable接口。
- (可选)检查该类型是否位于某个包中。
我卡在了第 2 步
noClasses().that()
.containAnyFieldsThat(have(rawType(HashMap.class)))
.should()...
关于如何获得通用类型的任何想法 class?感谢支持。
你的ArchRule
关键部分(可以直接根据fields()
or codeUnits()
) can be expressed with custom ArchCondition
s:
@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"));
}
}
};
}