正如問題所暗示的,我如何使用 archUnit 檢查某些匯入。
因此,當測驗類本身匯入 lombok.experimental.* 時,我希望測驗失敗。
我了解如何檢查包裹和類似的東西,但這種方法似乎不適用于進口。有什么建議?
我的代碼:
package com.nikita.Nikitos;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
public class AppTest
{
@Test
public void keineKlassenAusLombokExperimental() {
JavaClasses classes = new ClassFileImporter()
.importPackages("com.nikita..");
noClasses().should().dependOnClassesThat()
.resideInAPackage("lombok.experimental..").check(classes);
}
}
我要測驗的課程:
package com.nikita.Nikitos;
import lombok.experimental.UtilityClass;
@UtilityClass
public class App
{
static int hd;
}
uj5u.com熱心網友回復:
Lombok充當修改您的類的注釋處理器。
在這種情況下@lombok.experimental.UtilityClass(可能還有其他 lombok 注釋),最終的位元組碼實際上不再包含注釋:
@lombok.experimental.UtilityClass
public class App {
static int hd;
}
被編譯(轉換)為
public final class App
flags: (0x0031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER
this_class: #5 // App
super_class: #6 // java/lang/Object
interfaces: 0, fields: 1, methods: 1, attributes: 1
Constant pool:
#1 = Methodref #6.#15 // java/lang/Object."<init>":()V
#2 = Class #16 // java/lang/UnsupportedOperationException
#3 = String #17 // This is a utility class and cannot be instantiated
#4 = Methodref #2.#18 // java/lang/UnsupportedOperationException."<init>":(Ljava/lang/String;)V
#5 = Class #19 // App
#6 = Class #20 // java/lang/Object
#7 = Utf8 hd
#8 = Utf8 I
#9 = Utf8 <init>
#10 = Utf8 ()V
#11 = Utf8 Code
#12 = Utf8 LineNumberTable
#13 = Utf8 SourceFile
#14 = Utf8 App.java
#15 = NameAndType #9:#10 // "<init>":()V
#16 = Utf8 java/lang/UnsupportedOperationException
#17 = Utf8 This is a utility class and cannot be instantiated
#18 = NameAndType #9:#21 // "<init>":(Ljava/lang/String;)V
#19 = Utf8 App
#20 = Utf8 java/lang/Object
#21 = Utf8 (Ljava/lang/String;)V
{
static int hd;
descriptor: I
flags: (0x0008) ACC_STATIC
private App();
descriptor: ()V
flags: (0x0002) ACC_PRIVATE
Code:
stack=3, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: new #2 // class java/lang/UnsupportedOperationException
7: dup
8: ldc #3 // String This is a utility class and cannot be instantiated
10: invokespecial #4 // Method java/lang/UnsupportedOperationException."<init>":(Ljava/lang/String;)V
13: athrow
LineNumberTable:
line 4: 0
}
也可以從這個純 Java 代碼生成:
public final class App {
static int hd;
private App() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}
如果您想使用 ArchUnit 檢測位元組碼中的這種模式,您可能必須對 Lombok 所做的進行逆向工程,例如在呼叫UnsupportedOperationException(String)建構式的最終類中搜索私有建構式:
ArchRule no_UtilityClass = noConstructors()
.should().bePrivate()
.andShould().beDeclaredInClassesThat().haveModifier(JavaModifier.FINAL)
.andShould(new ArchCondition<JavaCodeUnit>("call new UnsupportedOperationException(String)") {
@Override
public void check(JavaCodeUnit codeUnit, ConditionEvents events) {
boolean satisfied = codeUnit.getCallsFromSelf().stream().anyMatch(call ->
call.getTargetOwner().isEquivalentTo(UnsupportedOperationException.class)
&& call.getName().equals(JavaConstructor.CONSTRUCTOR_NAME)
&& call.getTarget().getRawParameterTypes().size() == 1
&& call.getTarget().getRawParameterTypes().get(0).isEquivalentTo(String.class)
);
String message = String.format("%s %s `new UnsupportedOperationException(String)` in %s",
codeUnit.getDescription(), satisfied ? "calls" : "does not call", codeUnit.getSourceCodeLocation()
);
events.add(new SimpleConditionEvent(codeUnit, satisfied, message));
}
});
如果您想禁止lombok.experimental.*在源代碼中使用,很遺憾您需要另一個工具;ArchUnit(目前)只分析bytecode。
uj5u.com熱心網友回復:
匯入不會在位元組碼中生成任何簽名,因此 ArchUnit 無法直接檢測到它。
檢查您的代碼是否不依賴于該軟體包還不夠嗎?
ArchRule lombok_experimental_is_not_used = noClasses()
.should().dependOnClassesThat().resideInAPackage("lombok.experimental..");
如果您只想檢測星號匯入,那么很遺憾您需要使用其他工具。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/419464.html
標籤:
