diff --git a/Package.swift b/Package.swift index 14cc44f25..dc511d658 100644 --- a/Package.swift +++ b/Package.swift @@ -216,7 +216,7 @@ let package = Package( ), .target( name: "JavaUtilFunction", - dependencies: ["SwiftJava"], + dependencies: ["SwiftJava", "JavaUtil"], path: "Sources/JavaStdlib/JavaUtilFunction", exclude: ["swift-java.config"], swiftSettings: [ diff --git a/Sources/JavaStdlib/JavaLangReflect/JavaClass+Reflection.swift b/Sources/JavaStdlib/JavaLangReflect/JavaClass+Reflection.swift index 11061f85d..0ce7401ac 100644 --- a/Sources/JavaStdlib/JavaLangReflect/JavaClass+Reflection.swift +++ b/Sources/JavaStdlib/JavaLangReflect/JavaClass+Reflection.swift @@ -14,42 +14,7 @@ import SwiftJava -// TODO: We should be able to autogenerate this as an extension based on -// knowing that JavaClass was defined elsewhere. extension JavaClass { - @JavaMethod - public func getDeclaredMethods() -> [Method?] - - @JavaMethod - public func getMethods() -> [Method?] - - @JavaMethod - public func getDeclaredMethod( - _ name: String, - _ parameterTypes: [JavaClass?] - ) throws -> Method? - - @JavaMethod - public func getFields() -> [Field?] - - @JavaMethod - public func getGenericInterfaces() -> [Type?] - - @JavaMethod - public func getGenericSuperclass() -> Type! - - @JavaMethod - public func getConstructors() -> [Constructor?] - - @JavaMethod - public func getParameters() -> [Parameter?] - - @JavaMethod - public func getTypeParameters() -> [TypeVariable>?] - - @JavaMethod - public func getAnnotations() -> [Annotation?] - public func `as`(_: Type.Type) -> Type { Type(javaHolder: javaHolder) } diff --git a/Sources/JavaStdlib/JavaLangReflect/generated/JavaClass+Extensions.swift b/Sources/JavaStdlib/JavaLangReflect/generated/JavaClass+Extensions.swift new file mode 100644 index 000000000..66631446d --- /dev/null +++ b/Sources/JavaStdlib/JavaLangReflect/generated/JavaClass+Extensions.swift @@ -0,0 +1,230 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension JavaClass { + /// Java method `getAnnotatedInterfaces`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.AnnotatedType[] java.lang.Class.getAnnotatedInterfaces() + /// ``` + @JavaMethod + public func getAnnotatedInterfaces() -> [AnnotatedType?] + + /// Java method `getAnnotatedSuperclass`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.AnnotatedType java.lang.Class.getAnnotatedSuperclass() + /// ``` + @JavaMethod + public func getAnnotatedSuperclass() -> AnnotatedType! + + /// Java method `getAnnotation`. + /// + /// ### Java method signature + /// ```java + /// public A java.lang.Class.getAnnotation(java.lang.Class) + /// ``` + @JavaMethod(typeErasedResult: "A!", typeErasedResultBound: Annotation?.self) + public func getAnnotation(_ arg0: JavaClass?) -> A! + + /// Java method `getAnnotations`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.annotation.Annotation[] java.lang.Class.getAnnotations() + /// ``` + @JavaMethod + public func getAnnotations() -> [Annotation?] + + /// Java method `getAnnotationsByType`. + /// + /// ### Java method signature + /// ```java + /// public A[] java.lang.Class.getAnnotationsByType(java.lang.Class) + /// ``` + @JavaMethod + public func getAnnotationsByType(_ arg0: JavaClass?) -> [A?] + + /// Java method `getConstructor`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Constructor java.lang.Class.getConstructor(java.lang.Class...) throws java.lang.NoSuchMethodException + /// ``` + @JavaMethod + public func getConstructor(_ arg0: [JavaClass?]) throws -> Constructor! + + /// Java method `getConstructors`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Constructor[] java.lang.Class.getConstructors() + /// ``` + @JavaMethod + public func getConstructors() -> [Constructor?] + + /// Java method `getDeclaredAnnotation`. + /// + /// ### Java method signature + /// ```java + /// public A java.lang.Class.getDeclaredAnnotation(java.lang.Class) + /// ``` + @JavaMethod(typeErasedResult: "A!", typeErasedResultBound: Annotation?.self) + public func getDeclaredAnnotation(_ arg0: JavaClass?) -> A! + + /// Java method `getDeclaredAnnotations`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.annotation.Annotation[] java.lang.Class.getDeclaredAnnotations() + /// ``` + @JavaMethod + public func getDeclaredAnnotations() -> [Annotation?] + + /// Java method `getDeclaredAnnotationsByType`. + /// + /// ### Java method signature + /// ```java + /// public A[] java.lang.Class.getDeclaredAnnotationsByType(java.lang.Class) + /// ``` + @JavaMethod + public func getDeclaredAnnotationsByType(_ arg0: JavaClass?) -> [A?] + + /// Java method `getDeclaredConstructor`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Constructor java.lang.Class.getDeclaredConstructor(java.lang.Class...) throws java.lang.NoSuchMethodException + /// ``` + @JavaMethod + public func getDeclaredConstructor(_ arg0: [JavaClass?]) throws -> Constructor! + + /// Java method `getDeclaredConstructors`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Constructor[] java.lang.Class.getDeclaredConstructors() + /// ``` + @JavaMethod + public func getDeclaredConstructors() -> [Constructor?] + + /// Java method `getDeclaredField`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String) throws java.lang.NoSuchFieldException + /// ``` + @JavaMethod + public func getDeclaredField(_ arg0: String) throws -> Field! + + /// Java method `getDeclaredFields`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Field[] java.lang.Class.getDeclaredFields() + /// ``` + @JavaMethod + public func getDeclaredFields() -> [Field?] + + /// Java method `getDeclaredMethod`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Method java.lang.Class.getDeclaredMethod(java.lang.String,java.lang.Class...) throws java.lang.NoSuchMethodException + /// ``` + @JavaMethod + public func getDeclaredMethod(_ arg0: String, _ arg1: [JavaClass?]) throws -> Method! + + /// Java method `getDeclaredMethods`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Method[] java.lang.Class.getDeclaredMethods() + /// ``` + @JavaMethod + public func getDeclaredMethods() -> [Method?] + + /// Java method `getEnclosingConstructor`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Constructor java.lang.Class.getEnclosingConstructor() + /// ``` + @JavaMethod + public func getEnclosingConstructor() -> Constructor! + + /// Java method `getEnclosingMethod`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Method java.lang.Class.getEnclosingMethod() + /// ``` + @JavaMethod + public func getEnclosingMethod() -> Method! + + /// Java method `getField`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Field java.lang.Class.getField(java.lang.String) throws java.lang.NoSuchFieldException + /// ``` + @JavaMethod + public func getField(_ arg0: String) throws -> Field! + + /// Java method `getFields`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Field[] java.lang.Class.getFields() + /// ``` + @JavaMethod + public func getFields() -> [Field?] + + /// Java method `getGenericInterfaces`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Type[] java.lang.Class.getGenericInterfaces() + /// ``` + @JavaMethod + public func getGenericInterfaces() -> [Type?] + + /// Java method `getGenericSuperclass`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Type java.lang.Class.getGenericSuperclass() + /// ``` + @JavaMethod + public func getGenericSuperclass() -> Type! + + /// Java method `getMethod`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Method java.lang.Class.getMethod(java.lang.String,java.lang.Class...) throws java.lang.NoSuchMethodException + /// ``` + @JavaMethod + public func getMethod(_ arg0: String, _ arg1: [JavaClass?]) throws -> Method! + + /// Java method `getMethods`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.Method[] java.lang.Class.getMethods() + /// ``` + @JavaMethod + public func getMethods() -> [Method?] + + /// Java method `getTypeParameters`. + /// + /// ### Java method signature + /// ```java + /// public java.lang.reflect.TypeVariable>[] java.lang.Class.getTypeParameters() + /// ``` + @JavaMethod + public func getTypeParameters() -> [TypeVariable>?] +} diff --git a/Sources/JavaStdlib/JavaLangReflect/swift-java.config b/Sources/JavaStdlib/JavaLangReflect/swift-java.config index b4d96403d..14e6b721f 100644 --- a/Sources/JavaStdlib/JavaLangReflect/swift-java.config +++ b/Sources/JavaStdlib/JavaLangReflect/swift-java.config @@ -1,4 +1,5 @@ { + "extendClasses" : ["java.lang.Class"], "classes" : { "java.lang.annotation.Annotation" : "Annotation", "java.lang.reflect.AccessibleObject" : "AccessibleObject", diff --git a/Sources/JavaStdlib/JavaNet/JavaURL+Extensions.swift b/Sources/JavaStdlib/JavaNet/JavaURL+URIConversions.swift similarity index 93% rename from Sources/JavaStdlib/JavaNet/JavaURL+Extensions.swift rename to Sources/JavaStdlib/JavaNet/JavaURL+URIConversions.swift index 0336e7a95..c51be38fc 100644 --- a/Sources/JavaStdlib/JavaNet/JavaURL+Extensions.swift +++ b/Sources/JavaStdlib/JavaNet/JavaURL+URIConversions.swift @@ -21,11 +21,6 @@ import FoundationEssentials import Foundation #endif -extension JavaURL { - @JavaMethod - public func toURI() throws -> URI! -} - extension URL { public static func fromJava(_ url: JavaURL) throws -> URL { guard let converted = URL(string: try url.toURI().toString()) else { diff --git a/Sources/JavaStdlib/JavaNet/generated/File+Extensions.swift b/Sources/JavaStdlib/JavaNet/generated/File+Extensions.swift new file mode 100644 index 000000000..5f71c6473 --- /dev/null +++ b/Sources/JavaStdlib/JavaNet/generated/File+Extensions.swift @@ -0,0 +1,17 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension File { + @JavaMethod + @_nonoverride public convenience init(_ arg0: URI?, environment: JNIEnvironment? = nil) + + /// Java method `toURI`. + /// + /// ### Java method signature + /// ```java + /// public java.net.URI java.io.File.toURI() + /// ``` + @JavaMethod + public func toURI() -> URI! +} diff --git a/Sources/JavaStdlib/JavaNet/generated/JavaURL+Extensions.swift b/Sources/JavaStdlib/JavaNet/generated/JavaURL+Extensions.swift new file mode 100644 index 000000000..84935c714 --- /dev/null +++ b/Sources/JavaStdlib/JavaNet/generated/JavaURL+Extensions.swift @@ -0,0 +1,23 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension JavaURL { + /// Java method `openConnection`. + /// + /// ### Java method signature + /// ```java + /// public java.net.URLConnection java.net.URL.openConnection() throws java.io.IOException + /// ``` + @JavaMethod + public func openConnection() throws -> URLConnection! + + /// Java method `toURI`. + /// + /// ### Java method signature + /// ```java + /// public java.net.URI java.net.URL.toURI() throws java.net.URISyntaxException + /// ``` + @JavaMethod + public func toURI() throws -> URI! +} diff --git a/Sources/JavaStdlib/JavaNet/generated/Path+Extensions.swift b/Sources/JavaStdlib/JavaNet/generated/Path+Extensions.swift new file mode 100644 index 000000000..0fbb384df --- /dev/null +++ b/Sources/JavaStdlib/JavaNet/generated/Path+Extensions.swift @@ -0,0 +1,24 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension JavaClass { + /// Java method `of`. + /// + /// ### Java method signature + /// ```java + /// public static java.nio.file.Path java.nio.file.Path.of(java.net.URI) + /// ``` + @JavaStaticMethod + public func of(_ arg0: URI?) -> Path! +} +extension Path { + /// Java method `toUri`. + /// + /// ### Java method signature + /// ```java + /// public abstract java.net.URI java.nio.file.Path.toUri() + /// ``` + @JavaMethod + public func toUri() -> URI! +} diff --git a/Sources/JavaStdlib/JavaNet/swift-java.config b/Sources/JavaStdlib/JavaNet/swift-java.config index f939deb2c..d38967ab0 100644 --- a/Sources/JavaStdlib/JavaNet/swift-java.config +++ b/Sources/JavaStdlib/JavaNet/swift-java.config @@ -1,4 +1,5 @@ { + "extendClasses" : ["java.net.URL", "java.io.File", "java.nio.file.Path"], "classes" : { "java.net.URI" : "URI", "java.net.URLClassLoader" : "URLClassLoader", diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/ArrayDeque+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/ArrayDeque+Extensions.swift new file mode 100644 index 000000000..0a9d19f1e --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/ArrayDeque+Extensions.swift @@ -0,0 +1,24 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import JavaUtil +import SwiftJava +import SwiftJavaJNICore + +extension ArrayDeque { + /// Java method `forEach`. + /// + /// ### Java method signature + /// ```java + /// public void java.util.ArrayDeque.forEach(java.util.function.Consumer) + /// ``` + @JavaMethod + public func forEach(_ arg0: JavaConsumer?) + + /// Java method `removeIf`. + /// + /// ### Java method signature + /// ```java + /// public boolean java.util.ArrayDeque.removeIf(java.util.function.Predicate) + /// ``` + @JavaMethod + public func removeIf(_ arg0: JavaPredicate?) -> Bool +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/ArrayList+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/ArrayList+Extensions.swift new file mode 100644 index 000000000..e6da0629b --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/ArrayList+Extensions.swift @@ -0,0 +1,33 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import JavaUtil +import SwiftJava +import SwiftJavaJNICore + +extension ArrayList { + /// Java method `forEach`. + /// + /// ### Java method signature + /// ```java + /// public void java.util.ArrayList.forEach(java.util.function.Consumer) + /// ``` + @JavaMethod + public func forEach(_ arg0: JavaConsumer?) + + /// Java method `removeIf`. + /// + /// ### Java method signature + /// ```java + /// public boolean java.util.ArrayList.removeIf(java.util.function.Predicate) + /// ``` + @JavaMethod + public func removeIf(_ arg0: JavaPredicate?) -> Bool + + /// Java method `replaceAll`. + /// + /// ### Java method signature + /// ```java + /// public void java.util.ArrayList.replaceAll(java.util.function.UnaryOperator) + /// ``` + @JavaMethod + public func replaceAll(_ arg0: JavaUnaryOperator?) +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/HashMap+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/HashMap+Extensions.swift new file mode 100644 index 000000000..a1718838b --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/HashMap+Extensions.swift @@ -0,0 +1,60 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import JavaUtil +import SwiftJava +import SwiftJavaJNICore + +extension HashMap { + /// Java method `compute`. + /// + /// ### Java method signature + /// ```java + /// public V java.util.HashMap.compute(K,java.util.function.BiFunction) + /// ``` + @JavaMethod(typeErasedResult: "V!") + public func compute(_ arg0: K?, _ arg1: JavaBiFunction?) -> V! + + /// Java method `computeIfAbsent`. + /// + /// ### Java method signature + /// ```java + /// public V java.util.HashMap.computeIfAbsent(K,java.util.function.Function) + /// ``` + @JavaMethod(typeErasedResult: "V!") + public func computeIfAbsent(_ arg0: K?, _ arg1: JavaFunction?) -> V! + + /// Java method `computeIfPresent`. + /// + /// ### Java method signature + /// ```java + /// public V java.util.HashMap.computeIfPresent(K,java.util.function.BiFunction) + /// ``` + @JavaMethod(typeErasedResult: "V!") + public func computeIfPresent(_ arg0: K?, _ arg1: JavaBiFunction?) -> V! + + /// Java method `forEach`. + /// + /// ### Java method signature + /// ```java + /// public void java.util.HashMap.forEach(java.util.function.BiConsumer) + /// ``` + @JavaMethod + public func forEach(_ arg0: JavaBiConsumer?) + + /// Java method `merge`. + /// + /// ### Java method signature + /// ```java + /// public V java.util.HashMap.merge(K,V,java.util.function.BiFunction) + /// ``` + @JavaMethod(typeErasedResult: "V!") + public func merge(_ arg0: K?, _ arg1: V?, _ arg2: JavaBiFunction?) -> V! + + /// Java method `replaceAll`. + /// + /// ### Java method signature + /// ```java + /// public void java.util.HashMap.replaceAll(java.util.function.BiFunction) + /// ``` + @JavaMethod + public func replaceAll(_ arg0: JavaBiFunction?) +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/JavaCollection+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaCollection+Extensions.swift new file mode 100644 index 000000000..76576bd09 --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaCollection+Extensions.swift @@ -0,0 +1,32 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension JavaCollection { + /// Java method `forEach`. + /// + /// ### Java method signature + /// ```java + /// public default void java.lang.Iterable.forEach(java.util.function.Consumer) + /// ``` + @JavaMethod + public func forEach(_ arg0: JavaConsumer?) + + /// Java method `removeIf`. + /// + /// ### Java method signature + /// ```java + /// public default boolean java.util.Collection.removeIf(java.util.function.Predicate) + /// ``` + @JavaMethod + public func removeIf(_ arg0: JavaPredicate?) -> Bool + + /// Java method `toArray`. + /// + /// ### Java method signature + /// ```java + /// public default T[] java.util.Collection.toArray(java.util.function.IntFunction) + /// ``` + @JavaMethod + public func toArray(_ arg0: JavaIntFunction?) -> [T?] +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/JavaIterator+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaIterator+Extensions.swift new file mode 100644 index 000000000..71780c547 --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaIterator+Extensions.swift @@ -0,0 +1,14 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension JavaIterator { + /// Java method `forEachRemaining`. + /// + /// ### Java method signature + /// ```java + /// public default void java.util.Iterator.forEachRemaining(java.util.function.Consumer) + /// ``` + @JavaMethod + public func forEachRemaining(_ arg0: JavaConsumer?) +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/JavaMap+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaMap+Extensions.swift new file mode 100644 index 000000000..b2432a67e --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaMap+Extensions.swift @@ -0,0 +1,59 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension JavaMap { + /// Java method `compute`. + /// + /// ### Java method signature + /// ```java + /// public default V java.util.Map.compute(K,java.util.function.BiFunction) + /// ``` + @JavaMethod(typeErasedResult: "V!") + public func compute(_ arg0: K?, _ arg1: JavaBiFunction?) -> V! + + /// Java method `computeIfAbsent`. + /// + /// ### Java method signature + /// ```java + /// public default V java.util.Map.computeIfAbsent(K,java.util.function.Function) + /// ``` + @JavaMethod(typeErasedResult: "V!") + public func computeIfAbsent(_ arg0: K?, _ arg1: JavaFunction?) -> V! + + /// Java method `computeIfPresent`. + /// + /// ### Java method signature + /// ```java + /// public default V java.util.Map.computeIfPresent(K,java.util.function.BiFunction) + /// ``` + @JavaMethod(typeErasedResult: "V!") + public func computeIfPresent(_ arg0: K?, _ arg1: JavaBiFunction?) -> V! + + /// Java method `forEach`. + /// + /// ### Java method signature + /// ```java + /// public default void java.util.Map.forEach(java.util.function.BiConsumer) + /// ``` + @JavaMethod + public func forEach(_ arg0: JavaBiConsumer?) + + /// Java method `merge`. + /// + /// ### Java method signature + /// ```java + /// public default V java.util.Map.merge(K,V,java.util.function.BiFunction) + /// ``` + @JavaMethod(typeErasedResult: "V!") + public func merge(_ arg0: K?, _ arg1: V?, _ arg2: JavaBiFunction?) -> V! + + /// Java method `replaceAll`. + /// + /// ### Java method signature + /// ```java + /// public default void java.util.Map.replaceAll(java.util.function.BiFunction) + /// ``` + @JavaMethod + public func replaceAll(_ arg0: JavaBiFunction?) +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/JavaOptional+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaOptional+Extensions.swift new file mode 100644 index 000000000..adde97ee3 --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaOptional+Extensions.swift @@ -0,0 +1,84 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension JavaOptional { + /// Java method `filter`. + /// + /// ### Java method signature + /// ```java + /// public java.util.Optional java.util.Optional.filter(java.util.function.Predicate) + /// ``` + @JavaMethod + public func filter(_ arg0: JavaPredicate?) -> JavaOptional! + + public func filterOptional(_ arg0: JavaPredicate?) -> T? { + Optional(javaOptional: filter(arg0)) + } + + /// Java method `flatMap`. + /// + /// ### Java method signature + /// ```java + /// public java.util.Optional java.util.Optional.flatMap(java.util.function.Function>) + /// ``` + @JavaMethod + public func flatMap(_ arg0: JavaFunction>?) -> JavaOptional! + + public func flatMapOptional(_ arg0: JavaFunction>?) -> U? { + Optional(javaOptional: flatMap(arg0)) + } + + /// Java method `ifPresent`. + /// + /// ### Java method signature + /// ```java + /// public void java.util.Optional.ifPresent(java.util.function.Consumer) + /// ``` + @JavaMethod + public func ifPresent(_ arg0: JavaConsumer?) + + /// Java method `map`. + /// + /// ### Java method signature + /// ```java + /// public java.util.Optional java.util.Optional.map(java.util.function.Function) + /// ``` + @JavaMethod + public func map(_ arg0: JavaFunction?) -> JavaOptional! + + public func mapOptional(_ arg0: JavaFunction?) -> U? { + Optional(javaOptional: map(arg0)) + } + + /// Java method `or`. + /// + /// ### Java method signature + /// ```java + /// public java.util.Optional java.util.Optional.or(java.util.function.Supplier>) + /// ``` + @JavaMethod + public func or(_ arg0: JavaSupplier>?) -> JavaOptional! + + public func orOptional(_ arg0: JavaSupplier>?) -> T? { + Optional(javaOptional: or(arg0)) + } + + /// Java method `orElseGet`. + /// + /// ### Java method signature + /// ```java + /// public T java.util.Optional.orElseGet(java.util.function.Supplier) + /// ``` + @JavaMethod(typeErasedResult: "T!") + public func orElseGet(_ arg0: JavaSupplier?) -> T! + + /// Java method `orElseThrow`. + /// + /// ### Java method signature + /// ```java + /// public T java.util.Optional.orElseThrow(java.util.function.Supplier) throws X + /// ``` + @JavaMethod(typeErasedResult: "T!") + public func orElseThrow(_ arg0: JavaSupplier?) throws -> T! +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/JavaOptionalDouble+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaOptionalDouble+Extensions.swift new file mode 100644 index 000000000..ed24a1f4f --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaOptionalDouble+Extensions.swift @@ -0,0 +1,32 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension JavaOptionalDouble { + /// Java method `ifPresent`. + /// + /// ### Java method signature + /// ```java + /// public void java.util.OptionalDouble.ifPresent(java.util.function.DoubleConsumer) + /// ``` + @JavaMethod + public func ifPresent(_ arg0: JavaDoubleConsumer?) + + /// Java method `orElseGet`. + /// + /// ### Java method signature + /// ```java + /// public double java.util.OptionalDouble.orElseGet(java.util.function.DoubleSupplier) + /// ``` + @JavaMethod + public func orElseGet(_ arg0: JavaDoubleSupplier?) -> Double + + /// Java method `orElseThrow`. + /// + /// ### Java method signature + /// ```java + /// public double java.util.OptionalDouble.orElseThrow(java.util.function.Supplier) throws X + /// ``` + @JavaMethod + public func orElseThrow(_ arg0: JavaSupplier?) throws -> Double +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/JavaOptionalInt+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaOptionalInt+Extensions.swift new file mode 100644 index 000000000..53c4958b8 --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaOptionalInt+Extensions.swift @@ -0,0 +1,32 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension JavaOptionalInt { + /// Java method `ifPresent`. + /// + /// ### Java method signature + /// ```java + /// public void java.util.OptionalInt.ifPresent(java.util.function.IntConsumer) + /// ``` + @JavaMethod + public func ifPresent(_ arg0: JavaIntConsumer?) + + /// Java method `orElseGet`. + /// + /// ### Java method signature + /// ```java + /// public int java.util.OptionalInt.orElseGet(java.util.function.IntSupplier) + /// ``` + @JavaMethod + public func orElseGet(_ arg0: JavaIntSupplier?) -> Int32 + + /// Java method `orElseThrow`. + /// + /// ### Java method signature + /// ```java + /// public int java.util.OptionalInt.orElseThrow(java.util.function.Supplier) throws X + /// ``` + @JavaMethod + public func orElseThrow(_ arg0: JavaSupplier?) throws -> Int32 +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/JavaOptionalLong+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaOptionalLong+Extensions.swift new file mode 100644 index 000000000..f40b3cf2b --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaOptionalLong+Extensions.swift @@ -0,0 +1,32 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension JavaOptionalLong { + /// Java method `ifPresent`. + /// + /// ### Java method signature + /// ```java + /// public void java.util.OptionalLong.ifPresent(java.util.function.LongConsumer) + /// ``` + @JavaMethod + public func ifPresent(_ arg0: JavaLongConsumer?) + + /// Java method `orElseGet`. + /// + /// ### Java method signature + /// ```java + /// public long java.util.OptionalLong.orElseGet(java.util.function.LongSupplier) + /// ``` + @JavaMethod + public func orElseGet(_ arg0: JavaLongSupplier?) -> Int64 + + /// Java method `orElseThrow`. + /// + /// ### Java method signature + /// ```java + /// public long java.util.OptionalLong.orElseThrow(java.util.function.Supplier) throws X + /// ``` + @JavaMethod + public func orElseThrow(_ arg0: JavaSupplier?) throws -> Int64 +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/JavaSet+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaSet+Extensions.swift new file mode 100644 index 000000000..6924f7ac3 --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaSet+Extensions.swift @@ -0,0 +1,32 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension JavaSet { + /// Java method `forEach`. + /// + /// ### Java method signature + /// ```java + /// public default void java.lang.Iterable.forEach(java.util.function.Consumer) + /// ``` + @JavaMethod + public func forEach(_ arg0: JavaConsumer?) + + /// Java method `removeIf`. + /// + /// ### Java method signature + /// ```java + /// public default boolean java.util.Collection.removeIf(java.util.function.Predicate) + /// ``` + @JavaMethod + public func removeIf(_ arg0: JavaPredicate?) -> Bool + + /// Java method `toArray`. + /// + /// ### Java method signature + /// ```java + /// public default T[] java.util.Collection.toArray(java.util.function.IntFunction) + /// ``` + @JavaMethod + public func toArray(_ arg0: JavaIntFunction?) -> [T?] +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/JavaString+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaString+Extensions.swift new file mode 100644 index 000000000..64be878f9 --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/JavaString+Extensions.swift @@ -0,0 +1,14 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension JavaString { + /// Java method `transform`. + /// + /// ### Java method signature + /// ```java + /// public R java.lang.String.transform(java.util.function.Function) + /// ``` + @JavaMethod(typeErasedResult: "R!") + public func transform(_ arg0: JavaFunction?) -> R! +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/List+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/List+Extensions.swift new file mode 100644 index 000000000..1ceed981a --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/List+Extensions.swift @@ -0,0 +1,41 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension List { + /// Java method `forEach`. + /// + /// ### Java method signature + /// ```java + /// public default void java.lang.Iterable.forEach(java.util.function.Consumer) + /// ``` + @JavaMethod + public func forEach(_ arg0: JavaConsumer?) + + /// Java method `removeIf`. + /// + /// ### Java method signature + /// ```java + /// public default boolean java.util.Collection.removeIf(java.util.function.Predicate) + /// ``` + @JavaMethod + public func removeIf(_ arg0: JavaPredicate?) -> Bool + + /// Java method `replaceAll`. + /// + /// ### Java method signature + /// ```java + /// public default void java.util.List.replaceAll(java.util.function.UnaryOperator) + /// ``` + @JavaMethod + public func replaceAll(_ arg0: JavaUnaryOperator?) + + /// Java method `toArray`. + /// + /// ### Java method signature + /// ```java + /// public default T[] java.util.Collection.toArray(java.util.function.IntFunction) + /// ``` + @JavaMethod + public func toArray(_ arg0: JavaIntFunction?) -> [T?] +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/ListIterator+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/ListIterator+Extensions.swift new file mode 100644 index 000000000..be05f57e9 --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/ListIterator+Extensions.swift @@ -0,0 +1,14 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension ListIterator { + /// Java method `forEachRemaining`. + /// + /// ### Java method signature + /// ```java + /// public default void java.util.Iterator.forEachRemaining(java.util.function.Consumer) + /// ``` + @JavaMethod + public func forEachRemaining(_ arg0: JavaConsumer?) +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/Path+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/Path+Extensions.swift new file mode 100644 index 000000000..23b505ad4 --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/Path+Extensions.swift @@ -0,0 +1,14 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import SwiftJava +import SwiftJavaJNICore + +extension Path { + /// Java method `forEach`. + /// + /// ### Java method signature + /// ```java + /// public default void java.lang.Iterable.forEach(java.util.function.Consumer) + /// ``` + @JavaMethod + public func forEach(_ arg0: JavaConsumer?) +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/PriorityQueue+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/PriorityQueue+Extensions.swift new file mode 100644 index 000000000..62543bc76 --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/PriorityQueue+Extensions.swift @@ -0,0 +1,24 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import JavaUtil +import SwiftJava +import SwiftJavaJNICore + +extension PriorityQueue { + /// Java method `forEach`. + /// + /// ### Java method signature + /// ```java + /// public void java.util.PriorityQueue.forEach(java.util.function.Consumer) + /// ``` + @JavaMethod + public func forEach(_ arg0: JavaConsumer?) + + /// Java method `removeIf`. + /// + /// ### Java method signature + /// ```java + /// public boolean java.util.PriorityQueue.removeIf(java.util.function.Predicate) + /// ``` + @JavaMethod + public func removeIf(_ arg0: JavaPredicate?) -> Bool +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/Queue+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/Queue+Extensions.swift new file mode 100644 index 000000000..ac4fba40f --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/Queue+Extensions.swift @@ -0,0 +1,33 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import JavaUtil +import SwiftJava +import SwiftJavaJNICore + +extension Queue { + /// Java method `forEach`. + /// + /// ### Java method signature + /// ```java + /// public default void java.lang.Iterable.forEach(java.util.function.Consumer) + /// ``` + @JavaMethod + public func forEach(_ arg0: JavaConsumer?) + + /// Java method `removeIf`. + /// + /// ### Java method signature + /// ```java + /// public default boolean java.util.Collection.removeIf(java.util.function.Predicate) + /// ``` + @JavaMethod + public func removeIf(_ arg0: JavaPredicate?) -> Bool + + /// Java method `toArray`. + /// + /// ### Java method signature + /// ```java + /// public default T[] java.util.Collection.toArray(java.util.function.IntFunction) + /// ``` + @JavaMethod + public func toArray(_ arg0: JavaIntFunction?) -> [T?] +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/generated/TreeMap+Extensions.swift b/Sources/JavaStdlib/JavaUtilFunction/generated/TreeMap+Extensions.swift new file mode 100644 index 000000000..8c4e5a1d9 --- /dev/null +++ b/Sources/JavaStdlib/JavaUtilFunction/generated/TreeMap+Extensions.swift @@ -0,0 +1,60 @@ +// Auto-generated by Java-to-Swift wrapper generator. +import JavaUtil +import SwiftJava +import SwiftJavaJNICore + +extension TreeMap { + /// Java method `compute`. + /// + /// ### Java method signature + /// ```java + /// public V java.util.TreeMap.compute(K,java.util.function.BiFunction) + /// ``` + @JavaMethod(typeErasedResult: "V!") + public func compute(_ arg0: K?, _ arg1: JavaBiFunction?) -> V! + + /// Java method `computeIfAbsent`. + /// + /// ### Java method signature + /// ```java + /// public V java.util.TreeMap.computeIfAbsent(K,java.util.function.Function) + /// ``` + @JavaMethod(typeErasedResult: "V!") + public func computeIfAbsent(_ arg0: K?, _ arg1: JavaFunction?) -> V! + + /// Java method `computeIfPresent`. + /// + /// ### Java method signature + /// ```java + /// public V java.util.TreeMap.computeIfPresent(K,java.util.function.BiFunction) + /// ``` + @JavaMethod(typeErasedResult: "V!") + public func computeIfPresent(_ arg0: K?, _ arg1: JavaBiFunction?) -> V! + + /// Java method `forEach`. + /// + /// ### Java method signature + /// ```java + /// public void java.util.TreeMap.forEach(java.util.function.BiConsumer) + /// ``` + @JavaMethod + public func forEach(_ arg0: JavaBiConsumer?) + + /// Java method `merge`. + /// + /// ### Java method signature + /// ```java + /// public V java.util.TreeMap.merge(K,V,java.util.function.BiFunction) + /// ``` + @JavaMethod(typeErasedResult: "V!") + public func merge(_ arg0: K?, _ arg1: V?, _ arg2: JavaBiFunction?) -> V! + + /// Java method `replaceAll`. + /// + /// ### Java method signature + /// ```java + /// public void java.util.TreeMap.replaceAll(java.util.function.BiFunction) + /// ``` + @JavaMethod + public func replaceAll(_ arg0: JavaBiFunction?) +} diff --git a/Sources/JavaStdlib/JavaUtilFunction/swift-java.config b/Sources/JavaStdlib/JavaUtilFunction/swift-java.config index 4aa1fd9b1..0ad997101 100644 --- a/Sources/JavaStdlib/JavaUtilFunction/swift-java.config +++ b/Sources/JavaStdlib/JavaUtilFunction/swift-java.config @@ -1,4 +1,24 @@ { + "extendClasses" : [ + "java.util.Optional", + "java.util.OptionalInt", + "java.util.OptionalLong", + "java.util.OptionalDouble", + "java.lang.String", + "java.util.Collection", + "java.util.List", + "java.util.Set", + "java.util.Map", + "java.util.Iterator", + "java.util.ListIterator", + "java.nio.file.Path", + "java.util.ArrayList", + "java.util.HashMap", + "java.util.TreeMap", + "java.util.Queue", + "java.util.PriorityQueue", + "java.util.ArrayDeque" + ], "classes" : { "java.util.function.BiConsumer" : "JavaBiConsumer", "java.util.function.BiFunction" : "JavaBiFunction", diff --git a/Sources/SwiftJavaConfigurationShared/Configuration.swift b/Sources/SwiftJavaConfigurationShared/Configuration.swift index 50d4a6f13..3016f2dd5 100644 --- a/Sources/SwiftJavaConfigurationShared/Configuration.swift +++ b/Sources/SwiftJavaConfigurationShared/Configuration.swift @@ -28,6 +28,8 @@ import Foundation public typealias JavaVersion = Int +public typealias JavaFullyQualifiedTypeName = String + /// Configuration for the SwiftJava tools and plugins, provided on a per-target basis. public struct Configuration: Codable { @@ -219,6 +221,11 @@ public struct Configuration: Codable { /// the corresponding Swift names (e.g., JavaVector). public var classes: [String: String]? = [:] + /// Java classes whose Swift wrapper type is owned by another module, but which + /// this module should generate an extension of. + + public var extendClasses: [JavaFullyQualifiedTypeName]? = nil + // Compile for the specified Java SE release. public var sourceCompatibility: JavaVersion? diff --git a/Sources/SwiftJavaMacros/JavaMethodMacro.swift b/Sources/SwiftJavaMacros/JavaMethodMacro.swift index a28e58a55..feced4475 100644 --- a/Sources/SwiftJavaMacros/JavaMethodMacro.swift +++ b/Sources/SwiftJavaMacros/JavaMethodMacro.swift @@ -261,7 +261,9 @@ extension JavaMethodMacro: BodyMacro { ? "try" : "try!" let objectCreation: [CodeBlockItemSyntax] - if context.lexicalContext.first?.is(ClassDeclSyntax.self) ?? false { + if (context.lexicalContext.first?.is(ClassDeclSyntax.self) ?? false) + || initDecl.modifiers.contains(where: { $0.name.tokenKind == .keyword(.convenience) }) + { objectCreation = [ "let javaThis = \(raw: tryKeyword) Self.dynamicJavaNewObjectInstance(in: _environment\(raw: arguments))\n", "self.init(javaThis: javaThis, environment: _environment)\n", diff --git a/Sources/SwiftJavaTool/Commands/WrapJavaCommand.swift b/Sources/SwiftJavaTool/Commands/WrapJavaCommand.swift index cda9a445d..f6236bc91 100644 --- a/Sources/SwiftJavaTool/Commands/WrapJavaCommand.swift +++ b/Sources/SwiftJavaTool/Commands/WrapJavaCommand.swift @@ -19,6 +19,7 @@ import Logging import SwiftJava import SwiftJavaConfigurationShared import SwiftJavaToolLib +import SwiftSyntax extension SwiftJava { @@ -307,19 +308,11 @@ extension SwiftJava.WrapJavaCommand { let swiftClassDecls = try javaClasses.flatMap { try translator.translateClass($0) } - let importDecls = translator.getImportDecls() - - let swiftFileText = """ - // Auto-generated by Java-to-Swift wrapper generator. - \(importDecls.map { $0.description }.joined()) - \(swiftClassDecls.map { $0.description }.joined(separator: "\n")) - - """ - - try writeContents( - swiftFileText, + try writeGeneratedSwiftFile( + decls: swiftClassDecls, + translator: translator, outputDirectory: self.actualOutputDirectory, - to: singleSwiftFileOutput, + fileName: singleSwiftFileOutput, description: "Java class translation" ) } else { @@ -327,14 +320,6 @@ extension SwiftJava.WrapJavaCommand { translator.startNewFile() let swiftClassDecls = try translator.translateClass(javaClass) - let importDecls = translator.getImportDecls() - - let swiftFileText = """ - // Auto-generated by Java-to-Swift wrapper generator. - \(importDecls.map { $0.description }.joined()) - \(swiftClassDecls.map { $0.description }.joined(separator: "\n")) - - """ var generatedFileOutputDir = self.actualOutputDirectory if self.swiftMatchPackageDirectoryStructure { @@ -344,14 +329,85 @@ extension SwiftJava.WrapJavaCommand { let swiftFileName = try translator.getSwiftTypeName(javaClass, preferValueTypes: false) .swiftName.replacing(".", with: "+") + ".swift" - try writeContents( - swiftFileText, + try writeGeneratedSwiftFile( + decls: swiftClassDecls, + translator: translator, outputDirectory: generatedFileOutputDir, - to: swiftFileName, + fileName: swiftFileName, description: "Java class '\(javaClass.getName())' translation" ) } } + + //Generate extensions of wrapper types that are owned by a module other than + //the one being currently generated. + for extendedClassName in config.extendClasses ?? [] { + try writeCrossModuleExtension( + of: extendedClassName, + translator: translator, + classLoader: classLoader + ) + } + } + + private mutating func writeCrossModuleExtension( + of extendedClassName: JavaFullyQualifiedTypeName, + translator: JavaTranslator, + classLoader: ClassLoader + ) throws { + guard let owner = translator.translatedClasses[extendedClassName] else { + log.warning("Cannot extend class '\(extendedClassName)': not known to any module.") + return + } + guard let ownerModule = owner.swiftModule, ownerModule != effectiveSwiftModule else { + log.warning("Cannot extend class '\(extendedClassName)': it is owned by this module ('\(effectiveSwiftModule)').") + return + } + guard let extendedClass = try classLoader.loadClass(extendedClassName) else { + log.warning("Could not load Java class '\(extendedClassName)', skipping extension.") + return + } + + translator.startNewFile() + let extensionDecls = try translator.translateClassAsCrossModuleExtension(extendedClass) + guard !extensionDecls.isEmpty else { + log.info("No members to add in extension of class '\(extendedClassName)'; skipping.") + return + } + + let swiftFileName = + try translator.getSwiftTypeName(extendedClass, preferValueTypes: false) + .swiftName.replacing(".", with: "+") + "+Extensions.swift" + try writeGeneratedSwiftFile( + decls: extensionDecls, + translator: translator, + outputDirectory: self.actualOutputDirectory, + fileName: swiftFileName, + description: "Java class '\(extendedClassName)' extension" + ) + } + + private mutating func writeGeneratedSwiftFile( + decls: [DeclSyntax], + translator: JavaTranslator, + outputDirectory: Foundation.URL?, + fileName: String, + description: String + ) throws { + let importDecls = translator.getImportDecls() + let swiftFileText = """ + // Auto-generated by Java-to-Swift wrapper generator. + \(importDecls.map { $0.description }.joined()) + \(decls.map { $0.description }.joined(separator: "\n")) + + """ + + try writeContents( + swiftFileText, + outputDirectory: outputDirectory, + to: fileName, + description: description + ) } /// Determines whether a method should be extracted for translation. diff --git a/Sources/SwiftJavaToolLib/JavaClassTranslator.swift b/Sources/SwiftJavaToolLib/JavaClassTranslator.swift index bbb796da7..125def18b 100644 --- a/Sources/SwiftJavaToolLib/JavaClassTranslator.swift +++ b/Sources/SwiftJavaToolLib/JavaClassTranslator.swift @@ -559,7 +559,7 @@ extension JavaClassTranslator { /// Render the extension of JavaClass that collects all of the static /// fields and methods. - package func renderStaticMemberExtension() -> DeclSyntax? { + package func renderStaticMemberExtension(asCrossModuleExtension: Bool = false) -> DeclSyntax? { // Determine the where clause we need for static methods. let staticMemberWhereClause: String if !javaTypeParameters.isEmpty { @@ -574,8 +574,11 @@ extension JavaClassTranslator { } // Render static fields. - let properties = staticFields.sortedForEmission().compactMap { field in + let properties = staticFields.sortedForEmission().compactMap { field -> DeclSyntax? in // Translate each static field. + guard !asCrossModuleExtension || referencesCurrentModule(field) else { + return nil + } do { return try renderField(field) } catch { @@ -585,8 +588,11 @@ extension JavaClassTranslator { } // Render static methods. - let methods = staticMethods.methods.sortedForEmission().compactMap { method in + let methods = staticMethods.methods.sortedForEmission().compactMap { method -> DeclSyntax? in // Translate each static method. + guard !asCrossModuleExtension || referencesCurrentModule(method) else { + return nil + } do { return try renderMethod( method, @@ -628,6 +634,87 @@ extension JavaClassTranslator { return extDecl.formatted(using: translator.format).cast(DeclSyntax.self) } + private func owningModule(of javaClass: JavaClass?) -> String? { + guard var javaClass else { return nil } + while javaClass.isArray() { + guard let component = javaClass.getComponentType() else { break } + javaClass = component + } + return translator.translatedClasses[javaClass.getName()]?.swiftModule + } + + /// Whether this method references at least one Java type whose Swift wrapper + /// is owned by the module currently being generated. + private func referencesCurrentModule(_ types: [JavaClass?]) -> Bool { + types.contains { owningModule(of: $0) == translator.swiftModuleName } + } + private func referencesCurrentModule(_ method: Method) -> Bool { + referencesCurrentModule([method.getReturnType()] + method.getParameterTypes()) + } + private func referencesCurrentModule(_ constructor: Constructor) -> Bool { + referencesCurrentModule(constructor.getParameterTypes()) + } + private func referencesCurrentModule(_ field: Field) -> Bool { + referencesCurrentModule([field.getType()]) + } + + package func renderCrossModuleExtension() -> [DeclSyntax] { + guard let extendedSwiftName: String = translator.translatedClasses[javaClass.getName()]?.swiftType else { + return [] + } + + var decls: [DeclSyntax] = [] + if let staticExtension = renderStaticMemberExtension(asCrossModuleExtension: true) { + decls.append(staticExtension) + } + if let instanceExtension = renderCrossModuleInstanceExtension(of: extendedSwiftName) { + decls.append(instanceExtension) + } + return decls + } + + private func renderCrossModuleInstanceExtension(of extendedSwiftName: String) -> DeclSyntax? { + let initializers: [DeclSyntax] = constructors.sortedForEmission().compactMap { constructor -> DeclSyntax? in + guard referencesCurrentModule(constructor) else { + return nil + } + do { + return try renderConstructor(constructor) + } catch { + translator.logUntranslated("Unable to translate '\(javaClass.getName())' constructor: \(error)") + return nil + } + } + + let renderedMethods: [DeclSyntax] = methods.methods.sortedForEmission().compactMap { method -> DeclSyntax? in + guard referencesCurrentModule(method) else { + return nil + } + do { + return try renderMethod(method, implementedInSwift: false, asCrossModuleExtensionMember: true) + } catch { + translator.logUntranslated( + "Unable to translate '\(javaClass.getName())' method '\(method.getName())': \(error)" + ) + return nil + } + } + + let members = initializers + renderedMethods + if members.isEmpty { + return nil + } + + let extDecl: DeclSyntax = + """ + extension \(raw: extendedSwiftName) { + \(raw: members.map { $0.description }.joined(separator: "\n\n")) + } + """ + + return extDecl.formatted(using: translator.format).cast(DeclSyntax.self) + } + /// Render the protocol used for native methods. func renderNativeMethodsProtocol() -> DeclSyntax? { guard translator.swiftNativeImplementations.contains(javaClass.getName()) else { @@ -866,6 +953,18 @@ extension JavaClassTranslator { """ } + private func typeReferencesTypeParam(_ type: Type?, _ typeParam: TypeVariable) -> Bool { + guard let type else { return false } + if type.isEqualTo(typeParam.as(Type.self)) { + return true + } + if let wildcard = type.as(WildcardType.self) { + return wildcard.getUpperBounds().contains { $0.map { typeParam.as(Type.self).isEqualTo($0) } ?? false } + || wildcard.getLowerBounds().contains { $0.map { typeParam.as(Type.self).isEqualTo($0) } ?? false } + } + return false + } + func genericParameterIsUsedInSignature(_ typeParam: TypeVariable, in method: Method) -> Bool { // --- Return type // Is the return type exactly the type param @@ -876,8 +975,7 @@ extension JavaClassTranslator { if let parameterizedReturnType = method.getGenericReturnType().as(ParameterizedType.self) { for actualTypeParam in parameterizedReturnType.getActualTypeArguments() { - guard let actualTypeParam else { continue } - if actualTypeParam.isEqualTo(typeParam.as(Type.self)) { + if typeReferencesTypeParam(actualTypeParam, typeParam) { return true } } @@ -899,8 +997,7 @@ extension JavaClassTranslator { // Also check if the type param is used as a type argument inside a parameterized parameter type if let parameterizedParamType = parameterizedType.as(ParameterizedType.self) { for actualTypeParam in parameterizedParamType.getActualTypeArguments() { - guard let actualTypeParam else { continue } - if actualTypeParam.isEqualTo(typeParam.as(Type.self)) { + if typeReferencesTypeParam(actualTypeParam, typeParam) { return true } } @@ -943,7 +1040,8 @@ extension JavaClassTranslator { _ javaMethod: Method, implementedInSwift: Bool, genericParameters: [String] = [], - whereClause: String = "" + whereClause: String = "", + asCrossModuleExtensionMember: Bool = false ) throws -> DeclSyntax { // Map the generic params on the method. let allGenericParameters = collectMethodGenericParameters(genericParameters: genericParameters, method: javaMethod) @@ -1053,11 +1151,11 @@ extension JavaClassTranslator { let accessModifier = implementedInSwift ? "" - : (javaMethod.isStatic || !translateAsClass) + : (asCrossModuleExtensionMember || javaMethod.isStatic || !translateAsClass) ? "public " : "open " let overrideOpt = - (translateAsClass && !javaMethod.isStatic && isOverride(javaMethod)) + (!asCrossModuleExtensionMember && translateAsClass && !javaMethod.isStatic && isOverride(javaMethod)) ? "override " : "" diff --git a/Sources/SwiftJavaToolLib/JavaTranslator+Validation.swift b/Sources/SwiftJavaToolLib/JavaTranslator+Validation.swift index 397c4f82c..234a92ef8 100644 --- a/Sources/SwiftJavaToolLib/JavaTranslator+Validation.swift +++ b/Sources/SwiftJavaToolLib/JavaTranslator+Validation.swift @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -public typealias JavaFullyQualifiedTypeName = String +import SwiftJavaConfigurationShared package struct SwiftTypeName: Hashable, CustomStringConvertible { package let swiftModule: String? diff --git a/Sources/SwiftJavaToolLib/JavaTranslator.swift b/Sources/SwiftJavaToolLib/JavaTranslator.swift index 354d37cf5..c6b68eab2 100644 --- a/Sources/SwiftJavaToolLib/JavaTranslator.swift +++ b/Sources/SwiftJavaToolLib/JavaTranslator.swift @@ -380,6 +380,10 @@ extension JavaTranslator { package func translateClass(_ javaClass: JavaClass) throws -> [DeclSyntax] { try JavaClassTranslator(javaClass: javaClass, translator: self).render() } + + package func translateClassAsCrossModuleExtension(_ javaClass: JavaClass) throws -> [DeclSyntax] { + try JavaClassTranslator(javaClass: javaClass, translator: self).renderCrossModuleExtension() + } } extension String { diff --git a/Tests/SwiftJavaMacrosTests/JavaClassMacroTests.swift b/Tests/SwiftJavaMacrosTests/JavaClassMacroTests.swift index dad2b2db6..da7921182 100644 --- a/Tests/SwiftJavaMacrosTests/JavaClassMacroTests.swift +++ b/Tests/SwiftJavaMacrosTests/JavaClassMacroTests.swift @@ -29,6 +29,32 @@ class JavaKitMacroTests: XCTestCase { "JavaStaticField": JavaFieldMacro.self, ] + func testJavaClassConvenienceInitializerInExtension() throws { + assertMacroExpansion( + """ + extension HelloWorld { + @JavaMethod + @_nonoverride public convenience init(_ value: Int32, environment: JNIEnvironment? = nil) + } + """, + expandedSource: """ + + extension HelloWorld { + @_nonoverride public convenience init(_ value: Int32, environment: JNIEnvironment? = nil) { + let _environment = if let environment { + environment + } else { + try! JavaVirtualMachine.shared().environment() + } + let javaThis = try! Self.dynamicJavaNewObjectInstance(in: _environment, arguments: value.self) + self.init(javaThis: javaThis, environment: _environment) + } + } + """, + macros: Self.javaKitMacros + ) + } + func testJavaStaticMethodFailure() throws { assertMacroExpansion( """ diff --git a/Tests/SwiftJavaToolLibTests/WrapJavaTests/CrossModuleExtensionWrapJavaTests.swift b/Tests/SwiftJavaToolLibTests/WrapJavaTests/CrossModuleExtensionWrapJavaTests.swift new file mode 100644 index 000000000..43f39801a --- /dev/null +++ b/Tests/SwiftJavaToolLibTests/WrapJavaTests/CrossModuleExtensionWrapJavaTests.swift @@ -0,0 +1,251 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +import Foundation +import JavaNet +@_spi(Testing) import SwiftJava +import SwiftJavaConfigurationShared +import SwiftJavaShared +import XCTest + +@testable import SwiftJavaToolLib + +final class CrossModuleExtensionWrapJavaTests: XCTestCase { + + + func test_wrapJava_generatesCrossModuleExtensionOfJavaClass() async throws { + let classpathURL = try await compileJava("class Foo {}") + + let jvm = try JavaVirtualMachine.shared(replace: false) + let environment = try jvm.environment() + + var config = Configuration() + config.minimumInputAccessLevelMode = .package + + let currentModule = "JavaLangReflect" + let translator = JavaTranslator( + config: config, + swiftModuleName: currentModule, + environment: environment, + translateAsClass: true + ) + + translator.translatedClasses["java.lang.Class"] = .init(module: "SwiftJava", name: "JavaClass") + translator.translatedClasses["java.lang.String"] = .init(module: "SwiftJava", name: "String") + translator.translatedClasses["java.lang.reflect.Method"] = .init(module: currentModule, name: "Method") + translator.translatedClasses["java.lang.reflect.Field"] = .init(module: currentModule, name: "Field") + + translator.startNewFile() + + let classLoader = URLClassLoader( + [try! URI("\(classpathURL)/").toURL()], + environment: environment + ) + let loaded = try classLoader.loadClass("java.lang.Class") + let javaLangClass = try XCTUnwrap(loaded, "Could not load java.lang.Class") + + let decls = try translator.translateClassAsCrossModuleExtension(javaLangClass) + let output = decls.map { $0.description }.joined(separator: "\n") + let compact = output.replacing(" ", with: "") + + XCTAssertTrue( + compact.contains("extensionJavaClass{"), + "Expected an `extension JavaClass { ... }`, got:\n\(output)" + ) + + XCTAssertTrue( + compact.contains("getDeclaredMethods()->[Method?]") + || compact.contains("getDeclaredMethods()throws->[Method?]"), + "Expected `getDeclaredMethods()` returning [Method?], got:\n\(output)" + ) + XCTAssertTrue( + compact.contains("getFields()->[Field?]") + || compact.contains("getFields()throws->[Field?]"), + "Expected `getFields()` returning [Field?], got:\n\(output)" + ) + XCTAssertFalse( + compact.contains("openfuncgetDeclaredMethods"), + "Extension members must not be `open`:\n\(output)" + ) + XCTAssertFalse( + compact.contains("funcgetName("), + "Did not expect getName() (references only String, a type owned by another module):\n\(output)" + ) + } + + + func test_wrapJava_crossModuleExtensionOnlyIncludesCurrentModuleMembers() async throws { + let classpathURL = try await compileJava( + """ + package com.example; + + class Color {} + + class Palette { + public Color primary() { return null; } + public Color[] all() { return null; } + public String describe() { return ""; } + public Palette copy() { return null; } + } + """ + ) + + let jvm = try JavaVirtualMachine.shared(replace: false) + let environment = try jvm.environment() + + var config = Configuration() + config.minimumInputAccessLevelMode = .package + + let currentModule = "MyColors" + let translator = JavaTranslator( + config: config, + swiftModuleName: currentModule, + environment: environment, + translateAsClass: true + ) + + translator.translatedClasses["com.example.Palette"] = .init(module: "Upstream", name: "Palette") + translator.translatedClasses["com.example.Color"] = .init(module: currentModule, name: "Color") + translator.translatedClasses["java.lang.String"] = .init(module: "SwiftJava", name: "String") + + translator.startNewFile() + + let classLoader = URLClassLoader( + [try! URI("\(classpathURL)/").toURL()], + environment: environment + ) + let palette = try XCTUnwrap(try classLoader.loadClass("com.example.Palette")) + + let decls = try translator.translateClassAsCrossModuleExtension(palette) + let output = decls.map { $0.description }.joined(separator: "\n") + let compact = output.replacing(" ", with: "") + + XCTAssertTrue( + compact.contains("extensionPalette{"), + "Expected an `extension Palette { ... }`, got:\n\(output)" + ) + XCTAssertTrue( + compact.contains("primary()->Color!"), + "Expected `primary() -> Color!`, got:\n\(output)" + ) + XCTAssertTrue( + compact.contains("all()->[Color?]"), + "Expected `all() -> [Color?]`, got:\n\(output)" + ) + XCTAssertFalse( + compact.contains("funcdescribe("), + "Did not expect describe() (returns only String, a type owned by another module):\n\(output)" + ) + XCTAssertFalse( + compact.contains("funccopy("), + "Did not expect copy() (returns only Palette, a type owned by another module):\n\(output)" + ) + } + + func test_wrapJava_crossModuleExtensionIncludesConstructorsAndStaticMembers() async throws { + let classpathURL = try await compileJava( + """ + package com.example; + + class Color {} + + class Palette { + public static final Color DEFAULT = null; + public static final String NAME = ""; + + public Palette(Color seed) {} + public Palette(String name) {} + + public static Color mix(Color a, Color b) { return null; } + public static String describe() { return ""; } + } + """ + ) + + let jvm = try JavaVirtualMachine.shared(replace: false) + let environment = try jvm.environment() + + var config = Configuration() + config.minimumInputAccessLevelMode = .package + + let currentModule = "MyColors" + let translator = JavaTranslator( + config: config, + swiftModuleName: currentModule, + environment: environment, + translateAsClass: true + ) + + translator.translatedClasses["com.example.Palette"] = .init(module: "Upstream", name: "Palette") + translator.translatedClasses["com.example.Color"] = .init(module: currentModule, name: "Color") + translator.translatedClasses["java.lang.String"] = .init(module: "SwiftJava", name: "String") + + translator.startNewFile() + + let classLoader = URLClassLoader( + [try! URI("\(classpathURL)/").toURL()], + environment: environment + ) + let palette = try XCTUnwrap(try classLoader.loadClass("com.example.Palette")) + + let decls = try translator.translateClassAsCrossModuleExtension(palette) + let all = decls.map { $0.description }.joined(separator: "\n") + + XCTAssertEqual(decls.count, 2, "Expected a static and an instance extension, got:\n\(all)") + + let staticExtension = try XCTUnwrap( + decls.first { $0.description.replacing(" ", with: "").contains("extensionJavaClass{") }, + "Expected an `extension JavaClass { ... }`, got:\n\(all)" + ).description.replacing(" ", with: "") + + let instanceExtension = try XCTUnwrap( + decls.first { $0.description.replacing(" ", with: "").contains("extensionPalette{") }, + "Expected an `extension Palette { ... }`, got:\n\(all)" + ).description.replacing(" ", with: "") + + XCTAssertTrue( + instanceExtension.contains("convenienceinit(_arg0:Color?"), + "Expected a convenience init taking Color:\n\(all)" + ) + XCTAssertFalse( + instanceExtension.contains("init(_arg0:String"), + "Did not expect the String constructor:\n\(all)" + ) + XCTAssertTrue( + staticExtension.contains("funcmix("), + "Expected static mix(Color, Color) on JavaClass:\n\(all)" + ) + XCTAssertTrue( + staticExtension.contains("varDEFAULT:Color"), + "Expected static field DEFAULT: Color on JavaClass:\n\(all)" + ) + XCTAssertFalse( + instanceExtension.contains("funcmix("), + "Did not expect the static method on the instance extension:\n\(all)" + ) + XCTAssertFalse( + instanceExtension.contains("varDEFAULT"), + "Did not expect the static field on the instance extension:\n\(all)" + ) + + XCTAssertFalse( + staticExtension.contains("funcdescribe("), + "Did not expect static describe():\n\(all)" + ) + XCTAssertFalse( + staticExtension.contains("varNAME"), + "Did not expect static field NAME:\n\(all)" + ) + } +} diff --git a/scripts/wrap-java-generate.sh b/scripts/wrap-java-generate.sh index caeee9f09..f708819f8 100755 --- a/scripts/wrap-java-generate.sh +++ b/scripts/wrap-java-generate.sh @@ -37,7 +37,8 @@ $SWIFT_JAVA wrap-java \ --swift-module JavaStdlib/JavaUtilFunction \ -o Sources/JavaStdlib/JavaUtilFunction/generated \ --config Sources/JavaStdlib/JavaUtilFunction/swift-java.config \ - --depends-on SwiftJava=Sources/SwiftJava/swift-java.config + --depends-on SwiftJava=Sources/SwiftJava/swift-java.config \ + --depends-on JavaUtil=Sources/JavaStdlib/JavaUtil/swift-java.config echo "Regenerating JavaNet..." $SWIFT_JAVA wrap-java \