Repository navigation
jextract: Foundation values as standard Java types - #952
Open
piercifani wants to merge 2 commits into
Open
piercifani wants to merge 2 commits into
piercifani wants to merge 2 commits into
Conversation
The `Data`, `Date` and `URL` wrapper classes are generated into the Java package of every module that uses them, so a `URL` returned by one module's API is a different Java type from the `URL` another module's API accepts. With `"foundationTypesAsJavaTypes": true` (JNI mode), Foundation values cross as standard Java types and no wrapper classes are generated: `URL` as `java.net.URI`, `Date` as `java.util.Date`, `Data` as `byte[]`, `Locale` as `java.util.Locale` and `TimeZone` as `java.util.TimeZone`. They conform to `JavaValue` in SwiftJavaRuntimeSupport, so they work wherever a `String` does: parameters, results, optionals, arrays and closure parameters. `Locale`, `TimeZone` and `CGFloat` become known types. `CGFloat` is a Java `double`, with or without the option. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
In JNI mode,
Data,DateandURLreach Java as Swift-backed wrapper classes. jextract generates those classes into the Java package of every module that uses them, so a codebase with several Swift modules ends up with severalURLclasses:com.example.models.URL,com.example.features.URLand so on. AURLreturned by one module's API is a different Java type from theURLanother module's API accepts, so the value can't be passed along. Running jextract over a production codebase with 9 modules generated aURLclass in 7 of them.The wrappers have other costs too:
URL?parameters aren't supported.java.net.URI,java.util.Dateandbyte[]anyway.UUIDalready avoids all of this: it crosses asjava.util.UUID.Changes
"foundationTypesAsJavaTypes": trueinswift-java.config(JNI mode) makes these Foundation values cross as standard Java types, and stops generating the wrapper classes:URLjava.net.URIDatejava.util.DateDatabyte[]Localejava.util.LocaleTimeZonejava.util.TimeZoneJavaValueinSwiftJavaRuntimeSupport, which the generated thunks already import, so they work wherever aStringdoes: parameters, results, optionals, arrays and closure parameters. Values are copied: aDatekeeps millisecond precision, and aLocalecrosses as its language tag (pt_BRin Swift ispt-BRin Java).JNIJavaTypeTranslatormaps the kinds to the Java types when the option is on, and the places that special-case the wrapper classes defer to it then.ExtractDecider.shouldExtractFoundationType(_:), defaulting totrue, lets the Java decider skip the wrapper types.Locale,TimeZoneandCGFloatbecome known types inSwiftExtract.CGFloatis a Javadouble, with or without the option: it was unsupported before.The option is off by default, so existing generated APIs don't change. Not covered yet: Java-implemented protocols (
enableJavaCallbacks) with these types. They go through wrap-java's own type mapping, so jextract skips such a protocol with a warning, as it does for other unsupported types.Testing
JNIFoundationJavaTypesTests, with Java signatures and Swift thunks for every type in each position, andCGFloatwithout the option.FoundationJavaValueTestsinSwiftJavaTests(5 tests on a real JVM). They round-trip each type through JNI and check the Java side: ajava.net.URIwith its percent-encoding intact, and abyte[]of the right length.JExtractSwiftPluginand this option, called from Java. 21 checks passed, covering every type as a parameter, result,Optional(parameter and result), array and closure argument, including unsigned bytes inDataand a custom JavaTimeZoneID.URL,DateandDataparameters, among others). The Java still compiles with the same number of javac errors: 2 go away (wrapper names that collided with the codebase's own types), and 1 is a separate existing bug that now becomes reachable. An enum case with a closure payload references a functional interface that isn't generated, with or without this option:case custom((String) -> Bool)fails the same way onmain.swift testpasses; config docs regenerated, andFeaturesJextract.mdgains a "Foundation values as Java types" section.🤖 Generated with Claude Code