growthbook / growthbook-sdk-java

The Java SDK for GrowthBook (JVM, Android)
https://docs.growthbook.io/lib/java
MIT License
7 stars 10 forks source link

Add static analysis to help with null safety #21

Closed tinahollygb closed 1 month ago

tinahollygb commented 1 year ago

NullAway

The nullaway tool from Uber has a dependency on errorprone.

See more info about that below.

errorprone

Errorprone configuration has begun and it works for some things so far, e.g. MissingSummary, which I've disabled, and looking for fallthroughs in switch statements, but it throws an exception during the process. It appears to be a bug in the library since the stack trace wants it reported.

Exception from running gradlew check with errorprone enabled ``` growthbook-sdk-java/lib/src/main/java/growthbook/sdk/java/Experiment.java:1: error: An unhandled exception was thrown by the Error Prone static analysis plugin. package growthbook.sdk.java; ^ Please report this at https://github.com/google/error-prone/issues/new and include the following: error-prone version: 2.16 BugPattern: UnusedTypeParameter Stack Trace: java.util.NoSuchElementException: No value present at java.base/java.util.Optional.get(Optional.java:143) at com.google.errorprone.bugpatterns.UnusedTypeParameter.removeTypeParameter(UnusedTypeParameter.java:119) at com.google.errorprone.bugpatterns.UnusedTypeParameter$1.handle(UnusedTypeParameter.java:79) at com.google.errorprone.bugpatterns.UnusedTypeParameter$1.visitMethod(UnusedTypeParameter.java:69) at com.google.errorprone.bugpatterns.UnusedTypeParameter$1.visitMethod(UnusedTypeParameter.java:53) at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:953) at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:86) at com.google.errorprone.bugpatterns.BugChecker$SuppressibleTreePathScanner.scan(BugChecker.java:572) at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:96) at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:111) at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:119) at jdk.compiler/com.sun.source.util.TreeScanner.visitClass(TreeScanner.java:203) at com.google.errorprone.bugpatterns.UnusedTypeParameter$1.visitClass(UnusedTypeParameter.java:59) at com.google.errorprone.bugpatterns.UnusedTypeParameter$1.visitClass(UnusedTypeParameter.java:53) at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:860) at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:86) at com.google.errorprone.bugpatterns.BugChecker$SuppressibleTreePathScanner.scan(BugChecker.java:572) at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:111) at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:119) at jdk.compiler/com.sun.source.util.TreeScanner.visitCompilationUnit(TreeScanner.java:152) at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:614) at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:60) at com.google.errorprone.bugpatterns.UnusedTypeParameter.matchCompilationUnit(UnusedTypeParameter.java:83) at com.google.errorprone.scanner.ErrorProneScanner.processMatchers(ErrorProneScanner.java:449) at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:555) at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:150) at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:614) at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:60) at com.google.errorprone.scanner.Scanner.scan(Scanner.java:58) at com.google.errorprone.scanner.ErrorProneScannerTransformer.apply(ErrorProneScannerTransformer.java:43) at com.google.errorprone.ErrorProneAnalyzer.finished(ErrorProneAnalyzer.java:152) at jdk.compiler/com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:132) at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1394) at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1341) at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:933) at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:104) at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.invocationHelper(JavacTaskImpl.java:152) at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:100) at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:94) at org.gradle.internal.compiler.java.IncrementalCompileTask.call(IncrementalCompileTask.java:89) at org.gradle.api.internal.tasks.compile.AnnotationProcessingCompileTask.call(AnnotationProcessingCompileTask.java:94) at org.gradle.api.internal.tasks.compile.ResourceCleaningCompilationTask.call(ResourceCleaningCompilationTask.java:57) at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:54) at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:39) at org.gradle.api.internal.tasks.compile.daemon.AbstractDaemonCompiler$CompilerWorkAction.execute(AbstractDaemonCompiler.java:135) at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63) at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:49) at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:43) at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100) at org.gradle.workers.internal.AbstractClassLoaderWorker.executeInClassLoader(AbstractClassLoaderWorker.java:43) at org.gradle.workers.internal.FlatClassLoaderWorker.run(FlatClassLoaderWorker.java:32) at org.gradle.workers.internal.FlatClassLoaderWorker.run(FlatClassLoaderWorker.java:22) at org.gradle.workers.internal.WorkerDaemonServer.run(WorkerDaemonServer.java:87) at org.gradle.workers.internal.WorkerDaemonServer.run(WorkerDaemonServer.java:56) at org.gradle.process.internal.worker.request.WorkerAction$1.call(WorkerAction.java:138) at org.gradle.process.internal.worker.child.WorkerLogEventListener.withWorkerLoggingProtocol(WorkerLogEventListener.java:41) at org.gradle.process.internal.worker.request.WorkerAction.run(WorkerAction.java:135) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164) at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833) Note: Some input files use or override a deprecated API. Note: Recompile with -Xlint:deprecation for details. Note: /Users/tina/Documents/code/growthbook/growthbook-sdk-java/lib/src/main/java/growthbook/sdk/java/FeatureEvaluator.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. 1 error ```

Some examples include errorprone, which was initially started:

plugin {
    id('net.ltgt.errorprone') version '3.0.1'
}

dependencies {
    // Tooling
    errorprone("com.google.errorprone:error_prone_core:2.16")
}

tasks.withType(JavaCompile).configureEach {
    options.errorprone.disableWarningsInGeneratedCode = true
    options.errorprone.allErrorsAsWarnings = true
    options.errorprone.disable("MissingSummary")
}

The above configuration, however, throws an error

Bohdan-Kim commented 1 month ago

So, error-prone version 2.16 throws exception when running gradlew check. We created pull request with 3.1.0 version. v3.1.0 doesn't support Java 8. Seems like older versions of the plugin support Java 8, but older versions requires older dependencies. So, there wasn't found the way to add plugin not losing anything.