我想测试所有Hibernate关联注释(@ManyToOne、@OneToMany、@OneToOne、@ManyToMany)是否都在使用fetch = FetchType.LAZY。这就是工作原理:
private static final Set<Class<? extends Annotation>> associations =
Set.of(ManyToOne.class, OneToMany.class, OneToOne.class, ManyToMany.class);
@ArchTest
public static final ArchRule allEntityRelationsShouldBeLazy = fields().that()
.areDeclaredInClassesThat().areAnnotatedWith(Entity.class)
.and()
.areAnnotatedWith(ManyToOne.class)
.or().areAnnotatedWith(OneToMany.class)
.or().areAnnotatedWith(OneToOne.class)
.or().areAnnotatedWith(ManyToMany.class)
// what I'd like: .areAnnotatedWith(Any.of(associations))
.should()
.notBeAnnotatedWith(new DescribedPredicate<>("FetchType.EAGER or undefined FetchType") {
@Override
public boolean apply(JavaAnnotation<?> input) {
JavaClass rawType = input.getRawType();
if (!rawType.isEquivalentTo(OneToOne.class)
// what I'd like: if (!Any.of(associations).apply(input)) {
&& !rawType.isEquivalentTo(OneToMany.class)
&& !rawType.isEquivalentTo(ManyToOne.class)
&& !rawType.isEquivalentTo(ManyToMany.class)) {
// Filter again, because a field can contain multiple annotations.
return false;
}
return input.get("fetch")
.transform(JavaEnumConstant.class::cast)
.transform(fetchType -> !FetchType.LAZY.name().equals(fetchType.name()))
.or(true);
}
});我必须过滤两次,因为一个字段可以有几个注释,如下所示:
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "otherEntity", referencedColumnName = "id")
private OtherEntity otherEntity;我不喜欢的是我必须编写注释(ManyToOne…)两次。为什么ArchUnit中没有"anyOf"-Predicate?或者,有没有其他方法可以避免重复它们?
发布于 2021-06-15 04:33:56
使用实体字段的自定义条件,您可以直接操作associations的相关注释,而不必重复它们:
@ArchTest
ArchRule allEntityRelationsShouldBeLazy = fields()
.that().areDeclaredInClassesThat().areAnnotatedWith(Entity.class)
.should(new ArchCondition<JavaField>("be annotated with FetchType.LAZY if an association") {
@Override
public void check(JavaField field, ConditionEvents events) {
field.getAnnotations().stream()
.filter(annotation -> associations.stream().anyMatch(annotation.getRawType()::isEquivalentTo))
.forEach(association -> {
JavaEnumConstant fetchType = (JavaEnumConstant) association.get("fetch").get();
if (!FetchType.LAZY.name().equals(fetchType.name())) {
String message = field.getDescription() + " is not LAZY in " + field.getSourceCodeLocation();
events.add(SimpleConditionEvent.violated(field, message));
}
});
}
});发布于 2021-06-15 04:00:22
可以使用Java流操作构建您想要的内容:
import static com.tngtech.archunit.base.DescribedPredicate.describe;
import static com.tngtech.archunit.lang.conditions.ArchPredicates.are;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.fields;
private static final DescribedPredicate<CanBeAnnotated> ALWAYS_FALSE = new DescribedPredicate<CanBeAnnotated>("always false", new Object[0]) {
@Override
public boolean apply(CanBeAnnotated input) {
return false;
}
};@ArchTest
ArchRule allEntityRelationsShouldBeLazy = fields().that()
.areDeclaredInClassesThat().areAnnotatedWith(Entity.class)
.and(are(annotatedWithAnyOf(associations)))
.should().notBeAnnotatedWith(describe("FetchType.EAGER or undefined FetchType",
input -> associations.stream().anyMatch(input.getRawType()::isEquivalentTo)
&& input.get("fetch")
.transform(JavaEnumConstant.class::cast)
.transform(enumConst -> !FetchType.LAZY.name().equals(enumConst.name()))
.get() // associations have a default fetch type
));
DescribedPredicate<CanBeAnnotated> annotatedWithAnyOf(Collection<Class<? extends Annotation>> annotations) {
return annotations.stream()
.map(CanBeAnnotated.Predicates::annotatedWith)
.reduce(DescribedPredicate::or)
.orElse(ALWAYS_FALSE); // annotations must not be empty
}https://stackoverflow.com/questions/67898442
复制相似问题