Skip to content

jextract/jni: Move enum case classes inside the Case interface#709

Merged
ktoso merged 2 commits intoswiftlang:mainfrom
sidepelican:move_java_case_class
Apr 17, 2026
Merged

jextract/jni: Move enum case classes inside the Case interface#709
ktoso merged 2 commits intoswiftlang:mainfrom
sidepelican:move_java_case_class

Conversation

@sidepelican
Copy link
Copy Markdown
Contributor

Currently, generating Java code for a Swift enum where a case name matches a nested type name (as shown below) results in a compilation error.

public enum MyResponse: Codable {
  case success(Success)
  public struct Success {
    public init(message: String) {
      self.message = message
    }
    public var message: String
  }
  case failure(String)
}

This happens because jextract generates two Java classes named Success at the same nesting level—one for the enum case and one for the Swift struct.

To avoid this, I have moved the generated case classes inside the interface Case.

Note

While a collision could still theoretically occur if the Swift enum defines its own struct Case, the probability of encountering such a conflict is significantly lower with this new structure.

@sidepelican sidepelican requested a review from ktoso as a code owner April 17, 2026 06:22
"""
public sealed interface Case {}
public sealed interface Case {
record First() implements Case {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: public is unnecessary within an interface.

try (var arena = SwiftArena.ofConfined()) {
Vehicle vehicle = Vehicle.transformer(Vehicle.bicycle(arena), Vehicle.car("BMW", Optional.empty(), arena), arena);
Vehicle.Transformer transformer = vehicle.getAsTransformer(arena).orElseThrow();
Vehicle.Case.Transformer transformer = vehicle.getAsTransformer(arena).orElseThrow();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alternative would be to Vehicle.TransformerCase or Vehicle.$Transformer hm... The $ in the name is not ideal perhaps, we usually tell folks that things with $ in the name are "not for them" but the Case sufficient could work without the additional nesting...

WDYT, any opinions @madsodgaard ?

/// The description of the type java.util.Optional.
static func optional(_ T: JavaType) -> JavaType {
.class(package: "java.util", name: "Optional", typeParameters: [T])
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

Copy link
Copy Markdown
Collaborator

@ktoso ktoso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't dislike this tbh... let's give @madsodgaard a chance to reply as well

@madsodgaard
Copy link
Copy Markdown
Contributor

Yeah, I've faced this as well. Moving it into Case seems fine, I don't see any issues with it.

@ktoso
Copy link
Copy Markdown
Collaborator

ktoso commented Apr 17, 2026

Okey, I'm happy with the .Case., it's fine tbh :) Thank you !

@ktoso ktoso merged commit 7a53fdb into swiftlang:main Apr 17, 2026
64 checks passed
@sidepelican sidepelican deleted the move_java_case_class branch April 17, 2026 11:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants