Skip to content

Commit d28959a

Browse files
committed
import classes with static methods
1 parent 908bfec commit d28959a

File tree

6 files changed

+409
-213
lines changed

6 files changed

+409
-213
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
public class MySwiftClass {
16+
public static func method() {
17+
p("Hello from static method in a class!")
18+
}
19+
}

Samples/JExtractJNISampleApp/src/main/java/com/example/swift/HelloJava2Swift.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ static void examples() {
4040
long i = MySwiftLibrary.globalMakeInt();
4141
SwiftKit.trace("globalMakeInt() = " + i);
4242

43+
MySwiftClass.method();
44+
4345
System.out.println("DONE.");
4446
}
4547
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
extension JNISwift2JavaGenerator {
16+
func writeExportedJavaSources() throws {
17+
var printer = CodePrinter()
18+
try writeExportedJavaSources(&printer)
19+
}
20+
21+
package func writeExportedJavaSources(_ printer: inout CodePrinter) throws {
22+
for (_, ty) in analysis.importedTypes.sorted(by: { (lhs, rhs) in lhs.key < rhs.key }) {
23+
let filename = "\(ty.swiftNominal.name).java"
24+
logger.info("Printing contents: \(filename)")
25+
printImportedNominal(&printer, ty)
26+
27+
if let outputFile = try printer.writeContents(
28+
outputDirectory: javaOutputDirectory,
29+
javaPackagePath: javaPackagePath,
30+
filename: filename
31+
) {
32+
print("[swift-java] Generated: \(ty.swiftNominal.name.bold).java (at \(outputFile))")
33+
}
34+
}
35+
36+
let filename = "\(self.swiftModuleName).java"
37+
logger.trace("Printing module class: \(filename)")
38+
printModule(&printer)
39+
40+
if let outputFile = try printer.writeContents(
41+
outputDirectory: javaOutputDirectory,
42+
javaPackagePath: javaPackagePath,
43+
filename: filename
44+
) {
45+
logger.info("[swift-java] Generated: \(self.swiftModuleName).java (at \(outputFile))")
46+
}
47+
}
48+
49+
private func printModule(_ printer: inout CodePrinter) {
50+
printHeader(&printer)
51+
printPackage(&printer)
52+
53+
printModuleClass(&printer) { printer in
54+
printer.print(
55+
"""
56+
static final String LIB_NAME = "\(swiftModuleName)";
57+
58+
static {
59+
System.loadLibrary(LIB_NAME);
60+
}
61+
"""
62+
)
63+
64+
for decl in analysis.importedGlobalFuncs {
65+
self.logger.trace("Print global function: \(decl)")
66+
printFunctionBinding(&printer, decl)
67+
printer.println()
68+
}
69+
}
70+
}
71+
72+
private func printImportedNominal(_ printer: inout CodePrinter, _ decl: ImportedNominalType) {
73+
printHeader(&printer)
74+
printPackage(&printer)
75+
76+
printNominal(&printer, decl) { printer in
77+
for method in decl.methods {
78+
printFunctionBinding(&printer, method)
79+
}
80+
}
81+
}
82+
83+
private func printHeader(_ printer: inout CodePrinter) {
84+
printer.print(
85+
"""
86+
// Generated by jextract-swift
87+
// Swift module: \(swiftModuleName)
88+
89+
"""
90+
)
91+
}
92+
93+
private func printPackage(_ printer: inout CodePrinter) {
94+
printer.print(
95+
"""
96+
package \(javaPackage);
97+
98+
"""
99+
)
100+
}
101+
102+
private func printNominal(
103+
_ printer: inout CodePrinter, _ decl: ImportedNominalType, body: (inout CodePrinter) -> Void
104+
) {
105+
printer.printBraceBlock("public final class \(decl.swiftNominal.name)") { printer in
106+
body(&printer)
107+
}
108+
}
109+
110+
private func printModuleClass(_ printer: inout CodePrinter, body: (inout CodePrinter) -> Void) {
111+
printer.printBraceBlock("public final class \(swiftModuleName)") { printer in
112+
body(&printer)
113+
}
114+
}
115+
116+
private func printFunctionBinding(_ printer: inout CodePrinter, _ decl: ImportedFunc) {
117+
let returnType = decl.functionSignature.result.type.javaType
118+
let params = decl.functionSignature.parameters.enumerated().map { idx, param in
119+
"\(param.type.javaType) \(param.parameterName ?? "arg\(idx))")"
120+
}
121+
let throwsClause = decl.isThrowing ? " throws Exception" : ""
122+
123+
printer.print(
124+
"""
125+
/**
126+
* Downcall to Swift:
127+
* {@snippet lang=swift :
128+
* \(decl.signatureString)
129+
* }
130+
*/
131+
"""
132+
)
133+
printer.print(
134+
"public static native \(returnType) \(decl.name)(\(params.joined(separator: ", ")))\(throwsClause);"
135+
)
136+
}
137+
}
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
extension JNISwift2JavaGenerator {
16+
func writeSwiftThunkSources() throws {
17+
var printer = CodePrinter()
18+
try writeSwiftThunkSources(&printer)
19+
}
20+
21+
package func writeSwiftExpectedEmptySources() throws {
22+
for expectedFileName in self.expectedOutputSwiftFiles {
23+
logger.trace("Write empty file: \(expectedFileName) ...")
24+
25+
var printer = CodePrinter()
26+
printer.print("// Empty file generated on purpose")
27+
_ = try printer.writeContents(
28+
outputDirectory: self.swiftOutputDirectory,
29+
javaPackagePath: nil,
30+
filename: expectedFileName)
31+
}
32+
}
33+
34+
package func writeSwiftThunkSources(_ printer: inout CodePrinter) throws {
35+
let moduleFilenameBase = "\(self.swiftModuleName)Module+SwiftJava"
36+
let moduleFilename = "\(moduleFilenameBase).swift"
37+
38+
do {
39+
logger.trace("Printing swift module class: \(moduleFilename)")
40+
41+
try printGlobalSwiftThunkSources(&printer)
42+
43+
if let outputFile = try printer.writeContents(
44+
outputDirectory: self.swiftOutputDirectory,
45+
javaPackagePath: nil,
46+
filename: moduleFilename
47+
) {
48+
print("[swift-java] Generated: \(moduleFilenameBase.bold).swift (at \(outputFile))")
49+
self.expectedOutputSwiftFiles.remove(moduleFilename)
50+
}
51+
52+
for (_, ty) in self.analysis.importedTypes.sorted(by: { (lhs, rhs) in lhs.key < rhs.key }) {
53+
let fileNameBase = "\(ty.swiftNominal.qualifiedName)+SwiftJava"
54+
let filename = "\(fileNameBase).swift"
55+
logger.info("Printing contents: \(filename)")
56+
57+
do {
58+
try printNominalTypeThunks(&printer, ty)
59+
60+
if let outputFile = try printer.writeContents(
61+
outputDirectory: self.swiftOutputDirectory,
62+
javaPackagePath: nil,
63+
filename: filename) {
64+
print("[swift-java] Generated: \(fileNameBase.bold).swift (at \(outputFile))")
65+
self.expectedOutputSwiftFiles.remove(filename)
66+
}
67+
} catch {
68+
logger.warning("Failed to write to Swift thunks: \(filename)")
69+
}
70+
}
71+
} catch {
72+
logger.warning("Failed to write to Swift thunks: \(moduleFilename)")
73+
}
74+
}
75+
76+
private func printGlobalSwiftThunkSources(_ printer: inout CodePrinter) throws {
77+
printHeader(&printer)
78+
79+
for decl in analysis.importedGlobalFuncs {
80+
printSwiftFunctionThunk(&printer, decl)
81+
printer.println()
82+
}
83+
}
84+
85+
private func printNominalTypeThunks(_ printer: inout CodePrinter, _ type: ImportedNominalType) throws {
86+
printHeader(&printer)
87+
88+
for decl in type.methods {
89+
printSwiftFunctionThunk(&printer, decl, sorroundingType: type)
90+
printer.println()
91+
}
92+
}
93+
94+
private func printSwiftFunctionThunk(
95+
_ printer: inout CodePrinter,
96+
_ decl: ImportedFunc,
97+
sorroundingType: ImportedNominalType? = nil
98+
) {
99+
let parentName = sorroundingType?.swiftNominal.qualifiedName ?? swiftModuleName
100+
101+
let cName =
102+
"Java_" + self.javaPackage.replacingOccurrences(of: ".", with: "_") + "_\(parentName)_"
103+
+ decl.name
104+
let thunkName = thunkNameRegistry.functionThunkName(decl: decl)
105+
let translatedParameters = decl.functionSignature.parameters.enumerated().map { idx, param in
106+
(param.parameterName ?? "arg\(idx)", param.type.javaType)
107+
}
108+
109+
let thunkParameters =
110+
[
111+
"environment: UnsafeMutablePointer<JNIEnv?>!",
112+
"thisClass: jclass",
113+
] + translatedParameters.map { "\($0.0): \($0.1.jniTypeName)" }
114+
let swiftReturnType = decl.functionSignature.result.type
115+
let thunkReturnType =
116+
!swiftReturnType.isVoid ? " -> \(swiftReturnType.javaType.jniTypeName)" : ""
117+
118+
printer.printBraceBlock(
119+
"""
120+
@_cdecl("\(cName)")
121+
func \(thunkName)(\(thunkParameters.joined(separator: ", ")))\(thunkReturnType)
122+
"""
123+
) { printer in
124+
let downcallParameters = zip(decl.functionSignature.parameters, translatedParameters).map {
125+
originalParam, translatedParam in
126+
let label = originalParam.argumentLabel.map { "\($0): " } ?? ""
127+
return "\(label)\(originalParam.type)(fromJNI: \(translatedParam.0), in: environment!)"
128+
}
129+
let tryClause: String = decl.isThrowing ? "try " : ""
130+
let functionDowncall =
131+
"\(tryClause)\(parentName).\(decl.name)(\(downcallParameters.joined(separator: ", ")))"
132+
133+
let innerBody =
134+
if swiftReturnType.isVoid {
135+
functionDowncall
136+
} else {
137+
"""
138+
let result = \(functionDowncall)
139+
return result.getJNIValue(in: environment)
140+
"""
141+
}
142+
143+
if decl.isThrowing {
144+
let dummyReturn =
145+
!swiftReturnType.isVoid ? "return \(swiftReturnType).jniPlaceholderValue" : ""
146+
printer.print(
147+
"""
148+
do {
149+
\(innerBody)
150+
} catch {
151+
environment.throwAsException(error)
152+
\(dummyReturn)
153+
}
154+
"""
155+
)
156+
} else {
157+
printer.print(innerBody)
158+
}
159+
}
160+
}
161+
162+
private func printHeader(_ printer: inout CodePrinter) {
163+
printer.print(
164+
"""
165+
// Generated by swift-java
166+
167+
import JavaKit
168+
169+
"""
170+
)
171+
}
172+
}

0 commit comments

Comments
 (0)