ArchUnit:未检测到泛型的循环依赖
ArchUnit: cyclic dependency for generics not detected
ArchUnit 0.14.1 没有检测用作通用字段参数的类型的循环依赖性。这是 ArchUnit 的限制还是我做错了什么? ,即。 g.:
package com.test.a;
import com.test.b.B;
public class A {
protected B b;
}
package com.test.b;
import java.util.Optional;
import com.test.a.A;
public class B {
protected Optional<A> a; // not detected by archunit
// protected A a2; // detected by archunit
}
@AnalyzeClasses(packages = "com.test")
public class ArchitecturalChecks {
@ArchTest
public void testNoCycles(JavaClasses importedClasses) {
SlicesRuleDefinition.slices().matching("com.test.(*)..").should().beFreeOfCycles().check(importedClasses);
}
@ArchTest
public void testPackageStructure(JavaClasses importedClasses) {
// @formatter:off
Architectures.layeredArchitecture()
.layer("A").definedBy("com.test.a..")
.layer("B").definedBy("com.test.b..")
.whereLayer("A").mayNotBeAccessedByAnyLayer()
.whereLayer("B").mayOnlyBeAccessedByLayers("A")
.check(importedClasses);
// @formatter:on
}
}
ArchUnit 正在通过分析给定的 Java bytecode.
来完成它的工作
泛型是 type erasure 的主题,因此在检查的字节码中不会有类型信息,您的字段将被解释为 Optional<Object> a
因此没有检测到循环。
ArchUnit 目前(从 version 0.16.0) unfortunately not fully support generics 开始,但正在处理中。
(例如,ArchUnit 0.16.0 与以前的版本不同,它已经检测到 class B extends ArrayList<A>
的依赖关系。)
我相信 ArchUnit 的某些未来版本将通过字段的通用类型参数检测依赖关系,因为信息是实际存在于字节码中,请参阅javap -v B.class
:
public class com.test.b.B
minor version: 0
major version: 55
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #2 // com/test/b/B
super_class: #3 // java/lang/Object
interfaces: 0, fields: 1, methods: 1, attributes: 1
Constant pool:
#1 = Methodref #3.#14 // java/lang/Object."<init>":()V
#2 = Class #15 // com/test/b/B
#3 = Class #16 // java/lang/Object
#4 = Utf8 a
#5 = Utf8 Ljava/util/Optional; // <- erased type of a
#6 = Utf8 Signature
#7 = Utf8 Ljava/util/Optional<Lcom/test/a/A;>; // <- generic type of a
#8 = Utf8 <init>
#9 = Utf8 ()V
#10 = Utf8 Code
#11 = Utf8 LineNumberTable
#12 = Utf8 SourceFile
#13 = Utf8 B.java
#14 = NameAndType #8:#9 // "<init>":()V
#15 = Utf8 com/test/b/B
#16 = Utf8 java/lang/Object
{
protected java.util.Optional<com.test.a.A> a;
descriptor: Ljava/util/Optional;
flags: (0x0004) ACC_PROTECTED
Signature: #7 // Ljava/util/Optional<Lcom/test/a/A;>;
// ...
ArchUnit 0.14.1 没有检测用作通用字段参数的类型的循环依赖性。这是 ArchUnit 的限制还是我做错了什么? ,即。 g.:
package com.test.a;
import com.test.b.B;
public class A {
protected B b;
}
package com.test.b;
import java.util.Optional;
import com.test.a.A;
public class B {
protected Optional<A> a; // not detected by archunit
// protected A a2; // detected by archunit
}
@AnalyzeClasses(packages = "com.test")
public class ArchitecturalChecks {
@ArchTest
public void testNoCycles(JavaClasses importedClasses) {
SlicesRuleDefinition.slices().matching("com.test.(*)..").should().beFreeOfCycles().check(importedClasses);
}
@ArchTest
public void testPackageStructure(JavaClasses importedClasses) {
// @formatter:off
Architectures.layeredArchitecture()
.layer("A").definedBy("com.test.a..")
.layer("B").definedBy("com.test.b..")
.whereLayer("A").mayNotBeAccessedByAnyLayer()
.whereLayer("B").mayOnlyBeAccessedByLayers("A")
.check(importedClasses);
// @formatter:on
}
}
ArchUnit 正在通过分析给定的 Java bytecode.
来完成它的工作泛型是 type erasure 的主题,因此在检查的字节码中不会有类型信息,您的字段将被解释为 Optional<Object> a
因此没有检测到循环。
ArchUnit 目前(从 version 0.16.0) unfortunately not fully support generics 开始,但正在处理中。
(例如,ArchUnit 0.16.0 与以前的版本不同,它已经检测到 class B extends ArrayList<A>
的依赖关系。)
我相信 ArchUnit 的某些未来版本将通过字段的通用类型参数检测依赖关系,因为信息是实际存在于字节码中,请参阅javap -v B.class
:
public class com.test.b.B
minor version: 0
major version: 55
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #2 // com/test/b/B
super_class: #3 // java/lang/Object
interfaces: 0, fields: 1, methods: 1, attributes: 1
Constant pool:
#1 = Methodref #3.#14 // java/lang/Object."<init>":()V
#2 = Class #15 // com/test/b/B
#3 = Class #16 // java/lang/Object
#4 = Utf8 a
#5 = Utf8 Ljava/util/Optional; // <- erased type of a
#6 = Utf8 Signature
#7 = Utf8 Ljava/util/Optional<Lcom/test/a/A;>; // <- generic type of a
#8 = Utf8 <init>
#9 = Utf8 ()V
#10 = Utf8 Code
#11 = Utf8 LineNumberTable
#12 = Utf8 SourceFile
#13 = Utf8 B.java
#14 = NameAndType #8:#9 // "<init>":()V
#15 = Utf8 com/test/b/B
#16 = Utf8 java/lang/Object
{
protected java.util.Optional<com.test.a.A> a;
descriptor: Ljava/util/Optional;
flags: (0x0004) ACC_PROTECTED
Signature: #7 // Ljava/util/Optional<Lcom/test/a/A;>;
// ...