0

ArchUnit 0.14.1 没有检测到用作通用字段参数的类型的循环依赖关系。这是 ArchUnit 的限制还是我做错了什么?,例如:

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
    }

}
4

2 回答 2

0

ArchUnit 通过分析给定的Java 字节码来完成它的工作。

泛型是类型擦除的主题,因此在检查的字节码中不会有类型信息,您的字段将被解释为Optional<Object> a因此没有检测到循环。

于 2020-12-15T12:33:28.713 回答
0

不幸的是,ArchUnit 目前(从0.16.0开始)还没有完全支持泛型,但这正在处理中。(例如,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;>;

  // ...
于 2021-02-13T14:15:52.140 回答