Skip to content

Commit 45a9aea

Browse files
committed
multiple generic types on a method
1 parent 10dabf8 commit 45a9aea

File tree

3 files changed

+132
-35
lines changed

3 files changed

+132
-35
lines changed

Sources/SwiftJavaToolLib/JavaClassTranslator.swift

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,8 @@ extension JavaClassTranslator {
566566
let accessModifier = javaConstructor.isPublic ? "public " : ""
567567
let convenienceModifier = translateAsClass ? "convenience " : ""
568568
let nonoverrideAttribute = translateAsClass ? "@_nonoverride " : ""
569+
570+
// FIXME: handle generics in constructors
569571
return """
570572
@JavaMethod
571573
\(raw: nonoverrideAttribute)\(raw: accessModifier)\(raw: convenienceModifier)init(\(raw: parametersStr))\(raw: throwsStr)
@@ -592,13 +594,9 @@ extension JavaClassTranslator {
592594
}
593595

594596
// Map the parameters.
595-
let parameters = try translateJavaParameters(javaMethod.getParameters())
596-
597+
let parameters = try translateJavaParameters(javaMethod)
597598
let parametersStr = parameters.map { $0.description }.joined(separator: ", ")
598599

599-
print("javaMethod.getReturnType() == \(javaMethod.getReturnType())")
600-
print("javaMethod.getGenericReturnType() == \(javaMethod.getGenericReturnType())")
601-
602600
// Map the result type.
603601
let resultTypeStr: String
604602
let resultType = try translator.getSwiftReturnTypeNameAsString(
@@ -763,7 +761,30 @@ extension JavaClassTranslator {
763761
}
764762

765763
// Translate a Java parameter list into Swift parameters.
766-
private func translateJavaParameters(_ parameters: [Parameter?]) throws -> [FunctionParameterSyntax] {
764+
private func translateJavaParameters(
765+
_ javaMethod: JavaLangReflect.Method
766+
) throws -> [FunctionParameterSyntax] {
767+
let parameters: [Parameter?] = javaMethod.getParameters()
768+
769+
return try parameters.compactMap { javaParameter in
770+
guard let javaParameter else { return nil }
771+
772+
let typeName = try translator.getSwiftTypeNameAsString(
773+
method: javaMethod,
774+
javaParameter.getParameterizedType()!,
775+
preferValueTypes: true,
776+
outerOptional: .optional
777+
)
778+
let paramName = javaParameter.getName()
779+
return "_ \(raw: paramName): \(raw: typeName)"
780+
}
781+
}
782+
783+
// Translate a Java parameter list into Swift parameters.
784+
@available(*, deprecated, message: "Prefer the method based version") // FIXME: constructors are not well handled
785+
private func translateJavaParameters(
786+
_ parameters: [Parameter?]
787+
) throws -> [FunctionParameterSyntax] {
767788
return try parameters.compactMap { javaParameter in
768789
guard let javaParameter else { return nil }
769790

Sources/SwiftJavaToolLib/JavaTranslator.swift

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,26 @@ func getSwiftReturnTypeNameAsString(
135135
}
136136
}
137137

138-
return try getSwiftTypeNameAsString(genericReturnType!, preferValueTypes: preferValueTypes, outerOptional: outerOptional)
138+
return try getSwiftTypeNameAsString(method: method, genericReturnType!, preferValueTypes: preferValueTypes, outerOptional: outerOptional)
139139
}
140140

141141
/// Turn a Java type into a string.
142142
func getSwiftTypeNameAsString(
143+
method: JavaLangReflect.Method? = nil,
143144
_ javaType: Type,
144145
preferValueTypes: Bool,
145146
outerOptional: OptionalKind
146147
) throws -> String {
148+
print("get the javaType ==== \(javaType)")
149+
150+
// if let method,
151+
// let parameterizedType = javaType.as(ParameterizedType.self) {
152+
// if method.getGenericParameterTypes().contains(where: {$0?.getTypeName() == javaType.getTypeName()}) {
153+
// fatalError("java type = \(javaType.as(ParameterizedType.self))")
154+
// return javaType.getTypeName()
155+
// }
156+
// }
157+
147158
// Replace type variables with their bounds.
148159
if let typeVariable = javaType.as(TypeVariable<GenericDeclaration>.self),
149160
typeVariable.getBounds().count == 1,
@@ -190,30 +201,49 @@ func getSwiftReturnTypeNameAsString(
190201

191202
// Handle parameterized types by recursing on the raw type and the type
192203
// arguments.
193-
if let parameterizedType = javaType.as(ParameterizedType.self),
194-
let rawJavaType = parameterizedType.getRawType()
195-
{
196-
var rawSwiftType = try getSwiftTypeNameAsString(
197-
rawJavaType,
198-
preferValueTypes: false,
199-
outerOptional: outerOptional
200-
)
201-
202-
let optionalSuffix: String
203-
if let lastChar = rawSwiftType.last, lastChar == "?" || lastChar == "!" {
204-
optionalSuffix = "\(lastChar)"
205-
rawSwiftType.removeLast()
206-
} else {
207-
optionalSuffix = ""
208-
}
204+
print("parameterizedType = \(javaType.as(ParameterizedType.self))")
205+
print("parameterizedType.getRawType() = \(javaType.as(ParameterizedType.self)?.getRawType())")
206+
207+
if let parameterizedType = javaType.as(ParameterizedType.self) {
208+
if let rawJavaType = parameterizedType.getRawType() {
209+
var rawSwiftType = try getSwiftTypeNameAsString(
210+
rawJavaType,
211+
preferValueTypes: false,
212+
outerOptional: outerOptional
213+
)
214+
print("MAPPED rawSwiftType = \(rawSwiftType)")
215+
print("MAPPED parameterizedType.getActualTypeArguments() = \(parameterizedType.getActualTypeArguments())")
216+
217+
let optionalSuffix: String
218+
if let lastChar = rawSwiftType.last, lastChar == "?" || lastChar == "!" {
219+
optionalSuffix = "\(lastChar)"
220+
rawSwiftType.removeLast()
221+
} else {
222+
optionalSuffix = ""
223+
}
209224

210-
let typeArguments = try parameterizedType.getActualTypeArguments().compactMap { typeArg in
211-
try typeArg.map { typeArg in
212-
try getSwiftTypeNameAsString(typeArg, preferValueTypes: false, outerOptional: .nonoptional)
225+
let typeArguments: [String] = try parameterizedType.getActualTypeArguments().compactMap { typeArg in
226+
guard let typeArg else { return nil }
227+
228+
let mappedSwiftName = try getSwiftTypeNameAsString(method: method, typeArg, preferValueTypes: false, outerOptional: .nonoptional)
229+
230+
// FIXME: improve the get instead...
231+
if mappedSwiftName == nil || mappedSwiftName == "JavaObject" {
232+
// Try to salvage it, is it perhaps a type parameter?
233+
if let method {
234+
if method.getTypeParameters().contains(where: { $0?.getTypeName() == typeArg.getTypeName() }) {
235+
return typeArg.getTypeName()
236+
}
237+
}
238+
}
239+
240+
return mappedSwiftName
213241
}
214-
}
215242

216-
return "\(rawSwiftType)<\(typeArguments.joined(separator: ", "))>\(optionalSuffix)"
243+
print("MAPPED ->> typeArguments = \(typeArguments)")
244+
245+
return "\(rawSwiftType)<\(typeArguments.joined(separator: ", "))>\(optionalSuffix)"
246+
}
217247
}
218248

219249
// Handle direct references to Java classes.

Tests/SwiftJavaToolLibTests/WrapJavaTests.swift

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class WrapJavaTests: XCTestCase {
4848
)
4949
}
5050

51-
func testWrapJavaGenericMethod() async throws {
51+
func testWrapJavaGenericMethod_singleGeneric() async throws {
5252
do {
5353
let classpathURL = try await compileJava(
5454
"""
@@ -64,7 +64,6 @@ class WrapJavaTests: XCTestCase {
6464
6565
class ExampleSimpleClass {
6666
<KeyType> KeyType getGeneric(Item<KeyType> key) { return null; }
67-
// <KeyType, ValueType> Pair<KeyType, ValueType> getPair(String name, Item<KeyType> key, Item<ValueType> value) { return null; }
6867
}
6968
""")
7069

@@ -90,12 +89,59 @@ class WrapJavaTests: XCTestCase {
9089
""",
9190
"""
9291
@JavaMethod
93-
open func getGeneric<T1>(_ arg0: String, _ arg1: Item<T1>?) -> T1!
92+
open func getGeneric<KeyType: AnyJavaObject>(_ arg0: Item<KeyType>?) -> KeyType {
93+
""",
94+
]
95+
)
96+
} catch let error as Throwable {
97+
error.printStackTrace()
98+
XCTFail("error: \(error)")
99+
}
100+
}
101+
102+
func testWrapJavaGenericMethod_multipleGenerics() async throws {
103+
do {
104+
let classpathURL = try await compileJava(
105+
"""
106+
package com.example;
107+
108+
class Item<T> {
109+
final T value;
110+
Item(T item) {
111+
this.value = item;
112+
}
113+
}
114+
class Pair<First, Second> { }
115+
116+
class ExampleSimpleClass {
117+
<KeyType, ValueType> Pair<KeyType, ValueType> getPair(String name, Item<KeyType> key, Item<ValueType> value) { return null; }
118+
}
119+
""")
120+
121+
try assertWrapJavaOutput(
122+
javaClassNames: [
123+
"com.example.Item",
124+
"com.example.Pair",
125+
"com.example.ExampleSimpleClass"
126+
],
127+
classpath: [classpathURL],
128+
expectedChunks: [
129+
"""
130+
import CSwiftJavaJNI
131+
import SwiftJava
132+
""",
133+
"""
134+
@JavaClass("com.example.ExampleSimpleClass")
135+
open class ExampleSimpleClass: JavaObject {
136+
""",
137+
"""
138+
@JavaClass("com.example.ExampleSimpleClass")
139+
open class ExampleSimpleClass: JavaObject {
140+
""",
141+
"""
142+
@JavaMethod
143+
open func getPair<KeyType: AnyJavaObject, ValueType: AnyJavaObject>(_ arg0: String, _ arg1: Item<KeyType>?, _ arg2: Item<ValueType>) -> KeyType {
94144
""",
95-
// """
96-
// @JavaMethod
97-
// open func getStore<T1, T2>(_ arg0: String, _ arg1: Item<T1>?, _ arg2: Item<T2>?) -> BDStore<T1, T2>!
98-
// """
99145
]
100146
)
101147
} catch let error as Throwable {

0 commit comments

Comments
 (0)