You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Stab at JSpecify nullness annotation option
* Make the nullable checks a bit more robust
* Use JLS correct fully qualified nullables
and add tests to cover that strangeness. Not all compilers seem to care,
but it's the most technically correct generation.
* Prep for release
Copy file name to clipboardExpand all lines: CHANGELOG.md
+7Lines changed: 7 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,3 +1,10 @@
1
+
## 0.4.2
2
+
3
+
- Added `nullness_annotations` config option to emit JSpecify `@NullMarked` and
4
+
`@Nullable` annotations in generated code. When enabled, Rust `Option<T>` maps to
5
+
`@Nullable T` and all other types are non-null by default. Requires
6
+
`org.jspecify:jspecify` on the compile classpath.
7
+
1
8
## 0.4.1
2
9
3
10
- fix resolving callback trait implementations declared in submodules of the current crate. Previously, traits like `my_crate::metrics::MetricsRecorder` failed with "no interface with module_path" during code generation.
Copy file name to clipboardExpand all lines: README.md
+58Lines changed: 58 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -133,6 +133,7 @@ The generated Java can be configured using a `uniffi.toml` configuration file.
133
133
|`custom_types`|| A map which controls how custom types are exposed to Java. See the [custom types section of the UniFFI manual](https://mozilla.github.io/uniffi-rs/latest/udl/custom_types.html#custom-types-in-the-bindings-code)|
134
134
|`external_packages`|| A map of packages to be used for the specified external crates. The key is the Rust crate name, the value is the Java package which will be used referring to types in that crate. See the [external types section of the manual](https://mozilla.github.io/uniffi-rs/latest/udl/ext_types_external.html#kotlin)|
135
135
|`rename`|| A map to rename types, functions, methods, and their members in the generated Java bindings. See the [renaming section](https://mozilla.github.io/uniffi-rs/latest/renaming.html). |
136
+
|`nullness_annotations`|`false`| Generate [JSpecify](https://jspecify.dev/) nullness annotations. Rust `Option<T>` maps to `@Nullable T`; all other types are non-null by default via `@NullMarked`. Requires `org.jspecify:jspecify` on the compile classpath. See [Nullness Annotations](#nullness-annotations). |
136
137
|`android`|`false`| Generate [PanamaPort](https://github.com/vova7878/PanamaPort)-compatible code for Android. Replaces `java.lang.foreign.*` with `com.v7878.foreign.*` and `java.lang.invoke.VarHandle` with `com.v7878.invoke.VarHandle`. Requires PanamaPort `io.github.vova7878.panama:Core` as a runtime dependency and Android API 26+. |
137
138
|`omit_checksums`|`false`| Whether to omit checking the library checksums as the library is initialized. Changing this will shoot yourself in the foot if you mixup your build pipeline in any way, but might speed up initialization. |
138
139
@@ -174,6 +175,63 @@ Where `<namespace>` is the UniFFI namespace of your component (e.g., `arithmetic
174
175
175
176
You can also pass a plain library name as the override, in which case it behaves like `System.loadLibrary()` and still requires the library to be on `java.library.path`.
176
177
178
+
## Nullness Annotations
179
+
180
+
Generated bindings can include [JSpecify](https://jspecify.dev/) nullness annotations so that
181
+
Kotlin consumers get proper nullable/non-null types and Java consumers get IDE and static
182
+
analysis support.
183
+
184
+
Enable in `uniffi.toml`:
185
+
186
+
```toml
187
+
[bindings.java]
188
+
nullness_annotations = true
189
+
```
190
+
191
+
When enabled:
192
+
- A `package-info.java` is generated with `@NullMarked`, making all types non-null by default
193
+
- Rust `Option<T>` types are annotated with `@Nullable`, including inside generic type
194
+
arguments (e.g., `Map<String, @Nullable Integer>` for `HashMap<String, Option<i32>>`)
195
+
- All non-optional types (primitives, strings, records, objects, enums) are non-null
196
+
197
+
### Build Setup
198
+
199
+
JSpecify must be on the compile classpath when compiling the generated Java source.
200
+
201
+
**Gradle:**
202
+
```kotlin
203
+
// Use `api` if publishing a library so Kotlin/Java consumers benefit automatically.
204
+
// Use `compileOnly` if the bindings are only used within this project.
205
+
dependencies {
206
+
api("org.jspecify:jspecify:1.0.0")
207
+
}
208
+
```
209
+
210
+
**Maven:**
211
+
```xml
212
+
<!-- Use default scope if publishing a library. Use <scope>provided</scope> for internal use. -->
213
+
<dependency>
214
+
<groupId>org.jspecify</groupId>
215
+
<artifactId>jspecify</artifactId>
216
+
<version>1.0.0</version>
217
+
</dependency>
218
+
```
219
+
220
+
There is no runtime dependency — the JVM ignores annotation classes that are not present at
221
+
runtime.
222
+
223
+
### Kotlin Interop
224
+
225
+
Without nullness annotations, Kotlin sees all Java types from the generated bindings as
226
+
**platform types** (`String!`), which bypass null-safety checks. With annotations enabled,
This requires JSpecify to be on Kotlin's compile classpath (automatic if declared with `api`
233
+
scope).
234
+
177
235
## Notes
178
236
179
237
- failures in CompletableFutures will cause them to `completeExceptionally`. The error that caused the failure can be checked with `e.getCause()`. When implementing an async Rust trait in Java, you'll need to `completeExceptionally` instead of throwing. See `TestFixtureFutures.java` for an example trait implementation with errors.
0 commit comments