Skip to content

Java language bindings for payjoin-ffi #1860

Open

Description

@ram0verflow

Which crate is this feature request for?

payjoin-ffi

Please describe the feature you'd like to see added.

I'd like to add Java bindings for payjoin-ffi.

There is no JVM target today. I'd follow the C# layout (payjoin-ffi/java/), generate with uniffi-bindgen-java, and keep the generator in that directory rather than adding a cargo feature on payjoin-ffi.

First PR: generate, tests including v2, CI on linux/mac/windows. Not in that PR: Maven or a wallet.

Does that match what you'd want? I can open a draft after generate works locally.

Is your feature related to a problem, if so please describe it.

No response

Describe the solution you'd like

No response

Describe any alternatives you've considered

No response

Please leave any additional context

No response

Activity

  1. ram0verflow commented on Sep 6, 2026

    @ram0verflow
    ContributorAuthor

    Following up on this, I did some work and found a few things.

    uniffi-bindgen-java 0.5.0 requires uniffi 0.32. payjoin-ffi is on 0.31.2, and 0.5.0 rejects the metadata with Unexpected metadata type code: 116. The previous release, 0.4.2, reads 0.31 metadata but generates Java that does not compile for this crate.

    From there,

    I backported the 0.5.0 template fixes onto the 0.31 line. I opened IronCoreLabs/uniffi-bindgen-java#68 asking about a 0.4.3 and offered to do the work. Fixes are on a fork meanwhile and I generated bindings against that fork here

    A cleaner approach would be to move payjoin-ffi to uniffi 0.32, which 0.5.0 supports unmodified. That is not limited to payjoin-ffi. uniffi-bindgen-cs is pinned at v0.11.0+v0.31.0 and uniffi-dart at v0.2.1+v0.31.2, so both would need 0.32 tags first.

    A third option avoids the bindgen: a hand-written JVM layer over the official Kotlin bindings, CompletableFuture rather than coroutines. I did some work here. Works, but hand-maintained, and JNA rather than FFM.

    I can open a draft PR for whichever direction you prefer, or leave this if Java bindings are not wanted at present.

  2. chavic commented on Sep 6, 2026

    @chavic
    Collaborator

    @ram0verflow Thanks for taking this on. I see you added Kotlin and are wrapping it. I'd have the Kotlin in its own draft; it seems like that could ship faster...

    Also, do you have or know of a project demanding Java? I'd like to keep an eye on that

  3. ram0verflow commented on Sep 6, 2026

    @ram0verflow
    ContributorAuthor

    @chavic Thanks! I’ll separate the Kotlin work out and get a V2 integration test working first, then put up a draft PR.

    For Java, my original motivation was to experiment with integrating Payjoin V2 into Sparrow Wallet. I’m not working on Sparrow officially, It’s just a personal project/interest. I needed JVM/Java support for that, and the Kotlin work came out of exploring the cross-platform JVM side, rather than Kotlin being the original goal.

  4. ram0verflow commented on Sep 8, 2026

    @ram0verflow
    ContributorAuthor

    opened a pr #1869

  5. ram0verflow commented on Sep 13, 2026

    @ram0verflow
    ContributorAuthor

    For Java, the remaining blocker is "uniffi-bindgen-java": 0.5.x expects UniFFI 0.32, while "payjoin-ffi" is still on 0.31.x. The 0.4.x line can read the metadata but generates invalid Java for this crate without the template fixes I backported.

    Before I continue, which direction would you prefer?

    • generated Java bindings, using a patched/pinned 0.4.x generator for now;
    • wait until the UniFFI 0.32 ecosystem upgrade and use upstream "uniffi-bindgen-java";
    • a thin Java-facing layer over the merged Kotlin/JVM bindings.

    I’m happy to open the next PR once the preferred direction is clear.

  6. chavic commented on Sep 14, 2026

    @chavic
    Collaborator

    @ram0verflow I would patch now then upgraded later...

    Now that kotlin is merged, package incoming, do you have enough for your experimental integration? I saw you already tried the layer approach 🤔

  7. ram0verflow commented on Sep 14, 2026

    @ram0verflow
    ContributorAuthor

    Yeah, I think the merged Kotlin/JVM package should be enough to start the Sparrow experiment.

    I’ll try the integration against that first. If the Java interop turns out to be awkward or the API would benefit from first-class Java bindings, I can then open the generated-Java PR using the patched 0.4.x generator and upgrade it later with UniFFI 0.32.

  8. ram0verflow commented on Sep 14, 2026

    @ram0verflow
    ContributorAuthor

    I tested the merged Kotlin/JVM bindings in the Sparrow experiment and got a full BIP77 sender round trip working.

    It turns out full generated Java bindings aren't necessary for this path. Almost the entire sender API is directly callable from Java, including the synchronous persistence/state-machine APIs.

    The one issue I hit is the three SenderBuilder build methods: their u64/u8 parameters become Kotlin ULong/UByte, so the JVM method names are mangled and can't be called normally from Java. I initially used reflection to prove the integration, then tested a small hand-written Kotlin shim exposing Long/Int? wrappers. With that in place, the Sparrow round trip works without reflection, and the existing Kotlin integration suite still passes.

    Would you prefer a small PR adding that Java-interop shim to the Kotlin/JVM bindings, or would you still rather I proceed with the patched uniffi-bindgen-java 0.4.x route?

  9. chavic commented on Sep 14, 2026

    @chavic
    Collaborator

    The paths depend on whether you're blocked on the Sparrow experiment and how much work it is to rewrite if you eventually stumble on something.

    I lean towards patching the Java bindings generator, even though you have something working; that would make your implementation more durable in the long run.

    One thing: if it's going to take too long to fix the Java generator, and given we're more excited to see something working in Sparrow, don't treat the Java generator as a blocker to that work...

  10. ram0verflow commented on Sep 14, 2026

    @ram0verflow
    ContributorAuthor

    Makes sense. I'll keep the Sparrow experiment moving with the Kotlin/JVM bindings for now so the Java generator doesn't block it.

    In parallel I'll continue with the patched uniffi-bindgen-java 0.4.x route for the durable Java bindings, and if that lands cleanly I can switch the Sparrow integration over later.

  11. DanGould commented on Sep 15, 2026

    @DanGould
    Member

    @ram0verflow how much has been communicated of these plans to @craigraw? My understanding of that project is that they won't take on any new libraries, and this would be a major new library. Even large contributions from outsiders are usually rewritten by Craig from what I've seen. I think the best place for these bindings would be to demonstrate end to end experience demo of async page join as a sort of scaffold that would be replaced piece by piece in native Java. I for that reason I wouldn't want to introduce a bindings library in Rust Payjoin that we will maintain immediately, at least not until it was clear that there is demand for such a library.

    The most interesting thing about this approach to me is that it's not unique. I think this would be the same type of thing that Bitcoin Core would want if it were integrated, for example: Step one is make the demo using the Payjoin dev kit, and then step two is replace each function there with native code.

  12. ram0verflow commented on Sep 15, 2026

    @ram0verflow
    ContributorAuthor

    Not much yet. I haven't discussed the implementation approach with Craig directly, and I'm not working on Sparrow officially this started as a personal integration experiment.

    The useful result so far is that I have a real BIP77 sender round trip working through Sparrow's existing networking and signing path, so the bindings have been valuable as a scaffold for proving the flow.

    It makes sense not to take on a new external bindings dependency without clear downstream demand. I can treat the Java bindings work as experimental for now and take the working Sparrow PoC to Craig/#1980 first, rather than assuming Sparrow would adopt the library as a dependency.

    If the preferred Sparrow direction is native Java, the PDK-backed implementation can still serve as a reference/scaffold and be replaced piece by piece.

  13. ram0verflow commented on Sep 15, 2026

    @ram0verflow
    ContributorAuthor

    @DanGould I’ve taken the working sender PoC to Craig/Sparrow on #1980 and asked specifically about the dependency/native-Java direction. I’ll let that discussion determine whether the Java bindings work should go any further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions