$npx -y skills add sivaprasadreddy/sivalabs-agent-skills --skill jspecifyUse this skill when asked to perform any of the following actions in a Java project: - To add jspecify support - To prevent NullPointerExceptions - To better handle Nullability This skill will add jspecify dependency, configure Maven or Gradle build to automatically use jspecify
| 1 | Jspecify provides a set of annotations to explicitly declare the nullness expectations of the Java code. |
| 2 | |
| 3 | ## Add jSpecify support in Maven projects |
| 4 | If you are using Maven, then add the jspecify dependency in `pom.xml`. |
| 5 | In `pom.xml`, update or add the `nullability-maven-plugin`, to include the following configuration. |
| 6 | |
| 7 | ```xml |
| 8 | <dependencies> |
| 9 | <dependency> |
| 10 | <groupId>org.jspecify</groupId> |
| 11 | <artifactId>jspecify</artifactId> |
| 12 | <version>1.0.0</version> |
| 13 | </dependency> |
| 14 | </dependencies> |
| 15 | |
| 16 | <build> |
| 17 | <plugins> |
| 18 | <plugin> |
| 19 | <groupId>am.ik.maven</groupId> |
| 20 | <artifactId>nullability-maven-plugin</artifactId> |
| 21 | <version>0.4.2</version> |
| 22 | <extensions>true</extensions> |
| 23 | <configuration> |
| 24 | <checking>tests</checking> |
| 25 | <outputDirectory>${project.basedir}/src/main/java</outputDirectory> |
| 26 | <testOutputDirectory>${project.basedir}/src/test/java</testOutputDirectory> |
| 27 | </configuration> |
| 28 | <executions> |
| 29 | <execution> |
| 30 | <goals> |
| 31 | <goal>configure</goal> |
| 32 | <goal>generate-package-info</goal> |
| 33 | </goals> |
| 34 | </execution> |
| 35 | </executions> |
| 36 | </plugin> |
| 37 | </plugins> |
| 38 | </build> |
| 39 | ``` |
| 40 | |
| 41 | ## Add jSpecify support in Gradle projects |
| 42 | If you are using Gradle, then add the jspecify dependency. |
| 43 | In `build.gradle` or `build.gradle.kts`, update or add the following jspecify configuration. |
| 44 | |
| 45 | ```groovy |
| 46 | plugins { |
| 47 | id("net.ltgt.errorprone") version "5.1.0" |
| 48 | id("net.ltgt.nullaway") version "3.1.0" |
| 49 | } |
| 50 | |
| 51 | tasks.withType(JavaCompile).configureEach { |
| 52 | options.errorprone { |
| 53 | disableAllChecks = true // Other error prone checks are disabled |
| 54 | error("RequireExplicitNullMarking") // Require @NullMarked or @NullUnmarked on everything |
| 55 | nullaway { |
| 56 | error() |
| 57 | } |
| 58 | } |
| 59 | // Keep a JDK 25 baseline |
| 60 | options.release = 25 |
| 61 | } |
| 62 | |
| 63 | nullaway { |
| 64 | onlyNullMarked = true |
| 65 | jspecifyMode = true |
| 66 | } |
| 67 | |
| 68 | dependencies { |
| 69 | implementation("org.jspecify:jspecify:1.0.0") |
| 70 | errorprone("com.google.errorprone:error_prone_core:2.50.0") |
| 71 | errorprone("com.uber.nullaway:nullaway:0.13.7") |
| 72 | } |
| 73 | ``` |
| 74 | |
| 75 | ## Add @NullMarked to package-info.java files |
| 76 | In every java package under the application main source code (`src/main/java`), |
| 77 | create `package-info.java` if not exists already, and add the `@NullMarked` annotation as follows: |
| 78 | |
| 79 | ```java |
| 80 | @org.jspecify.annotations.NullMarked |
| 81 | package com.mycompnay.myproject; |
| 82 | ``` |
| 83 | |
| 84 | If `package-info.java` file already exists, update the file to add `@org.jspecify.annotations.NullMarked` annotation. |
| 85 | DO NOT REMOVE ANY OTHER EXISTING CODE IN `package-info.java` FILE. |
| 86 | |
| 87 | ## Verify jSpecify support |
| 88 | If python is installed, after adding the jSpecify support, run `scripts/verify_nullmarked.py` |
| 89 | to check if all non-empty packages has `package-info.java` file or not. |
| 90 | |
| 91 | ## Migrating an existing codebase from other annotation libraries |
| 92 | |
| 93 | If the project already uses another nullability annotation library (JSR-305 / `javax`, Jakarta, |
| 94 | JetBrains, Spring, Android, FindBugs/SpotBugs, Checker Framework, or Eclipse JDT), migrate those |
| 95 | annotations to JSpecify **before** adding `@NullMarked`. The OpenRewrite `MigrateToJSpecify` recipe |
| 96 | automates the common cases (javax, Jakarta, JetBrains, Micrometer, Micronaut); the rest are a short |
| 97 | manual mapping. See [references/annotation-migration.md](references/annotation-migration.md). |
| 98 | |
| 99 | ## Incremental adoption for large codebases |
| 100 | |
| 101 | Flipping every package to `@NullMarked` at once is impractical on a large or legacy codebase. |
| 102 | `@NullUnmarked` lets you enforce NullAway on a growing perimeter while the rest stays untouched. |
| 103 | Because the build above enables `OnlyNullMarked` mode, packages without `@NullMarked` are simply |
| 104 | ignored — so adoption is driven purely by adding markers, one package at a time. Strategies, |
| 105 | progress tracking, common NullAway errors, and redundant null-guard removal are in |
| 106 | [references/incremental-adoption.md](references/incremental-adoption.md). |
| 107 | |
| 108 | ## Kotlin interop (optional) |
| 109 | |
| 110 | If the project also has Kotlin sources, the Kotlin compiler (K2) reads JSpecify annotations on Java |
| 111 | APIs and surfaces accurate nullability instead of platform types. See |
| 112 | [references/kotlin-interop.md](references/kotlin-interop.md). |