Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@
import SwiftJava
import SwiftJavaJNICore

@JavaInterface(
"java.util.function.BinaryOperator",
extends: JavaBiFunction<JavaObject, JavaObject, JavaObject>.self
)
@JavaInterface("java.util.function.BinaryOperator", extends: JavaBiFunction<JavaObject, JavaObject, JavaObject>.self)
public struct JavaBinaryOperator<T: AnyJavaObject> {
@JavaMethod
public func apply(_ arg0: JavaObject?, _ arg1: JavaObject?) -> JavaObject?
/// Java method `apply`.
///
/// ### Java method signature
/// ```java
/// public abstract R java.util.function.BiFunction.apply(T,U)
/// ```
@JavaMethod(typeErasedResult: "T!")
public func apply(_ arg0: T?, _ arg1: T?) -> T!

/// Java method `andThen`.
///
/// ### Java method signature
/// ```java
/// public default <V> java.util.function.BiFunction<T, U, V> java.util.function.BiFunction.andThen(java.util.function.Function<? super R, ? extends V>)
/// ```
@JavaMethod
public func andThen(
_ arg0: JavaFunction<JavaObject, JavaObject>?
) -> JavaBiFunction<
JavaObject, JavaObject, JavaObject
>?
public func andThen<V: AnyJavaObject>(_ arg0: JavaFunction<JavaObject, V>?) -> JavaBiFunction<T, T, V>!
}
44 changes: 29 additions & 15 deletions Sources/JavaStdlib/JavaUtilFunction/generated/JavaFunction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,40 @@ import SwiftJavaJNICore

@JavaInterface("java.util.function.Function")
public struct JavaFunction<T: AnyJavaObject, R: AnyJavaObject> {
@JavaMethod
public func apply(_ arg0: JavaObject?) -> JavaObject?
/// Java method `apply`.
///
/// ### Java method signature
/// ```java
/// public abstract R java.util.function.Function.apply(T)
/// ```
@JavaMethod(typeErasedResult: "R!")
public func apply(_ arg0: T?) -> R!

/// Java method `compose`.
///
/// ### Java method signature
/// ```java
/// public default <V> java.util.function.Function<V, R> java.util.function.Function.compose(java.util.function.Function<? super V, ? extends T>)
/// ```
@JavaMethod
public func compose(
_ arg0: JavaFunction<JavaObject, JavaObject>?
) -> JavaFunction<
JavaObject, JavaObject
>?
public func compose<V: AnyJavaObject>(_ arg0: JavaFunction<JavaObject, T>?) -> JavaFunction<V, R>!

/// Java method `andThen`.
///
/// ### Java method signature
/// ```java
/// public default <V> java.util.function.Function<T, V> java.util.function.Function.andThen(java.util.function.Function<? super R, ? extends V>)
/// ```
@JavaMethod
public func andThen(
_ arg0: JavaFunction<JavaObject, JavaObject>?
) -> JavaFunction<
JavaObject, JavaObject
>?
public func andThen<V: AnyJavaObject>(_ arg0: JavaFunction<JavaObject, V>?) -> JavaFunction<T, V>!
}
extension JavaClass {
/// Java method `identity`.
///
/// ### Java method signature
/// ```java
/// public static <T> java.util.function.Function<T, T> java.util.function.Function.identity()
/// ```
@JavaStaticMethod
public func identity<T: AnyJavaObject, R: AnyJavaObject>() -> JavaFunction<
JavaObject, JavaObject
>? where ObjectType == JavaFunction<T, R>
public func identity<T: AnyJavaObject, R: AnyJavaObject>() -> JavaFunction<T, T>! where ObjectType == JavaFunction<T, R>
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,42 @@
import SwiftJava
import SwiftJavaJNICore

@JavaInterface(
"java.util.function.UnaryOperator",
extends: JavaFunction<JavaObject, JavaObject>.self
)
@JavaInterface("java.util.function.UnaryOperator", extends: JavaFunction<JavaObject, JavaObject>.self)
public struct JavaUnaryOperator<T: AnyJavaObject> {
@JavaMethod
public func apply(_ arg0: JavaObject?) -> JavaObject?
/// Java method `apply`.
///
/// ### Java method signature
/// ```java
/// public abstract R java.util.function.Function.apply(T)
/// ```
@JavaMethod(typeErasedResult: "T!")
public func apply(_ arg0: T?) -> T!

/// Java method `compose`.
///
/// ### Java method signature
/// ```java
/// public default <V> java.util.function.Function<V, R> java.util.function.Function.compose(java.util.function.Function<? super V, ? extends T>)
/// ```
@JavaMethod
public func compose(
_ arg0: JavaFunction<JavaObject, JavaObject>?
) -> JavaFunction<
JavaObject, JavaObject
>?
public func compose<V: AnyJavaObject>(_ arg0: JavaFunction<JavaObject, T>?) -> JavaFunction<V, T>!

/// Java method `andThen`.
///
/// ### Java method signature
/// ```java
/// public default <V> java.util.function.Function<T, V> java.util.function.Function.andThen(java.util.function.Function<? super R, ? extends V>)
/// ```
@JavaMethod
public func andThen(
_ arg0: JavaFunction<JavaObject, JavaObject>?
) -> JavaFunction<
JavaObject, JavaObject
>?
public func andThen<V: AnyJavaObject>(_ arg0: JavaFunction<JavaObject, V>?) -> JavaFunction<T, V>!
}
extension JavaClass {
/// Java method `identity`.
///
/// ### Java method signature
/// ```java
/// public static <T> java.util.function.UnaryOperator<T> java.util.function.UnaryOperator.identity()
/// ```
@JavaStaticMethod
public func identity<T: AnyJavaObject>() -> JavaUnaryOperator<JavaObject>?
where ObjectType == JavaUnaryOperator<T>
public func identity<T: AnyJavaObject>() -> JavaUnaryOperator<T>! where ObjectType == JavaUnaryOperator<T>
}
24 changes: 18 additions & 6 deletions Sources/SwiftJavaToolLib/JavaClassTranslator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ struct JavaClassTranslator {
/// The Swift names of the interfaces that this class implements.
let swiftInterfaces: [String]

/// Substitution map for resolving generic types.
let substitution: SubstitutionMap

/// The annotations of the Java class.
/// In other words, RUNTIME retained annotations, visible through reflection.
let annotations: [Annotation]
Expand Down Expand Up @@ -138,6 +141,9 @@ struct JavaClassTranslator {
self.javaTypeParameters = javaClass.getTypeParameters().compactMap { $0 }
self.nestedClasses = translator.nestedClasses[fullName] ?? []

// Generic substitution.
self.substitution = SubstitutionMap(startingFrom: javaClass)

// Superclass, incl parameter types (if any)
if !javaClass.isInterface() {
var javaSuperclass = javaClass.getSuperclass()
Expand All @@ -149,12 +155,13 @@ struct JavaClassTranslator {
swiftSuperclassName = try translator.getSwiftTypeName(javaSuperclassNonOpt, preferValueTypes: false).swiftName
if let javaGenericSuperclass = javaGenericSuperclass?.as(ParameterizedType.self) {
for typeArg in javaGenericSuperclass.getActualTypeArguments() {
let javaTypeArgName = typeArg?.getTypeName() ?? ""
if let swiftTypeArgName = self.translator.translatedClasses[javaTypeArgName] {
swiftSuperclassTypeArgs.append(swiftTypeArgName.qualifiedName)
} else {
swiftSuperclassTypeArgs.append("/* MISSING MAPPING FOR */ \(javaTypeArgName)")
}
let mappedSwiftName = try translator.getSwiftTypeNameAsString(
typeArg!,
substitution: substitution,
preferValueTypes: false,
outerOptional: .nonoptional
)
swiftSuperclassTypeArgs.append(mappedSwiftName)
}
}
break
Expand Down Expand Up @@ -185,6 +192,7 @@ struct JavaClassTranslator {
do {
return try translator.getSwiftTypeNameAsString(
javaType,
substitution: nil,
preferValueTypes: false,
outerOptional: .nonoptional,
eraseTypeArguments: true
Expand Down Expand Up @@ -920,6 +928,7 @@ extension JavaClassTranslator {
let resultTypeStr: String
let resultType = try translator.getSwiftReturnTypeNameAsString(
method: javaMethod,
substitution: substitution,
preferValueTypes: true,
outerOptional: .implicitlyUnwrappedOptional
)
Expand Down Expand Up @@ -1050,6 +1059,7 @@ extension JavaClassTranslator {
package func renderField(_ javaField: Field) throws -> DeclSyntax {
let typeName = try translator.getSwiftTypeNameAsString(
javaField.getGenericType()!,
substitution: substitution,
preferValueTypes: true,
outerOptional: .implicitlyUnwrappedOptional
)
Expand Down Expand Up @@ -1163,6 +1173,7 @@ extension JavaClassTranslator {
let typeName = try translator.getSwiftTypeNameAsString(
method: javaMethod,
javaParameter.getParameterizedType()!,
substitution: substitution,
preferValueTypes: true,
outerOptional: .optional
)
Expand All @@ -1181,6 +1192,7 @@ extension JavaClassTranslator {

let typeName = try translator.getSwiftTypeNameAsString(
javaParameter.getParameterizedType()!,
substitution: substitution,
preferValueTypes: true,
outerOptional: .optional
)
Expand Down
65 changes: 65 additions & 0 deletions Sources/SwiftJavaToolLib/JavaGenericsSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,68 @@ func isTypeErased(_ type: Type?) -> Bool {

return false
}

/// Handles generic type substitution by mapping type variables of ancestor classes
/// to actual types provided in 'extends' or 'implements' clauses.
struct SubstitutionMap {
private struct MapKey: Hashable {
var declaringClassName: String
var typeVariableName: String
}
private var mapping: [MapKey: Type] = [:]

init(startingFrom javaClass: JavaClass<JavaObject>) {
buildSubstitutionMap(for: javaClass)
}

private mutating func buildSubstitutionMap(for currentClass: JavaClass<JavaObject>) {
var genericParents: [Type] = currentClass.getGenericInterfaces().compactMap { $0 }
if let genericSuperclass = currentClass.getGenericSuperclass() {
genericParents.append(genericSuperclass)
}

for genericParent in genericParents {
guard let parameterizedParent = genericParent.as(ParameterizedType.self) else {
// If the parent is not parameterized, still check its ancestors recursively
if let rawParent = genericParent.as(JavaClass<JavaObject>.self) {
buildSubstitutionMap(for: rawParent)
}
continue
}
guard let rawParent = parameterizedParent.getRawType()?.as(JavaClass<JavaObject>.self) else {
continue
}

let typeParameters = rawParent.getTypeParameters()
let actualTypeArguments = parameterizedParent.getActualTypeArguments()

for (typeParam, actualArg) in zip(typeParameters, actualTypeArguments) {
guard let typeParam, let actualArg else { continue }

let key = MapKey(
declaringClassName: rawParent.getName(),
typeVariableName: typeParam.getName()
)
mapping[key] = actualArg
}

buildSubstitutionMap(for: rawParent)
}
}

func resolve(_ type: Type) -> Type? {
if let typeVar = type.as(TypeVariable<GenericDeclaration>.self),
let declClass = typeVar.getGenericDeclaration().as(JavaClass<JavaObject>.self)
{
let key = MapKey(
declaringClassName: declClass.getName(),
typeVariableName: typeVar.getName()
)
if let substituted = mapping[key] {
// Recursively resolve if the substituted type is also a type variable.
return resolve(substituted) ?? substituted
}
}
return nil
}
}
14 changes: 12 additions & 2 deletions Sources/SwiftJavaToolLib/JavaTranslator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ extension JavaTranslator {

func getSwiftReturnTypeNameAsString(
method: JavaLangReflect.Method,
substitution: SubstitutionMap?,
preferValueTypes: Bool,
outerOptional: OptionalKind
) throws -> String {
Expand All @@ -145,6 +146,7 @@ extension JavaTranslator {
return try getSwiftTypeNameAsString(
method: method,
genericReturnType!,
substitution: substitution,
preferValueTypes: preferValueTypes,
outerOptional: outerOptional
)
Expand All @@ -154,14 +156,18 @@ extension JavaTranslator {
func getSwiftTypeNameAsString(
method: JavaLangReflect.Method? = nil,
_ javaType: Type,
substitution: SubstitutionMap?,
preferValueTypes: Bool,
outerOptional: OptionalKind,
eraseTypeArguments: Bool = false
) throws -> String {
// Replace if it is a type variable and we have a substitution for it.
let javaType = substitution?.resolve(javaType) ?? javaType

// Replace type variables with their bounds.
if let typeVariable = javaType.as(TypeVariable<GenericDeclaration>.self),
typeVariable.getBounds().count == 1,
let bound = typeVariable.getBounds()[0]
typeVariable.getBounds()[0] != nil
{
return outerOptional.adjustTypeName(typeVariable.getName())
}
Expand All @@ -174,6 +180,7 @@ extension JavaTranslator {
// Replace a wildcard type with its first bound.
return try getSwiftTypeNameAsString(
bound,
substitution: substitution,
preferValueTypes: preferValueTypes,
outerOptional: outerOptional
)
Expand All @@ -184,6 +191,7 @@ extension JavaTranslator {
if preferValueTypes {
let elementType = try getSwiftTypeNameAsString(
arrayType.getGenericComponentType()!,
substitution: substitution,
preferValueTypes: preferValueTypes,
outerOptional: .optional
)
Expand All @@ -204,6 +212,7 @@ extension JavaTranslator {
if let rawJavaType = parameterizedType.getRawType() {
var rawSwiftType = try getSwiftTypeNameAsString(
rawJavaType,
substitution: substitution,
preferValueTypes: false,
outerOptional: outerOptional
)
Expand All @@ -225,12 +234,13 @@ extension JavaTranslator {
let mappedSwiftName = try getSwiftTypeNameAsString(
method: method,
typeArg,
substitution: substitution,
preferValueTypes: false,
outerOptional: .nonoptional
)

// FIXME: improve the get instead...
if mappedSwiftName == nil || mappedSwiftName == "JavaObject" {
if mappedSwiftName == "JavaObject" {
// Try to salvage it, is it perhaps a type parameter?
if let method {
let typeParameters = method.getTypeParameters() as [TypeVariable<JavaLangReflect.Method>?]
Expand Down
Loading
Loading