From 3305ee38e6672e4db1231018e0a7c5bb437f0dbf Mon Sep 17 00:00:00 2001 From: Iceman Date: Tue, 17 Mar 2026 11:52:55 +0900 Subject: [PATCH 01/10] Add typeErasedResultBound parameter --- .../JavaClass+Reflection.swift | 4 + .../generated/TypeVariable.swift | 90 +++++++++++++++++-- Sources/SwiftJava/Macros.swift | 7 ++ Sources/SwiftJavaMacros/JavaMethodMacro.swift | 21 +++-- .../SwiftJavaMacros/SwiftSyntaxUtils.swift | 12 +++ .../JavaClassTranslator.swift | 9 +- 6 files changed, 124 insertions(+), 19 deletions(-) diff --git a/Sources/JavaStdlib/JavaLangReflect/JavaClass+Reflection.swift b/Sources/JavaStdlib/JavaLangReflect/JavaClass+Reflection.swift index 49e93ee3f..11061f85d 100644 --- a/Sources/JavaStdlib/JavaLangReflect/JavaClass+Reflection.swift +++ b/Sources/JavaStdlib/JavaLangReflect/JavaClass+Reflection.swift @@ -49,4 +49,8 @@ extension JavaClass { @JavaMethod public func getAnnotations() -> [Annotation?] + + public func `as`(_: Type.Type) -> Type { + Type(javaHolder: javaHolder) + } } diff --git a/Sources/JavaStdlib/JavaLangReflect/generated/TypeVariable.swift b/Sources/JavaStdlib/JavaLangReflect/generated/TypeVariable.swift index 76c21b7d0..a9fe224ed 100644 --- a/Sources/JavaStdlib/JavaLangReflect/generated/TypeVariable.swift +++ b/Sources/JavaStdlib/JavaLangReflect/generated/TypeVariable.swift @@ -3,40 +3,112 @@ import SwiftJava import SwiftJavaJNICore @JavaInterface("java.lang.reflect.TypeVariable", extends: Type.self) -public struct TypeVariable: CustomStringConvertible { - @JavaMethod - public func getGenericDeclaration() -> GenericDeclaration! +public struct TypeVariable { + /// Java method `getGenericDeclaration`. + /// + /// ### Java method signature + /// ```java + /// public abstract D java.lang.reflect.TypeVariable.getGenericDeclaration() + /// ``` + @JavaMethod(typeErasedResult: "D!", typeErasedResultBound: GenericDeclaration?.self) + public func getGenericDeclaration() -> D! + /// Java method `getAnnotatedBounds`. + /// + /// ### Java method signature + /// ```java + /// public abstract java.lang.reflect.AnnotatedType[] java.lang.reflect.TypeVariable.getAnnotatedBounds() + /// ``` @JavaMethod public func getAnnotatedBounds() -> [AnnotatedType?] + /// Java method `getName`. + /// + /// ### Java method signature + /// ```java + /// public abstract java.lang.String java.lang.reflect.TypeVariable.getName() + /// ``` @JavaMethod public func getName() -> String + /// Java method `getBounds`. + /// + /// ### Java method signature + /// ```java + /// public abstract java.lang.reflect.Type[] java.lang.reflect.TypeVariable.getBounds() + /// ``` @JavaMethod public func getBounds() -> [Type?] + /// Java method `getTypeName`. + /// + /// ### Java method signature + /// ```java + /// public default java.lang.String java.lang.reflect.Type.getTypeName() + /// ``` @JavaMethod public func getTypeName() -> String + /// Java method `isAnnotationPresent`. + /// + /// ### Java method signature + /// ```java + /// public default boolean java.lang.reflect.AnnotatedElement.isAnnotationPresent(java.lang.Class) + /// ``` @JavaMethod public func isAnnotationPresent(_ arg0: JavaClass?) -> Bool - @JavaMethod - public func getAnnotation(_ arg0: JavaClass?) -> Annotation! + /// Java method `getAnnotation`. + /// + /// ### Java method signature + /// ```java + /// public abstract T java.lang.reflect.AnnotatedElement.getAnnotation(java.lang.Class) + /// ``` + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) + public func getAnnotation(_ arg0: JavaClass?) -> T! + /// Java method `getAnnotationsByType`. + /// + /// ### Java method signature + /// ```java + /// public default T[] java.lang.reflect.AnnotatedElement.getAnnotationsByType(java.lang.Class) + /// ``` @JavaMethod - public func getAnnotationsByType(_ arg0: JavaClass?) -> [Annotation?] + public func getAnnotationsByType(_ arg0: JavaClass?) -> [T?] + /// Java method `getAnnotations`. + /// + /// ### Java method signature + /// ```java + /// public abstract java.lang.annotation.Annotation[] java.lang.reflect.AnnotatedElement.getAnnotations() + /// ``` @JavaMethod public func getAnnotations() -> [Annotation?] - @JavaMethod - public func getDeclaredAnnotation(_ arg0: JavaClass?) -> Annotation! + /// Java method `getDeclaredAnnotation`. + /// + /// ### Java method signature + /// ```java + /// public default T java.lang.reflect.AnnotatedElement.getDeclaredAnnotation(java.lang.Class) + /// ``` + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) + public func getDeclaredAnnotation(_ arg0: JavaClass?) -> T! + /// Java method `getDeclaredAnnotationsByType`. + /// + /// ### Java method signature + /// ```java + /// public default T[] java.lang.reflect.AnnotatedElement.getDeclaredAnnotationsByType(java.lang.Class) + /// ``` @JavaMethod - public func getDeclaredAnnotationsByType(_ arg0: JavaClass?) -> [Annotation?] + public func getDeclaredAnnotationsByType(_ arg0: JavaClass?) -> [T?] + /// Java method `getDeclaredAnnotations`. + /// + /// ### Java method signature + /// ```java + /// public abstract java.lang.annotation.Annotation[] java.lang.reflect.AnnotatedElement.getDeclaredAnnotations() + /// ``` @JavaMethod public func getDeclaredAnnotations() -> [Annotation?] } diff --git a/Sources/SwiftJava/Macros.swift b/Sources/SwiftJava/Macros.swift index c0993254f..525638751 100644 --- a/Sources/SwiftJava/Macros.swift +++ b/Sources/SwiftJava/Macros.swift @@ -146,6 +146,13 @@ public macro JavaMethod( typeErasedResult: String? = nil ) = #externalMacro(module: "SwiftJavaMacros", type: "JavaMethodMacro") +@attached(body) +public macro JavaMethod( + _ javaMethodName: String? = nil, + typeErasedResult: String, + typeErasedResultBound: Result.Type, +) = #externalMacro(module: "SwiftJavaMacros", type: "JavaMethodMacro") + /// Attached macro that turns a Swift method on JavaClass into one that wraps /// a Java static method on the underlying Java class object. /// diff --git a/Sources/SwiftJavaMacros/JavaMethodMacro.swift b/Sources/SwiftJavaMacros/JavaMethodMacro.swift index 9996127d7..3e685137a 100644 --- a/Sources/SwiftJavaMacros/JavaMethodMacro.swift +++ b/Sources/SwiftJavaMacros/JavaMethodMacro.swift @@ -53,10 +53,8 @@ extension JavaMethodMacro: BodyMacro { var resultStatements: [CodeBlockItemSyntax] = [] let funcName = - if case .argumentList(let arguments) = node.arguments, - let argument = arguments.first, - argument.label?.text != "typeErasedResult", - let stringLiteral = argument.expression.as(StringLiteralExprSyntax.self), + if let expression = node.arguments?.firstExpr(label: nil), + let stringLiteral = expression.as(StringLiteralExprSyntax.self), stringLiteral.segments.count == 1, case let .stringSegment(funcNameSegment)? = stringLiteral.segments.first { @@ -91,10 +89,8 @@ extension JavaMethodMacro: BodyMacro { } let genericResultType: String? = - if case let .argumentList(arguments) = node.arguments, - let element = arguments.first(where: { $0.label?.text == "typeErasedResult" }), - let stringLiteral = element.expression - .as(StringLiteralExprSyntax.self), + if let expression = node.arguments?.firstExpr(label: "typeErasedResult"), + let stringLiteral = expression.as(StringLiteralExprSyntax.self), stringLiteral.segments.count == 1, case let .stringSegment(wrapperName)? = stringLiteral.segments.first { @@ -110,6 +106,13 @@ extension JavaMethodMacro: BodyMacro { nil } + let typeErasedResultBound: String? = + if let expression = node.arguments?.firstExpr(label: "typeErasedResultBound") { + expression.trimmedDescription + } else { + nil + } + // Determine the result type let resultType: String = if let returnClause = funcDecl.signature.returnClause { @@ -117,7 +120,7 @@ extension JavaMethodMacro: BodyMacro { // we need to type-erase the signature, because on JVM level generics are erased and we'd otherwise // form a signature with the "concrete" type, which would not match the real byte-code level signature // of the method we're trying to call -- which would result in a MethodNotFound exception. - ", resultType: /*type-erased:\(genericResultType)*/JavaObject?.self" + ", resultType: /*type-erased:\(genericResultType)*/\(typeErasedResultBound ?? "JavaObject?.self")" } else { ", resultType: \(returnClause.type.typeReferenceString).self" } diff --git a/Sources/SwiftJavaMacros/SwiftSyntaxUtils.swift b/Sources/SwiftJavaMacros/SwiftSyntaxUtils.swift index 086070566..baf62ffa3 100644 --- a/Sources/SwiftJavaMacros/SwiftSyntaxUtils.swift +++ b/Sources/SwiftJavaMacros/SwiftSyntaxUtils.swift @@ -29,3 +29,15 @@ extension FunctionParameterSyntax { return firstName.text } } + +extension AttributeSyntax.Arguments { + func firstExpr(label: String?) -> ExprSyntax? { + if case let .argumentList(arguments) = self, + let element = arguments.first(where: { $0.label?.text == label }) + { + element.expression + } else { + nil + } + } +} diff --git a/Sources/SwiftJavaToolLib/JavaClassTranslator.swift b/Sources/SwiftJavaToolLib/JavaClassTranslator.swift index 31bc2e561..284a72ac8 100644 --- a/Sources/SwiftJavaToolLib/JavaClassTranslator.swift +++ b/Sources/SwiftJavaToolLib/JavaClassTranslator.swift @@ -988,7 +988,14 @@ extension JavaClassTranslator { parameters.append("\"init\"") } if hasTypeEraseGenericResultType { - parameters.append("typeErasedResult: \"\(resultType)\"") + let boundType = try translator.getSwiftTypeNameAsString( + method: javaMethod, + javaMethod.getReturnType().as(Type.self), + substitution: substitution, + preferValueTypes: true, + outerOptional: .optional + ) + parameters.append(#"typeErasedResult: "\#(resultType)", typeErasedResultBound: \#(boundType).self"#) } // TODO: generic parameters? From 15573765cd3785b76c3c4ce62596408f043eb204 Mon Sep 17 00:00:00 2001 From: Iceman Date: Tue, 17 Mar 2026 12:16:10 +0900 Subject: [PATCH 02/10] Generate related classes in JavaLangReflect --- .../generated/AccessibleObject.swift | 4 +- .../generated/AnnotatedType.swift | 66 +++++++- .../generated/Constructor.swift | 4 +- .../generated/Executable.swift | 2 +- .../JavaLangReflect/generated/Field.swift | 2 +- .../generated/GenericDeclaration.swift | 60 +++++++- .../JavaLangReflect/generated/Method.swift | 2 +- .../JavaLangReflect/generated/Parameter.swift | 143 ++++++++++++++++-- 8 files changed, 249 insertions(+), 34 deletions(-) diff --git a/Sources/JavaStdlib/JavaLangReflect/generated/AccessibleObject.swift b/Sources/JavaStdlib/JavaLangReflect/generated/AccessibleObject.swift index 7527bc1ed..5b54b1df8 100644 --- a/Sources/JavaStdlib/JavaLangReflect/generated/AccessibleObject.swift +++ b/Sources/JavaStdlib/JavaLangReflect/generated/AccessibleObject.swift @@ -28,7 +28,7 @@ open class AccessibleObject: JavaObject { /// ```java /// public T java.lang.reflect.AccessibleObject.getAnnotation(java.lang.Class) /// ``` - @JavaMethod(typeErasedResult: "T!") + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) open func getAnnotation(_ arg0: JavaClass?) -> T! /// Java method `getAnnotationsByType`. @@ -55,7 +55,7 @@ open class AccessibleObject: JavaObject { /// ```java /// public T java.lang.reflect.AccessibleObject.getDeclaredAnnotation(java.lang.Class) /// ``` - @JavaMethod(typeErasedResult: "T!") + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) open func getDeclaredAnnotation(_ arg0: JavaClass?) -> T! /// Java method `getDeclaredAnnotationsByType`. diff --git a/Sources/JavaStdlib/JavaLangReflect/generated/AnnotatedType.swift b/Sources/JavaStdlib/JavaLangReflect/generated/AnnotatedType.swift index 95407466b..13ce2d906 100644 --- a/Sources/JavaStdlib/JavaLangReflect/generated/AnnotatedType.swift +++ b/Sources/JavaStdlib/JavaLangReflect/generated/AnnotatedType.swift @@ -4,30 +4,84 @@ import SwiftJavaJNICore @JavaInterface("java.lang.reflect.AnnotatedType") public struct AnnotatedType { + /// Java method `getAnnotatedOwnerType`. + /// + /// ### Java method signature + /// ```java + /// public default java.lang.reflect.AnnotatedType java.lang.reflect.AnnotatedType.getAnnotatedOwnerType() + /// ``` @JavaMethod public func getAnnotatedOwnerType() -> AnnotatedType! - @JavaMethod - public func getAnnotation(_ arg0: JavaClass?) -> Annotation! + /// Java method `getAnnotation`. + /// + /// ### Java method signature + /// ```java + /// public abstract T java.lang.reflect.AnnotatedType.getAnnotation(java.lang.Class) + /// ``` + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) + public func getAnnotation(_ arg0: JavaClass?) -> T! + /// Java method `getAnnotations`. + /// + /// ### Java method signature + /// ```java + /// public abstract java.lang.annotation.Annotation[] java.lang.reflect.AnnotatedType.getAnnotations() + /// ``` @JavaMethod public func getAnnotations() -> [Annotation?] + /// Java method `getDeclaredAnnotations`. + /// + /// ### Java method signature + /// ```java + /// public abstract java.lang.annotation.Annotation[] java.lang.reflect.AnnotatedType.getDeclaredAnnotations() + /// ``` @JavaMethod public func getDeclaredAnnotations() -> [Annotation?] + /// Java method `getType`. + /// + /// ### Java method signature + /// ```java + /// public abstract java.lang.reflect.Type java.lang.reflect.AnnotatedType.getType() + /// ``` @JavaMethod public func getType() -> Type! + /// Java method `isAnnotationPresent`. + /// + /// ### Java method signature + /// ```java + /// public default boolean java.lang.reflect.AnnotatedElement.isAnnotationPresent(java.lang.Class) + /// ``` @JavaMethod public func isAnnotationPresent(_ arg0: JavaClass?) -> Bool + /// Java method `getAnnotationsByType`. + /// + /// ### Java method signature + /// ```java + /// public default T[] java.lang.reflect.AnnotatedElement.getAnnotationsByType(java.lang.Class) + /// ``` @JavaMethod - public func getAnnotationsByType(_ arg0: JavaClass?) -> [Annotation?] + public func getAnnotationsByType(_ arg0: JavaClass?) -> [T?] - @JavaMethod - public func getDeclaredAnnotation(_ arg0: JavaClass?) -> Annotation! + /// Java method `getDeclaredAnnotation`. + /// + /// ### Java method signature + /// ```java + /// public default T java.lang.reflect.AnnotatedElement.getDeclaredAnnotation(java.lang.Class) + /// ``` + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) + public func getDeclaredAnnotation(_ arg0: JavaClass?) -> T! + /// Java method `getDeclaredAnnotationsByType`. + /// + /// ### Java method signature + /// ```java + /// public default T[] java.lang.reflect.AnnotatedElement.getDeclaredAnnotationsByType(java.lang.Class) + /// ``` @JavaMethod - public func getDeclaredAnnotationsByType(_ arg0: JavaClass?) -> [Annotation?] + public func getDeclaredAnnotationsByType(_ arg0: JavaClass?) -> [T?] } diff --git a/Sources/JavaStdlib/JavaLangReflect/generated/Constructor.swift b/Sources/JavaStdlib/JavaLangReflect/generated/Constructor.swift index dbc61c894..e423e3b98 100644 --- a/Sources/JavaStdlib/JavaLangReflect/generated/Constructor.swift +++ b/Sources/JavaStdlib/JavaLangReflect/generated/Constructor.swift @@ -73,7 +73,7 @@ open class Constructor: Executable { /// ```java /// public T java.lang.reflect.Constructor.newInstance(java.lang.Object...) throws java.lang.InstantiationException,java.lang.IllegalAccessException,java.lang.IllegalArgumentException,java.lang.reflect.InvocationTargetException /// ``` - @JavaMethod(typeErasedResult: "T!") + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) open func newInstance(_ arg0: [JavaObject?]) throws -> T! /// Java method `getParameterTypes`. @@ -118,7 +118,7 @@ open class Constructor: Executable { /// ```java /// public T java.lang.reflect.Constructor.getAnnotation(java.lang.Class) /// ``` - @JavaMethod(typeErasedResult: "T!") + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) open override func getAnnotation(_ arg0: JavaClass?) -> T! /// Java method `getDeclaredAnnotations`. diff --git a/Sources/JavaStdlib/JavaLangReflect/generated/Executable.swift b/Sources/JavaStdlib/JavaLangReflect/generated/Executable.swift index ddbcd7f73..fa7ee379b 100644 --- a/Sources/JavaStdlib/JavaLangReflect/generated/Executable.swift +++ b/Sources/JavaStdlib/JavaLangReflect/generated/Executable.swift @@ -73,7 +73,7 @@ open class Executable: AccessibleObject { /// ```java /// public T java.lang.reflect.Executable.getAnnotation(java.lang.Class) /// ``` - @JavaMethod(typeErasedResult: "T!") + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) open override func getAnnotation(_ arg0: JavaClass?) -> T! /// Java method `getAnnotationsByType`. diff --git a/Sources/JavaStdlib/JavaLangReflect/generated/Field.swift b/Sources/JavaStdlib/JavaLangReflect/generated/Field.swift index be96bea64..75739f7b9 100644 --- a/Sources/JavaStdlib/JavaLangReflect/generated/Field.swift +++ b/Sources/JavaStdlib/JavaLangReflect/generated/Field.swift @@ -172,7 +172,7 @@ open class Field: AccessibleObject { /// ```java /// public T java.lang.reflect.Field.getAnnotation(java.lang.Class) /// ``` - @JavaMethod(typeErasedResult: "T!") + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) open override func getAnnotation(_ arg0: JavaClass?) -> T! /// Java method `getAnnotationsByType`. diff --git a/Sources/JavaStdlib/JavaLangReflect/generated/GenericDeclaration.swift b/Sources/JavaStdlib/JavaLangReflect/generated/GenericDeclaration.swift index 311904740..9290f29bf 100644 --- a/Sources/JavaStdlib/JavaLangReflect/generated/GenericDeclaration.swift +++ b/Sources/JavaStdlib/JavaLangReflect/generated/GenericDeclaration.swift @@ -4,27 +4,75 @@ import SwiftJavaJNICore @JavaInterface("java.lang.reflect.GenericDeclaration") public struct GenericDeclaration { + /// Java method `getTypeParameters`. + /// + /// ### Java method signature + /// ```java + /// public abstract java.lang.reflect.TypeVariable[] java.lang.reflect.GenericDeclaration.getTypeParameters() + /// ``` @JavaMethod public func getTypeParameters() -> [TypeVariable?] + /// Java method `isAnnotationPresent`. + /// + /// ### Java method signature + /// ```java + /// public default boolean java.lang.reflect.AnnotatedElement.isAnnotationPresent(java.lang.Class) + /// ``` @JavaMethod public func isAnnotationPresent(_ arg0: JavaClass?) -> Bool - @JavaMethod - public func getAnnotation(_ arg0: JavaClass?) -> Annotation! + /// Java method `getAnnotation`. + /// + /// ### Java method signature + /// ```java + /// public abstract T java.lang.reflect.AnnotatedElement.getAnnotation(java.lang.Class) + /// ``` + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) + public func getAnnotation(_ arg0: JavaClass?) -> T! + /// Java method `getAnnotationsByType`. + /// + /// ### Java method signature + /// ```java + /// public default T[] java.lang.reflect.AnnotatedElement.getAnnotationsByType(java.lang.Class) + /// ``` @JavaMethod - public func getAnnotationsByType(_ arg0: JavaClass?) -> [Annotation?] + public func getAnnotationsByType(_ arg0: JavaClass?) -> [T?] + /// Java method `getAnnotations`. + /// + /// ### Java method signature + /// ```java + /// public abstract java.lang.annotation.Annotation[] java.lang.reflect.AnnotatedElement.getAnnotations() + /// ``` @JavaMethod public func getAnnotations() -> [Annotation?] - @JavaMethod - public func getDeclaredAnnotation(_ arg0: JavaClass?) -> Annotation! + /// Java method `getDeclaredAnnotation`. + /// + /// ### Java method signature + /// ```java + /// public default T java.lang.reflect.AnnotatedElement.getDeclaredAnnotation(java.lang.Class) + /// ``` + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) + public func getDeclaredAnnotation(_ arg0: JavaClass?) -> T! + /// Java method `getDeclaredAnnotationsByType`. + /// + /// ### Java method signature + /// ```java + /// public default T[] java.lang.reflect.AnnotatedElement.getDeclaredAnnotationsByType(java.lang.Class) + /// ``` @JavaMethod - public func getDeclaredAnnotationsByType(_ arg0: JavaClass?) -> [Annotation?] + public func getDeclaredAnnotationsByType(_ arg0: JavaClass?) -> [T?] + /// Java method `getDeclaredAnnotations`. + /// + /// ### Java method signature + /// ```java + /// public abstract java.lang.annotation.Annotation[] java.lang.reflect.AnnotatedElement.getDeclaredAnnotations() + /// ``` @JavaMethod public func getDeclaredAnnotations() -> [Annotation?] } diff --git a/Sources/JavaStdlib/JavaLangReflect/generated/Method.swift b/Sources/JavaStdlib/JavaLangReflect/generated/Method.swift index d81e112c0..5881c1aa1 100644 --- a/Sources/JavaStdlib/JavaLangReflect/generated/Method.swift +++ b/Sources/JavaStdlib/JavaLangReflect/generated/Method.swift @@ -127,7 +127,7 @@ open class Method: Executable { /// ```java /// public T java.lang.reflect.Method.getAnnotation(java.lang.Class) /// ``` - @JavaMethod(typeErasedResult: "T!") + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) open override func getAnnotation(_ arg0: JavaClass?) -> T! /// Java method `getDeclaredAnnotations`. diff --git a/Sources/JavaStdlib/JavaLangReflect/generated/Parameter.swift b/Sources/JavaStdlib/JavaLangReflect/generated/Parameter.swift index cde76ce40..40abae3b4 100644 --- a/Sources/JavaStdlib/JavaLangReflect/generated/Parameter.swift +++ b/Sources/JavaStdlib/JavaLangReflect/generated/Parameter.swift @@ -1,64 +1,177 @@ // Auto-generated by Java-to-Swift wrapper generator. -import JavaUtil import SwiftJava import SwiftJavaJNICore @JavaClass("java.lang.reflect.Parameter") open class Parameter: JavaObject { + /// Java method `getName`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.String java.lang.reflect.Parameter.getName() + /// ``` @JavaMethod open func getName() -> String + /// Java method `equals`. + /// + /// ### Java method signature + /// ```java + /// public boolean java.lang.reflect.Parameter.equals(java.lang.Object) + /// ``` @JavaMethod open override func equals(_ arg0: JavaObject?) -> Bool + /// Java method `toString`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.String java.lang.reflect.Parameter.toString() + /// ``` @JavaMethod open override func toString() -> String + /// Java method `hashCode`. + /// + /// ### Java method signature + /// ```java + /// public int java.lang.reflect.Parameter.hashCode() + /// ``` @JavaMethod open override func hashCode() -> Int32 + /// Java method `getModifiers`. + /// + /// ### Java method signature + /// ```java + /// public int java.lang.reflect.Parameter.getModifiers() + /// ``` @JavaMethod open func getModifiers() -> Int32 + /// Java method `isSynthetic`. + /// + /// ### Java method signature + /// ```java + /// public boolean java.lang.reflect.Parameter.isSynthetic() + /// ``` @JavaMethod open func isSynthetic() -> Bool - @JavaMethod - open func getAnnotation(_ arg0: JavaClass?) -> Annotation! - - @JavaMethod - open func getAnnotationsByType(_ arg0: JavaClass?) -> [Annotation?] - + /// Java method `getAnnotation`. + /// + /// ### Java method signature + /// ```java + /// public T java.lang.reflect.Parameter.getAnnotation(java.lang.Class) + /// ``` + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) + open func getAnnotation(_ arg0: JavaClass?) -> T! + + /// Java method `getAnnotationsByType`. + /// + /// ### Java method signature + /// ```java + /// public T[] java.lang.reflect.Parameter.getAnnotationsByType(java.lang.Class) + /// ``` + @JavaMethod + open func getAnnotationsByType(_ arg0: JavaClass?) -> [T?] + + /// Java method `getAnnotations`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.annotation.Annotation[] java.lang.reflect.Parameter.getAnnotations() + /// ``` @JavaMethod open func getAnnotations() -> [Annotation?] - @JavaMethod - open func getDeclaredAnnotation(_ arg0: JavaClass?) -> Annotation! - - @JavaMethod - open func getDeclaredAnnotationsByType(_ arg0: JavaClass?) -> [Annotation?] - + /// Java method `getDeclaredAnnotation`. + /// + /// ### Java method signature + /// ```java + /// public T java.lang.reflect.Parameter.getDeclaredAnnotation(java.lang.Class) + /// ``` + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Annotation?.self) + open func getDeclaredAnnotation(_ arg0: JavaClass?) -> T! + + /// Java method `getDeclaredAnnotationsByType`. + /// + /// ### Java method signature + /// ```java + /// public T[] java.lang.reflect.Parameter.getDeclaredAnnotationsByType(java.lang.Class) + /// ``` + @JavaMethod + open func getDeclaredAnnotationsByType(_ arg0: JavaClass?) -> [T?] + + /// Java method `getDeclaredAnnotations`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.annotation.Annotation[] java.lang.reflect.Parameter.getDeclaredAnnotations() + /// ``` @JavaMethod open func getDeclaredAnnotations() -> [Annotation?] + /// Java method `getType`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.Class java.lang.reflect.Parameter.getType() + /// ``` @JavaMethod open func getType() -> JavaClass! + /// Java method `getAnnotatedType`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.AnnotatedType java.lang.reflect.Parameter.getAnnotatedType() + /// ``` @JavaMethod open func getAnnotatedType() -> AnnotatedType! + /// Java method `getParameterizedType`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Type java.lang.reflect.Parameter.getParameterizedType() + /// ``` @JavaMethod open func getParameterizedType() -> Type! + /// Java method `isVarArgs`. + /// + /// ### Java method signature + /// ```java + /// public boolean java.lang.reflect.Parameter.isVarArgs() + /// ``` @JavaMethod open func isVarArgs() -> Bool + /// Java method `getDeclaringExecutable`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Executable java.lang.reflect.Parameter.getDeclaringExecutable() + /// ``` @JavaMethod - open func isNamePresent() -> Bool + open func getDeclaringExecutable() -> Executable! + /// Java method `isNamePresent`. + /// + /// ### Java method signature + /// ```java + /// public boolean java.lang.reflect.Parameter.isNamePresent() + /// ``` @JavaMethod - open func getDeclaringExecutable() -> Executable! + open func isNamePresent() -> Bool + /// Java method `isImplicit`. + /// + /// ### Java method signature + /// ```java + /// public boolean java.lang.reflect.Parameter.isImplicit() + /// ``` @JavaMethod open func isImplicit() -> Bool } From f3f981a4627f18aae1f2ecc71f57f277fcdf37f3 Mon Sep 17 00:00:00 2001 From: Iceman Date: Tue, 17 Mar 2026 14:16:57 +0900 Subject: [PATCH 03/10] Fix some test case --- .../CompileJavaWrapTools.swift | 3 ++- Tests/SwiftJavaToolLibTests/Java2SwiftTests.swift | 4 ++-- .../WrapJavaTests/BasicWrapJavaTests.swift | 2 +- .../GenericsSubstitutionWrapJavaTests.swift | 8 ++++---- .../WrapJavaTests/GenericsWrapJavaTests.swift | 14 +++++++------- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Tests/SwiftJavaToolLibTests/CompileJavaWrapTools.swift b/Tests/SwiftJavaToolLibTests/CompileJavaWrapTools.swift index df21bc681..4ce8bb8e8 100644 --- a/Tests/SwiftJavaToolLibTests/CompileJavaWrapTools.swift +++ b/Tests/SwiftJavaToolLibTests/CompileJavaWrapTools.swift @@ -162,7 +162,8 @@ func assertWrapJavaOutput( "Expected chunk: \n" + "\(expectedChunk.yellow)" + "\n" + "not found in:\n" + "\(swiftCompleteOutputText)" XCTAssertTrue( checkAgainstText.contains(checkAgainstExpectedChunk), - "\(failureMessage)" + "\(failureMessage)", + file: file, line: line ) } } diff --git a/Tests/SwiftJavaToolLibTests/Java2SwiftTests.swift b/Tests/SwiftJavaToolLibTests/Java2SwiftTests.swift index d32c02e79..dc543ca95 100644 --- a/Tests/SwiftJavaToolLibTests/Java2SwiftTests.swift +++ b/Tests/SwiftJavaToolLibTests/Java2SwiftTests.swift @@ -270,7 +270,7 @@ class Java2SwiftTests: XCTestCase { public struct MyJavaObjects { """, """ - @JavaStaticMethod(typeErasedResult: "T!") + @JavaStaticMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) public func requireNonNull(_ arg0: T?, _ arg1: MySupplier?) -> T """, ] @@ -544,7 +544,7 @@ class Java2SwiftTests: XCTestCase { public struct MyJavaIntFunction { """, """ - @JavaMethod(typeErasedResult: "R!") + @JavaMethod(typeErasedResult: "R!", typeErasedResultBound: JavaObject?.self) public func apply(_ arg0: Int32) -> R! """, ] diff --git a/Tests/SwiftJavaToolLibTests/WrapJavaTests/BasicWrapJavaTests.swift b/Tests/SwiftJavaToolLibTests/WrapJavaTests/BasicWrapJavaTests.swift index 533a82748..a6167a7b2 100644 --- a/Tests/SwiftJavaToolLibTests/WrapJavaTests/BasicWrapJavaTests.swift +++ b/Tests/SwiftJavaToolLibTests/WrapJavaTests/BasicWrapJavaTests.swift @@ -272,7 +272,7 @@ final class BasicWrapJavaTests: XCTestCase { /// ```java /// public abstract ValueType com.example.CallMe.apply(ValueType,ValueType) /// ``` - @JavaMethod(typeErasedResult: "ValueType!") + @JavaMethod(typeErasedResult: "ValueType!", typeErasedResultBound: JavaObject?.self) public func apply(_ arg0: ValueType?, _ arg1: ValueType?) -> ValueType! } """ diff --git a/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsSubstitutionWrapJavaTests.swift b/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsSubstitutionWrapJavaTests.swift index 174ef4c66..399ff7e6e 100644 --- a/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsSubstitutionWrapJavaTests.swift +++ b/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsSubstitutionWrapJavaTests.swift @@ -48,7 +48,7 @@ final class GenericsSubstitutionWrapJavaTests: XCTestCase { public struct MyFunction { """, """ - @JavaMethod(typeErasedResult: "R!") + @JavaMethod(typeErasedResult: "R!", typeErasedResultBound: JavaObject?.self) public func apply(_ arg0: T?) -> R! """, """ @@ -56,7 +56,7 @@ final class GenericsSubstitutionWrapJavaTests: XCTestCase { public struct MyUnaryOperator { """, """ - @JavaMethod(typeErasedResult: "T!") + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) public func apply(_ arg0: T?) -> T! """, ] @@ -90,7 +90,7 @@ final class GenericsSubstitutionWrapJavaTests: XCTestCase { open class ClassFunction: JavaObject { """, """ - @JavaMethod(typeErasedResult: "R!") + @JavaMethod(typeErasedResult: "R!", typeErasedResultBound: JavaObject?.self) open func apply(_ arg0: T?) -> R! """, """ @@ -98,7 +98,7 @@ final class GenericsSubstitutionWrapJavaTests: XCTestCase { open class ClassUnaryOperator: ClassFunction { """, """ - @JavaMethod(typeErasedResult: "T!") + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) open override func apply(_ arg0: T?) -> T! """, ] diff --git a/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsWrapJavaTests.swift b/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsWrapJavaTests.swift index c64735e63..d65788666 100644 --- a/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsWrapJavaTests.swift +++ b/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsWrapJavaTests.swift @@ -63,7 +63,7 @@ final class GenericsWrapJavaTests: XCTestCase { open class ExampleSimpleClass: JavaObject { """, """ - @JavaMethod(typeErasedResult: "KeyType!") + @JavaMethod(typeErasedResult: "KeyType!", typeErasedResultBound: JavaObject?.self) open func getGeneric(_ arg0: Item?) -> KeyType! """, ] @@ -102,7 +102,7 @@ final class GenericsWrapJavaTests: XCTestCase { classpath: [classpathURL], expectedChunks: [ """ - @JavaMethod(typeErasedResult: "KeyType!") + @JavaMethod(typeErasedResult: "KeyType!", typeErasedResultBound: JavaObject?.self) open func getGeneric() -> KeyType! """ ] @@ -200,11 +200,11 @@ final class GenericsWrapJavaTests: XCTestCase { classpath: [classpathURL], expectedChunks: [ """ - @JavaMethod(typeErasedResult: "T!") + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) open func getClassGeneric() -> T! """, """ - @JavaMethod(typeErasedResult: "M!") + @JavaMethod(typeErasedResult: "M!", typeErasedResultBound: JavaObject?.self) open func getMethodGeneric() -> M! """, """ @@ -377,7 +377,7 @@ final class GenericsWrapJavaTests: XCTestCase { open class Kappa: JavaObject { """, """ - @JavaMethod(typeErasedResult: "T!") + @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) open func get() -> T! } """, @@ -416,7 +416,7 @@ final class GenericsWrapJavaTests: XCTestCase { public func ofNullable(_ arg0: T?) -> Optional! where ObjectType == Optional """, """ - @JavaStaticMethod(typeErasedResult: "T!") + @JavaStaticMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) public func nonNull(_ arg0: T?) -> T! where ObjectType == Optional """, ] @@ -489,7 +489,7 @@ final class GenericsWrapJavaTests: XCTestCase { open class Something: JavaObject { """, """ - @JavaMethod(typeErasedResult: "M!") + @JavaMethod(typeErasedResult: "M!", typeErasedResultBound: Map?.self) open func putIn(_ arg0: M?) -> M! """, ] From 31d268a1fc78a7a4c818b898b5855706b7e513a2 Mon Sep 17 00:00:00 2001 From: Iceman Date: Tue, 17 Mar 2026 15:21:51 +0900 Subject: [PATCH 04/10] Take care about bound type includes generic parameter --- .../SwiftJavaToolLib/JavaClassTranslator.swift | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Sources/SwiftJavaToolLib/JavaClassTranslator.swift b/Sources/SwiftJavaToolLib/JavaClassTranslator.swift index 284a72ac8..764e2c9c2 100644 --- a/Sources/SwiftJavaToolLib/JavaClassTranslator.swift +++ b/Sources/SwiftJavaToolLib/JavaClassTranslator.swift @@ -988,16 +988,23 @@ extension JavaClassTranslator { parameters.append("\"init\"") } if hasTypeEraseGenericResultType { - let boundType = try translator.getSwiftTypeNameAsString( + let returnType = javaMethod.getReturnType()! + var boundType = try translator.getSwiftTypeNameAsString( method: javaMethod, - javaMethod.getReturnType().as(Type.self), + returnType.as(Type.self), substitution: substitution, preferValueTypes: true, - outerOptional: .optional + outerOptional: .nonoptional ) - parameters.append(#"typeErasedResult: "\#(resultType)", typeErasedResultBound: \#(boundType).self"#) + // `getSwiftTypeNameAsString` does not includes generic parameters for non parameterized type + if let returnClass = returnType.as(JavaClass.self) { + let typeParameters = returnClass.getTypeParameters() + if !typeParameters.isEmpty { + boundType += "<\([String](repeating: "JavaObject", count: typeParameters.count).joined(separator: ", "))>" + } + } + parameters.append(#"typeErasedResult: "\#(resultType)", typeErasedResultBound: \#(boundType)?.self"#) } - // TODO: generic parameters? if !parameters.isEmpty { methodAttributeStr += "(" From bd9778df16bd3b3f8f26d7a32884b4ab697a6aaa Mon Sep 17 00:00:00 2001 From: Iceman Date: Tue, 17 Mar 2026 16:21:20 +0900 Subject: [PATCH 05/10] Update Sources/SwiftJavaToolLib/JavaClassTranslator.swift Co-authored-by: Konrad `ktoso` Malawski --- Sources/SwiftJavaToolLib/JavaClassTranslator.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftJavaToolLib/JavaClassTranslator.swift b/Sources/SwiftJavaToolLib/JavaClassTranslator.swift index 764e2c9c2..af50ca85e 100644 --- a/Sources/SwiftJavaToolLib/JavaClassTranslator.swift +++ b/Sources/SwiftJavaToolLib/JavaClassTranslator.swift @@ -996,7 +996,7 @@ extension JavaClassTranslator { preferValueTypes: true, outerOptional: .nonoptional ) - // `getSwiftTypeNameAsString` does not includes generic parameters for non parameterized type + // `getSwiftTypeNameAsString` does not include generic parameters for non parameterized type if let returnClass = returnType.as(JavaClass.self) { let typeParameters = returnClass.getTypeParameters() if !typeParameters.isEmpty { From cd8d27fefce10989ebca5332134b3a478a47a429 Mon Sep 17 00:00:00 2001 From: Iceman Date: Tue, 17 Mar 2026 16:21:29 +0900 Subject: [PATCH 06/10] swift format --- Tests/SwiftJavaToolLibTests/CompileJavaWrapTools.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/SwiftJavaToolLibTests/CompileJavaWrapTools.swift b/Tests/SwiftJavaToolLibTests/CompileJavaWrapTools.swift index 4ce8bb8e8..1fb48fc42 100644 --- a/Tests/SwiftJavaToolLibTests/CompileJavaWrapTools.swift +++ b/Tests/SwiftJavaToolLibTests/CompileJavaWrapTools.swift @@ -163,7 +163,8 @@ func assertWrapJavaOutput( XCTAssertTrue( checkAgainstText.contains(checkAgainstExpectedChunk), "\(failureMessage)", - file: file, line: line + file: file, + line: line ) } } From ea43861194d3d6fde600b92ab87a0393725da4d5 Mon Sep 17 00:00:00 2001 From: Iceman Date: Tue, 17 Mar 2026 16:36:39 +0900 Subject: [PATCH 07/10] single macro method definition --- Sources/SwiftJava/Macros.swift | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Sources/SwiftJava/Macros.swift b/Sources/SwiftJava/Macros.swift index 525638751..8dc1840c1 100644 --- a/Sources/SwiftJava/Macros.swift +++ b/Sources/SwiftJava/Macros.swift @@ -141,16 +141,10 @@ public macro JavaStaticField(_ javaFieldName: String? = nil, isFinal: Bool = fal /// This allows the macro to form a call into the get() method, which at runtime, will have an `java.lang.Object` /// returning method signature, and then, convert the result to the expected `T` type on the Swift side. @attached(body) -public macro JavaMethod( +public macro JavaMethod( _ javaMethodName: String? = nil, - typeErasedResult: String? = nil -) = #externalMacro(module: "SwiftJavaMacros", type: "JavaMethodMacro") - -@attached(body) -public macro JavaMethod( - _ javaMethodName: String? = nil, - typeErasedResult: String, - typeErasedResultBound: Result.Type, + typeErasedResult: String? = nil, + typeErasedResultBound: ResultBoundType.Type = JavaObject?.self ) = #externalMacro(module: "SwiftJavaMacros", type: "JavaMethodMacro") /// Attached macro that turns a Swift method on JavaClass into one that wraps From 8c048cda23cc5cce11dee01728c2e804dbf65a5f Mon Sep 17 00:00:00 2001 From: Iceman Date: Tue, 17 Mar 2026 16:46:43 +0900 Subject: [PATCH 08/10] Omit typeErasedResultBound parameter if it can --- .../generated/Constructor.swift | 2 +- .../JavaClassTranslator.swift | 29 ++++++++++--------- .../Java2SwiftTests.swift | 4 +-- .../WrapJavaTests/BasicWrapJavaTests.swift | 2 +- .../GenericsSubstitutionWrapJavaTests.swift | 8 ++--- .../WrapJavaTests/GenericsWrapJavaTests.swift | 12 ++++---- 6 files changed, 30 insertions(+), 27 deletions(-) diff --git a/Sources/JavaStdlib/JavaLangReflect/generated/Constructor.swift b/Sources/JavaStdlib/JavaLangReflect/generated/Constructor.swift index e423e3b98..501309e4a 100644 --- a/Sources/JavaStdlib/JavaLangReflect/generated/Constructor.swift +++ b/Sources/JavaStdlib/JavaLangReflect/generated/Constructor.swift @@ -73,7 +73,7 @@ open class Constructor: Executable { /// ```java /// public T java.lang.reflect.Constructor.newInstance(java.lang.Object...) throws java.lang.InstantiationException,java.lang.IllegalAccessException,java.lang.IllegalArgumentException,java.lang.reflect.InvocationTargetException /// ``` - @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) + @JavaMethod(typeErasedResult: "T!") open func newInstance(_ arg0: [JavaObject?]) throws -> T! /// Java method `getParameterTypes`. diff --git a/Sources/SwiftJavaToolLib/JavaClassTranslator.swift b/Sources/SwiftJavaToolLib/JavaClassTranslator.swift index af50ca85e..48cf33132 100644 --- a/Sources/SwiftJavaToolLib/JavaClassTranslator.swift +++ b/Sources/SwiftJavaToolLib/JavaClassTranslator.swift @@ -989,21 +989,24 @@ extension JavaClassTranslator { } if hasTypeEraseGenericResultType { let returnType = javaMethod.getReturnType()! - var boundType = try translator.getSwiftTypeNameAsString( - method: javaMethod, - returnType.as(Type.self), - substitution: substitution, - preferValueTypes: true, - outerOptional: .nonoptional - ) - // `getSwiftTypeNameAsString` does not include generic parameters for non parameterized type - if let returnClass = returnType.as(JavaClass.self) { - let typeParameters = returnClass.getTypeParameters() - if !typeParameters.isEmpty { - boundType += "<\([String](repeating: "JavaObject", count: typeParameters.count).joined(separator: ", "))>" + parameters.append(#"typeErasedResult: "\#(resultType)""#) + if returnType.getName() != "java.lang.Object" { + var boundType = try translator.getSwiftTypeNameAsString( + method: javaMethod, + returnType.as(Type.self), + substitution: substitution, + preferValueTypes: true, + outerOptional: .nonoptional + ) + // `getSwiftTypeNameAsString` does not include generic parameters for non parameterized type + if let returnClass = returnType.as(JavaClass.self) { + let typeParameters = returnClass.getTypeParameters() + if !typeParameters.isEmpty { + boundType += "<\([String](repeating: "JavaObject", count: typeParameters.count).joined(separator: ", "))>" + } } + parameters.append(#"typeErasedResultBound: \#(boundType)?.self"#) } - parameters.append(#"typeErasedResult: "\#(resultType)", typeErasedResultBound: \#(boundType)?.self"#) } if !parameters.isEmpty { diff --git a/Tests/SwiftJavaToolLibTests/Java2SwiftTests.swift b/Tests/SwiftJavaToolLibTests/Java2SwiftTests.swift index dc543ca95..d32c02e79 100644 --- a/Tests/SwiftJavaToolLibTests/Java2SwiftTests.swift +++ b/Tests/SwiftJavaToolLibTests/Java2SwiftTests.swift @@ -270,7 +270,7 @@ class Java2SwiftTests: XCTestCase { public struct MyJavaObjects { """, """ - @JavaStaticMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) + @JavaStaticMethod(typeErasedResult: "T!") public func requireNonNull(_ arg0: T?, _ arg1: MySupplier?) -> T """, ] @@ -544,7 +544,7 @@ class Java2SwiftTests: XCTestCase { public struct MyJavaIntFunction { """, """ - @JavaMethod(typeErasedResult: "R!", typeErasedResultBound: JavaObject?.self) + @JavaMethod(typeErasedResult: "R!") public func apply(_ arg0: Int32) -> R! """, ] diff --git a/Tests/SwiftJavaToolLibTests/WrapJavaTests/BasicWrapJavaTests.swift b/Tests/SwiftJavaToolLibTests/WrapJavaTests/BasicWrapJavaTests.swift index a6167a7b2..533a82748 100644 --- a/Tests/SwiftJavaToolLibTests/WrapJavaTests/BasicWrapJavaTests.swift +++ b/Tests/SwiftJavaToolLibTests/WrapJavaTests/BasicWrapJavaTests.swift @@ -272,7 +272,7 @@ final class BasicWrapJavaTests: XCTestCase { /// ```java /// public abstract ValueType com.example.CallMe.apply(ValueType,ValueType) /// ``` - @JavaMethod(typeErasedResult: "ValueType!", typeErasedResultBound: JavaObject?.self) + @JavaMethod(typeErasedResult: "ValueType!") public func apply(_ arg0: ValueType?, _ arg1: ValueType?) -> ValueType! } """ diff --git a/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsSubstitutionWrapJavaTests.swift b/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsSubstitutionWrapJavaTests.swift index 399ff7e6e..174ef4c66 100644 --- a/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsSubstitutionWrapJavaTests.swift +++ b/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsSubstitutionWrapJavaTests.swift @@ -48,7 +48,7 @@ final class GenericsSubstitutionWrapJavaTests: XCTestCase { public struct MyFunction { """, """ - @JavaMethod(typeErasedResult: "R!", typeErasedResultBound: JavaObject?.self) + @JavaMethod(typeErasedResult: "R!") public func apply(_ arg0: T?) -> R! """, """ @@ -56,7 +56,7 @@ final class GenericsSubstitutionWrapJavaTests: XCTestCase { public struct MyUnaryOperator { """, """ - @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) + @JavaMethod(typeErasedResult: "T!") public func apply(_ arg0: T?) -> T! """, ] @@ -90,7 +90,7 @@ final class GenericsSubstitutionWrapJavaTests: XCTestCase { open class ClassFunction: JavaObject { """, """ - @JavaMethod(typeErasedResult: "R!", typeErasedResultBound: JavaObject?.self) + @JavaMethod(typeErasedResult: "R!") open func apply(_ arg0: T?) -> R! """, """ @@ -98,7 +98,7 @@ final class GenericsSubstitutionWrapJavaTests: XCTestCase { open class ClassUnaryOperator: ClassFunction { """, """ - @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) + @JavaMethod(typeErasedResult: "T!") open override func apply(_ arg0: T?) -> T! """, ] diff --git a/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsWrapJavaTests.swift b/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsWrapJavaTests.swift index d65788666..af36ab6fb 100644 --- a/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsWrapJavaTests.swift +++ b/Tests/SwiftJavaToolLibTests/WrapJavaTests/GenericsWrapJavaTests.swift @@ -63,7 +63,7 @@ final class GenericsWrapJavaTests: XCTestCase { open class ExampleSimpleClass: JavaObject { """, """ - @JavaMethod(typeErasedResult: "KeyType!", typeErasedResultBound: JavaObject?.self) + @JavaMethod(typeErasedResult: "KeyType!") open func getGeneric(_ arg0: Item?) -> KeyType! """, ] @@ -102,7 +102,7 @@ final class GenericsWrapJavaTests: XCTestCase { classpath: [classpathURL], expectedChunks: [ """ - @JavaMethod(typeErasedResult: "KeyType!", typeErasedResultBound: JavaObject?.self) + @JavaMethod(typeErasedResult: "KeyType!") open func getGeneric() -> KeyType! """ ] @@ -200,11 +200,11 @@ final class GenericsWrapJavaTests: XCTestCase { classpath: [classpathURL], expectedChunks: [ """ - @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) + @JavaMethod(typeErasedResult: "T!") open func getClassGeneric() -> T! """, """ - @JavaMethod(typeErasedResult: "M!", typeErasedResultBound: JavaObject?.self) + @JavaMethod(typeErasedResult: "M!") open func getMethodGeneric() -> M! """, """ @@ -377,7 +377,7 @@ final class GenericsWrapJavaTests: XCTestCase { open class Kappa: JavaObject { """, """ - @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) + @JavaMethod(typeErasedResult: "T!") open func get() -> T! } """, @@ -416,7 +416,7 @@ final class GenericsWrapJavaTests: XCTestCase { public func ofNullable(_ arg0: T?) -> Optional! where ObjectType == Optional """, """ - @JavaStaticMethod(typeErasedResult: "T!", typeErasedResultBound: JavaObject?.self) + @JavaStaticMethod(typeErasedResult: "T!") public func nonNull(_ arg0: T?) -> T! where ObjectType == Optional """, ] From 50c3206e4ada043e66fc15ac19596dc79154e3da Mon Sep 17 00:00:00 2001 From: Iceman Date: Tue, 17 Mar 2026 16:57:13 +0900 Subject: [PATCH 09/10] Add document for `typeErasedResultBound` param --- Sources/SwiftJava/Macros.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Sources/SwiftJava/Macros.swift b/Sources/SwiftJava/Macros.swift index 8dc1840c1..97aebc001 100644 --- a/Sources/SwiftJava/Macros.swift +++ b/Sources/SwiftJava/Macros.swift @@ -134,12 +134,19 @@ public macro JavaStaticField(_ javaFieldName: String? = nil, isFinal: Bool = fal /// /// In order to mark a generic return type you must indicate it to the @JavaMethod macro like this: /// ```swift -/// // Java: class Test { public get(); } +/// // Java: class Test { public T get(); } /// @JavaMethod(typeErasedResult: "T!") /// func get() -> T! /// ``` /// This allows the macro to form a call into the get() method, which at runtime, will have an `java.lang.Object` /// returning method signature, and then, convert the result to the expected `T` type on the Swift side. +/// +/// If the return type is a wildcard type, specify the bound type instead of `java.lang.Object`: +/// ```swift +/// // Java: class Test { public T get(); } +/// @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Animal?.self) +/// func get() -> T! +/// ``` @attached(body) public macro JavaMethod( _ javaMethodName: String? = nil, From 234a3be7f44349b62a08475f11b7d1cd0ec84a92 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Tue, 17 Mar 2026 17:29:36 +0900 Subject: [PATCH 10/10] Apply suggestion from @ktoso --- Sources/SwiftJava/Macros.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftJava/Macros.swift b/Sources/SwiftJava/Macros.swift index 97aebc001..7c384425b 100644 --- a/Sources/SwiftJava/Macros.swift +++ b/Sources/SwiftJava/Macros.swift @@ -141,7 +141,7 @@ public macro JavaStaticField(_ javaFieldName: String? = nil, isFinal: Bool = fal /// This allows the macro to form a call into the get() method, which at runtime, will have an `java.lang.Object` /// returning method signature, and then, convert the result to the expected `T` type on the Swift side. /// -/// If the return type is a wildcard type, specify the bound type instead of `java.lang.Object`: +/// If the return type is a bounded type parameter, specify the bound type instead of `java.lang.Object`: /// ```swift /// // Java: class Test { public T get(); } /// @JavaMethod(typeErasedResult: "T!", typeErasedResultBound: Animal?.self)