NullAway는 Java 코드에서 NPE( NullPointerException
)를 제거하는 데 도움이 되는 도구입니다. NullAway를 사용하려면 먼저 필드, 메소드 매개변수 또는 반환 값이 null
일 수 있는 코드에 @Nullable
주석을 추가하세요. 이러한 주석이 제공되면 NullAway는 일련의 유형 기반 로컬 검사를 수행하여 코드에서 역참조되는 포인터가 null
이 될 수 없도록 합니다. NullAway는 Kotlin 및 Swift 언어의 유형 기반 null 허용 여부 검사와 Java용 Checker Framework 및 Eradicate null 검사기와 유사합니다.
NullAway는 빠릅니다 . 이는 Error Prone의 플러그인으로 구축되었으며 코드의 모든 단일 빌드에서 실행될 수 있습니다. 측정 결과, NullAway 실행의 빌드 시간 오버헤드는 일반적으로 10% 미만입니다. NullAway는 실용적 이기도 합니다. 코드에서 가능한 모든 NPE를 방지하지는 않지만 합리적인 주석 부담을 부과하면서 프로덕션에서 관찰한 대부분의 NPE를 포착하여 "비용 대비 큰 이익"을 제공합니다.
NullAway를 사용하려면 Error Prone 버전 2.14.0 이상으로 코드를 빌드해야 합니다. Error Prone을 시작하고 빌드 시스템과 통합하는 방법에 대한 지침은 Error Prone 설명서를 참조하세요. 아래 지침에서는 Gradle을 사용한다고 가정합니다. 다른 빌드 시스템에 대한 논의는 문서를 참조하세요.
NullAway를 Android가 아닌 Java 프로젝트에 통합하려면 build.gradle
파일에 다음을 추가하세요.
plugins {
// we assume you are already using the Java plugin
id " net.ltgt.errorprone " version " <plugin version> "
}
dependencies {
errorprone " com.uber.nullaway:nullaway:<NullAway version> "
// Some source of nullability annotations; JSpecify recommended,
// but others supported as well.
api " org.jspecify:jspecify:1.0.0 "
errorprone " com.google.errorprone:error_prone_core:<Error Prone version> "
}
import net.ltgt.gradle.errorprone.CheckSeverity
tasks . withType( JavaCompile ) {
options . errorprone {
check( " NullAway " , CheckSeverity . ERROR )
option( " NullAway:AnnotatedPackages " , " com.uber " )
}
// Include to disable NullAway on test code
if (name . toLowerCase() . contains( " test " )) {
options . errorprone {
disable( " NullAway " )
}
}
}
이 스크립트를 단계별로 살펴보겠습니다. plugins
섹션은 Error Prone 통합을 위해 Gradle Error Prone 플러그인을 가져옵니다.
dependencies
에서 errorprone
첫 번째 줄은 NullAway를 로드하고 api
줄은 적절한 null 허용 여부 주석을 제공하는 JSpecify 라이브러리(예: org.jspecify.annotations.Nullable
를 로드합니다. NullAway를 사용하면 모든 @Nullable
주석을 사용할 수 있으므로 AndroidX 주석 라이브러리 또는 JetBrains 주석의 @Nullable
도 괜찮습니다. 두 번째 errorprone
줄은 사용되는 Error Prone 버전을 설정합니다.
마지막으로 tasks.withType(JavaCompile)
섹션에서는 일부 구성 옵션을 NullAway에 전달합니다. 첫 번째 check("NullAway", CheckSeverity.ERROR)
NullAway 문제를 오류 수준으로 설정합니다( -Xep:NullAway:ERROR
표준 Error Prone 인수와 동일). 기본적으로 NullAway는 경고를 내보냅니다. 그런 다음 option("NullAway:AnnotatedPackages", "com.uber")
( -XepOpt:NullAway:AnnotatedPackages=com.uber
표준 Error Prone 인수와 동일)은 NullAway에게 com.uber
네임스페이스 아래 패키지의 소스 코드가 다음과 같아야 함을 알려줍니다. null 역참조 및 @Nullable
주석의 적절한 사용을 확인하고 이러한 패키지의 클래스 파일에 @Nullable
의 올바른 사용이 있다고 가정해야 합니다(참조: 자세한 내용은 문서를 참조하세요). NullAway는 주석이 달린 코드와 주석이 없는 코드를 구별하기 위해 최소한 AnnotatedPackages
구성 인수를 실행해야 합니다. 다른 유용한 구성 옵션은 구성 문서를 참조하세요. NullAway 옵션을 더욱 간단하게 구성하려면 Gradle NullAway 플러그인을 사용하세요. 마지막으로 원하는 경우 테스트 코드에서 NullAway를 비활성화하는 방법을 보여줍니다.
Error Prone이 보고하는 모든 문제, 특히 (경고가 아닌) 오류로 보고된 문제를 해결하는 것이 좋습니다. 그러나 다른 Error Prone 검사를 실행하지 않고 NullAway를 시험해 보려면 options.errorprone.disableAllChecks
사용할 수 있습니다(NullAway 관련 인수 앞에 "-XepDisableAllChecks"
컴파일러에 전달하는 것과 동일).
Gradle Error Prone 플러그인 버전 3.0.0 이상에서는 더 이상 Android를 지원하지 않습니다. 따라서 이 플러그인의 최신 버전을 사용하는 경우 Error Prone 및 NullAway를 실행하려면 몇 가지 추가 구성을 추가해야 합니다. 샘플 앱 build.gradle
파일은 이를 수행하는 한 가지 방법을 보여 주지만 Android 프로젝트에는 조정이 필요할 수 있습니다. 또는 Gradle Error Prone 플러그인의 2.x 버전은 여전히 Android를 지원하며 프로젝트에서 계속 작동할 수 있습니다.
그 외에도 Java 구성과 비교하여 JSpecify 종속성을 제거할 수 있습니다. 대신 AndroidX 주석 라이브러리의 androidx.annotation.Nullable
주석을 사용할 수 있습니다.
Dagger 및 AutoValue와 같은 일부 주석 프로세서는 자신의 코드와 동일한 패키지 네임스페이스에 코드를 생성합니다. 위에서 제안한 대로 NullAway를 ERROR
수준으로 설정할 때 문제가 발생할 수 있습니다. 생성된 코드의 오류로 인해 빌드가 차단되기 때문입니다. 현재 이 문제에 대한 가장 좋은 해결책은 Error Prone 2.1.3에 추가된 -XepExcludedPaths
옵션을 사용하여 생성된 코드에서 Error Prone을 완전히 비활성화하는 것입니다(여기에 설명되어 있으며 Gradle에서 options.errorprone.excludedPaths=
사용). 사용하려면 생성된 코드가 포함된 디렉터리를 파악하고 해당 디렉터리를 제외된 경로 정규식에 추가하세요.
Dagger 사용자를 위한 참고 사항 : 2.12 이전 Dagger 버전은 NullAway와 상호 작용이 좋지 않을 수 있습니다. 여기를 참조하세요. 문제를 해결하려면 Dagger 2.12로 업데이트하세요.
위의 다른 주석 프로세서와 달리 Lombok은 처리하는 코드의 메모리 내 AST를 수정합니다. 이는 Error Prone 및 결과적으로 NullAway와의 수많은 비호환성의 원인입니다.
Lombok에서는 NullAway를 사용하는 것을 특별히 권장하지 않습니다. 그러나 NullAway는 일반적인 Lombok 주석에 대한 일부 지식을 인코딩하며 최선의 호환성을 위해 노력합니다. 특히 @lombok.Builder
및 @Data
클래스와 같은 일반적인 사용법이 지원되어야 합니다.
NullAway가 메모리 내 Java AST 내에서 Lombok 생성 코드를 성공적으로 감지하려면 다음 구성 옵션을 적용 가능한 lombok.config
파일의 일부로 Lombok에 전달해야 합니다.
lombok.addLombokGeneratedAnnotation = true
이로 인해 Lombok은 생성하는 메서드/클래스에 @lombok.Generated
를 추가합니다. NullAway는 생성된 코드의 구현을 무시(즉 확인하지 않음)하고 주석이 없는 것으로 처리합니다.
간단한 코드 예제에서 NullAway가 어떻게 작동하는지 살펴보겠습니다.
static void log ( Object x ) {
System . out . println ( x . toString ());
}
static void foo () {
log ( null );
}
이 코드는 버그가 있습니다. foo()
호출되면 log()
에 대한 후속 호출이 NPE로 인해 실패합니다. 다음을 실행하여 NullAway 샘플 앱에서 이 오류를 볼 수 있습니다.
cp sample/src/main/java/com/uber/mylib/MyClass.java.buggy sample/src/main/java/com/uber/mylib/MyClass.java
./gradlew build
기본적으로 NullAway는 모든 메소드 매개변수, 반환 값 및 필드가 null이 아닌 것으로 가정합니다. 즉, null
값이 할당될 수 없습니다. 위 코드에서 log()
의 x
매개변수는 null이 아닌 것으로 가정됩니다. 따라서 NullAway는 다음 오류를 보고합니다.
warning: [NullAway] passing @Nullable parameter 'null' where @NonNull is required
log(null);
^
@Nullable
주석을 사용하여 null
log()
에 전달되도록 허용하여 이 오류를 수정할 수 있습니다.
static void log ( @ Nullable Object x ) {
System . out . println ( x . toString ());
}
이 주석을 통해 NullAway는 가능한 null 역참조를 지적합니다.
warning: [NullAway] dereferenced expression x is @Nullable
System.out.println(x.toString());
^
null 검사를 추가하여 이 경고를 수정할 수 있습니다.
static void log ( @ Nullable Object x ) {
if ( x != null ) {
System . out . println ( x . toString ());
}
}
이 변경으로 모든 NullAway 경고가 수정되었습니다.
NullAway의 검사, 오류 메시지 및 제한 사항에 대한 자세한 내용은 자세한 가이드를 참조하세요.
NullAway 사용 방법에 대해 궁금한 점이 있으면 언제든지 GitHub 문제를 열어주세요. 또는 NullAway Discord 서버에 가입하여 질문을 하실 수도 있습니다.
NullAway에 기여해 주시길 바랍니다! 끌어오기 요청을 생성하면 Uber 기여자 라이선스 계약에 서명하라는 메시지가 표시됩니다.
NullAway는 MIT 라이센스에 따라 라이센스가 부여됩니다. 자세한 내용은 LICENSE.txt 파일을 참조하십시오.