diff --git a/Sources/Java2SwiftLib/JavaTranslator.swift b/Sources/Java2SwiftLib/JavaTranslator.swift index 2b482b13..3b592715 100644 --- a/Sources/Java2SwiftLib/JavaTranslator.swift +++ b/Sources/Java2SwiftLib/JavaTranslator.swift @@ -234,11 +234,16 @@ extension JavaTranslator { // Fields var staticFields: [Field] = [] + var enumConstants: [Field] = [] members.append( contentsOf: javaClass.getFields().compactMap { $0.flatMap { field in if field.isStatic { staticFields.append(field) + + if field.isEnumConstant() { + enumConstants.append(field) + } return nil } @@ -252,6 +257,13 @@ extension JavaTranslator { } ) + if !enumConstants.isEmpty { + let enumName = "\(swiftTypeName)Cases" + members.append( + contentsOf: translateToEnumValue(name: enumName, enumFields: enumConstants) + ) + } + // Constructors members.append( contentsOf: javaClass.getConstructors().compactMap { @@ -447,6 +459,50 @@ extension JavaTranslator { """ } + package func translateToEnumValue(name: String, enumFields: [Field]) -> [DeclSyntax] { + let extensionSyntax: DeclSyntax = """ + public enum \(raw: name): Equatable { + \(raw: enumFields.map { "case \($0.getName())" }.joined(separator: "\n")) + } + """ + + let mappingSyntax: DeclSyntax = """ + public var enumValue: \(raw: name)? { + let classObj = self.javaClass + \(raw: enumFields.map { + // The equals method takes a java object, so we need to cast it here + """ + if self.equals(classObj.\($0.getName())?.as(JavaObject.self)) { + return \(name).\($0.getName()) + } + """ + }.joined(separator: " else ")) else { + return nil + } + } + """ + + let initSyntax: DeclSyntax = """ + public init(_ enumValue: \(raw: name), environment: JNIEnvironment) { + let classObj = try! JavaClass(in: environment) + switch enumValue { + \(raw: enumFields.map { + return """ + case .\($0.getName()): + if let \($0.getName()) = classObj.\($0.getName()) { + self = \($0.getName()) + } else { + fatalError("Enum value \($0.getName()) was unexpectedly nil, please re-run Java2Swift on the most updated Java class") + } + """ + }.joined(separator: "\n")) + } + } + """ + + return [extensionSyntax, mappingSyntax, initSyntax] + } + // Translate a Java parameter list into Swift parameters. private func translateParameters(_ parameters: [Parameter?]) throws -> [FunctionParameterSyntax] { return try parameters.compactMap { javaParameter in diff --git a/Tests/Java2SwiftTests/Java2SwiftTests.swift b/Tests/Java2SwiftTests/Java2SwiftTests.swift index b3418ff2..579c74a8 100644 --- a/Tests/Java2SwiftTests/Java2SwiftTests.swift +++ b/Tests/Java2SwiftTests/Java2SwiftTests.swift @@ -24,6 +24,11 @@ var jvm: JavaVirtualMachine { } } +@JavaClass("java.time.Month") +public struct JavaMonth { + +} + class Java2SwiftTests: XCTestCase { func testJavaLangObjectMapping() throws { try assertTranslatedClass( @@ -47,6 +52,36 @@ class Java2SwiftTests: XCTestCase { ) } + func testEnum() async throws { + try assertTranslatedClass( + JavaMonth.self, + swiftTypeName: "Month", + expectedChunks: [ + "import JavaKit", + "enum MonthCases: Equatable", + "case APRIL", + "public var enumValue: MonthCases?", + """ + } else if self.equals(classObj.APRIL?.as(JavaObject.self)) { + return MonthCases.APRIL + } + """, + "public init(_ enumValue: MonthCases, environment: JNIEnvironment) {", + """ + case .APRIL: + if let APRIL = classObj.APRIL { + self = APRIL + } else { + fatalError("Enum value APRIL was unexpectedly nil, please re-run Java2Swift on the most updated Java class") + } + """, + """ + @JavaStaticField + public var APRIL: Month? + """ + ]) + } + func testGenericCollections() throws { try assertTranslatedClass( MyArrayList.self,