NullAway é uma ferramenta para ajudar a eliminar NullPointerException
s (NPEs) em seu código Java. Para usar NullAway, primeiro adicione anotações @Nullable
em seu código sempre que um campo, parâmetro de método ou valor de retorno puder ser null
. Dadas essas anotações, o NullAway executa uma série de verificações locais baseadas em tipo para garantir que qualquer ponteiro que seja desreferenciado em seu código não possa ser null
. NullAway é semelhante à verificação de nulidade baseada em tipo nas linguagens Kotlin e Swift, e aos verificadores de nulos Checker Framework e Eradicate para Java.
NullAway é rápido . Ele é construído como um plugin para Error Prone e pode ser executado em cada compilação do seu código. Em nossas medições, a sobrecarga no tempo de construção da execução do NullAway é geralmente inferior a 10%. NullAway também é prático : ele não evita todos os NPEs possíveis em seu código, mas captura a maioria dos NPEs que observamos na produção, ao mesmo tempo que impõe uma carga de anotação razoável, proporcionando um ótimo retorno para seu investimento.
NullAway requer que você construa seu código com Error Prone, versão 2.14.0 ou superior. Consulte a documentação do Error Prone para obter instruções sobre como começar a usar o Error Prone e integração com seu sistema de compilação. As instruções abaixo pressupõem que você esteja usando o Gradle; consulte a documentação para discussão sobre outros sistemas de construção.
Para integrar o NullAway ao seu projeto Java não Android, adicione o seguinte ao seu arquivo 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 " )
}
}
}
Vamos percorrer esse script passo a passo. A seção plugins
extrai o plug-in Gradle Error Prone para integração com Error Prone.
Em dependencies
, a primeira linha errorprone
carrega NullAway e a linha api
carrega a biblioteca JSpecify que fornece anotações de nulidade adequadas, por exemplo, org.jspecify.annotations.Nullable
. NullAway permite que qualquer anotação @Nullable
seja usada, portanto, por exemplo, @Nullable
da biblioteca de anotações AndroidX ou anotações JetBrains também é adequado. A segunda linha errorprone
define a versão do Error Prone usada.
Por fim, na seção tasks.withType(JavaCompile)
, passamos algumas opções de configuração para NullAway. Primeiro check("NullAway", CheckSeverity.ERROR)
define os problemas de NullAway para o nível de erro (é equivalente ao argumento padrão Error Prone -Xep:NullAway:ERROR
); por padrão, o NullAway emite avisos. Então, option("NullAway:AnnotatedPackages", "com.uber")
(equivalente ao argumento padrão Error Prone -XepOpt:NullAway:AnnotatedPackages=com.uber
) informa ao NullAway que o código-fonte em pacotes no namespace com.uber
deve ser verificado quanto a desreferências nulas e uso adequado de anotações @Nullable
, e que os arquivos de classe nesses pacotes devem ser considerados como tendo uso correto de @Nullable
(veja a documentação para mais detalhes). NullAway requer pelo menos o argumento de configuração AnnotatedPackages
para ser executado, a fim de distinguir entre código anotado e não anotado. Consulte a documentação de configuração para outras opções de configuração úteis. Para uma configuração ainda mais simples das opções do NullAway, use o plugin Gradle NullAway. Por fim, mostramos como desabilitar o NullAway no código de teste, se desejar.
Recomendamos abordar todos os problemas relatados pelo Error Prone, especialmente aqueles relatados como erros (em vez de avisos). Mas, se quiser experimentar o NullAway sem executar outras verificações propensas a erros, você pode usar options.errorprone.disableAllChecks
(equivalente a passar "-XepDisableAllChecks"
para o compilador, antes dos argumentos específicos do NullAway).
As versões 3.0.0 e posteriores do plug-in Gradle Error Prone não oferecem mais suporte ao Android. Portanto, se estiver usando uma versão recente deste plugin, você precisará adicionar algumas configurações adicionais para executar o Error Prone e o NullAway. Nosso arquivo build.gradle
de aplicativo de amostra mostra uma maneira de fazer isso, mas seu projeto Android pode exigir ajustes. Como alternativa, as versões 2.x do plug-in Gradle Error Prone ainda suportam Android e ainda podem funcionar com seu projeto.
Além disso, em comparação com a configuração Java, a dependência JSpecify pode ser removida; você pode usar a anotação androidx.annotation.Nullable
da biblioteca de anotações AndroidX.
Alguns processadores de anotação, como Dagger e AutoValue, geram código no mesmo namespace de pacote que seu próprio código. Isso pode causar problemas ao definir NullAway para o nível ERROR
conforme sugerido acima, pois erros neste código gerado bloquearão a construção. Atualmente, a melhor solução para esse problema é desabilitar completamente o Error Prone no código gerado, usando a opção -XepExcludedPaths
adicionada no Error Prone 2.1.3 (documentado aqui, use options.errorprone.excludedPaths=
no Gradle). Para usar, descubra qual diretório contém o código gerado e adicione esse diretório ao regex do caminho excluído.
Nota para usuários do Dagger : Versões do Dagger anteriores a 2.12 podem ter interações ruins com o NullAway; veja aqui. Atualize para o Dagger 2.12 para corrigir o problema.
Ao contrário de outros processadores de anotação acima, o Lombok modifica o AST na memória do código que processa, o que é a fonte de inúmeras incompatibilidades com o Error Prone e, consequentemente, o NullAway.
Não recomendamos particularmente o uso do NullAway com Lombok. No entanto, NullAway codifica algum conhecimento de anotações comuns do Lombok e tentamos a compatibilidade do melhor esforço. Em particular, usos comuns como classes @lombok.Builder
e @Data
devem ser suportados.
Para que o NullAway detecte com êxito o código gerado pelo Lombok no Java AST na memória, a seguinte opção de configuração deve ser passada ao Lombok como parte de um arquivo lombok.config
aplicável:
lombok.addLombokGeneratedAnnotation = true
Isso faz com que o Lombok adicione @lombok.Generated
aos métodos/classes que ele gera. NullAway irá ignorar (ou seja, não verificar) a implementação deste código gerado, tratando-o como não anotado.
Vamos ver como o NullAway funciona em um exemplo de código simples:
static void log ( Object x ) {
System . out . println ( x . toString ());
}
static void foo () {
log ( null );
}
Este código apresenta erros: quando foo()
é chamado, a chamada subsequente para log()
falhará com um NPE. Você pode ver esse erro no aplicativo de exemplo NullAway executando:
cp sample/src/main/java/com/uber/mylib/MyClass.java.buggy sample/src/main/java/com/uber/mylib/MyClass.java
./gradlew build
Por padrão, NullAway assume que cada parâmetro do método, valor de retorno e campo é não-nulo , ou seja, nunca pode ser atribuído um valor null
. No código acima, o parâmetro x
de log()
é considerado não nulo. Portanto, NullAway relata o seguinte erro:
warning: [NullAway] passing @Nullable parameter 'null' where @NonNull is required
log(null);
^
Podemos corrigir esse erro permitindo que null
seja passado para log()
, com uma anotação @Nullable
:
static void log ( @ Nullable Object x ) {
System . out . println ( x . toString ());
}
Com esta anotação, NullAway aponta a possível desreferência nula:
warning: [NullAway] dereferenced expression x is @Nullable
System.out.println(x.toString());
^
Podemos corrigir esse aviso adicionando uma verificação nula:
static void log ( @ Nullable Object x ) {
if ( x != null ) {
System . out . println ( x . toString ());
}
}
Com esta alteração, todos os avisos NullAway são corrigidos.
Para obter mais detalhes sobre as verificações, mensagens de erro e limitações do NullAway, consulte nosso guia detalhado.
Sinta-se à vontade para abrir um problema no GitHub se tiver alguma dúvida sobre como usar o NullAway. Ou você pode entrar no servidor NullAway Discord e nos fazer uma pergunta lá.
Adoraríamos que você contribuísse para o NullAway! Observe que, depois de criar uma solicitação pull, você será solicitado a assinar nosso Contrato de Licença de Colaborador Uber.
NullAway é licenciado sob a licença MIT. Consulte o arquivo LICENSE.txt para obter mais informações.