diff --git a/Sources/JExtractSwiftLib/Convenience/String+Extensions.swift b/Sources/JExtractSwiftLib/Convenience/String+Extensions.swift index 1878ba2f..1851e154 100644 --- a/Sources/JExtractSwiftLib/Convenience/String+Extensions.swift +++ b/Sources/JExtractSwiftLib/Convenience/String+Extensions.swift @@ -14,8 +14,7 @@ extension String { - // TODO: naive implementation good enough for our simple case `methodMethodSomething` -> `MethodSomething` - var toCamelCase: String { + var firstCharacterUppercased: String { guard let f = first else { return self } diff --git a/Sources/JExtractSwiftLib/ImportedDecls.swift b/Sources/JExtractSwiftLib/ImportedDecls.swift index 4b8a478a..dd7e9c10 100644 --- a/Sources/JExtractSwiftLib/ImportedDecls.swift +++ b/Sources/JExtractSwiftLib/ImportedDecls.swift @@ -160,15 +160,25 @@ extension ImportedFunc { let returnsBoolean = self.functionSignature.result.type.asNominalTypeDeclaration?.knownTypeKind == .bool if !returnsBoolean { - return "get\(self.name.toCamelCase)" + return "get\(self.name.firstCharacterUppercased)" } else if !self.name.hasJavaBooleanNamingConvention { - return "is\(self.name.toCamelCase)" + return "is\(self.name.firstCharacterUppercased)" } else { - return self.name.toCamelCase + return self.name } } var javaSetterName: String { - "set\(self.name.toCamelCase)" + let isBooleanSetter = self.functionSignature.parameters.first?.type.asNominalTypeDeclaration?.knownTypeKind == .bool + + // If the variable is already named "isX", then we make + // the setter "setX" to match beans spec. + if isBooleanSetter && self.name.hasJavaBooleanNamingConvention { + // Safe to force unwrap due to `hasJavaBooleanNamingConvention` check. + let propertyName = self.name.split(separator: "is", maxSplits: 1).last! + return "set\(propertyName)" + } else { + return "set\(self.name.firstCharacterUppercased)" + } } } diff --git a/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift b/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift index 5b70f68a..47397c63 100644 --- a/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift +++ b/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift @@ -115,7 +115,6 @@ func assertOutput( print("==== ---------------------------------------------------------------") #expect(output.contains(expectedChunk), sourceLocation: sourceLocation) - fatalError("Failed: \(filePath):\(line)") continue } diff --git a/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift b/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift index 3f65bd97..272d27b5 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIVariablesTests.swift @@ -33,7 +33,7 @@ struct JNIVariablesTests { set { } } public var someBoolean: Bool - public let isBoolean: Bool + public var isBoolean: Bool } """ @@ -411,7 +411,7 @@ struct JNIVariablesTests { } @Test - func boolean_swiftThunks() throws { + func someBoolean_swiftThunks() throws { try assertOutput( input: membersSource, .jni, @@ -450,4 +450,87 @@ struct JNIVariablesTests { ] ) } + + @Test + func isBoolean_javaBindings() throws { + try assertOutput( + input: membersSource, + .jni, + .java, + detectChunkByInitialLines: 8, + expectedChunks: [ + """ + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public var isBoolean: Bool + * } + */ + public boolean isBoolean() { + long self$ = this.$memoryAddress(); + return MyClass.$isBoolean(self$); + } + """, + """ + /** + * Downcall to Swift: + * {@snippet lang=swift : + * public var isBoolean: Bool + * } + */ + public void setBoolean(boolean newValue) { + long self$ = this.$memoryAddress(); + MyClass.$setBoolean(newValue, self$); + } + """, + """ + private static native boolean $isBoolean(long selfPointer); + """, + """ + private static native void $setBoolean(boolean newValue, long selfPointer); + """ + ] + ) + } + + @Test + func isBoolean_swiftThunks() throws { + try assertOutput( + input: membersSource, + .jni, + .swift, + detectChunkByInitialLines: 1, + expectedChunks: [ + """ + @_cdecl("Java_com_example_swift_MyClass__00024isBoolean__J") + func Java_com_example_swift_MyClass__00024isBoolean__J(environment: UnsafeMutablePointer!, thisClass: jclass, selfPointer: jlong) -> jboolean { + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("self memory address was null in call to \\(#function)!") + } + let result = self$.pointee.isBoolean + return result.getJNIValue(in: environment) + } + """, + """ + @_cdecl("Java_com_example_swift_MyClass__00024setBoolean__ZJ") + func Java_com_example_swift_MyClass__00024setBoolean__ZJ(environment: UnsafeMutablePointer!, thisClass: jclass, newValue: jboolean, selfPointer: jlong) { + guard let env$ = environment else { + fatalError("Missing JNIEnv in downcall to \\(#function)") + } + assert(selfPointer != 0, "selfPointer memory address was null") + let selfBits$ = Int(Int64(fromJNI: selfPointer, in: env$)) + guard let self$ = UnsafeMutablePointer(bitPattern: selfBits$) else { + fatalError("self memory address was null in call to \\(#function)!") + } + self$.pointee.isBoolean = Bool(fromJNI: newValue, in: environment!) + } + """ + ] + ) + } }