Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bcd5f76
WIP: fixing up wrap-java behavior, also adding tests which compile and
ktoso Sep 28, 2025
d1f29d8
WIP: need the parameterized parent types
ktoso Sep 29, 2025
45a4a3e
SwiftJava: regenerate and add JavaType and JavaParameterizedType
ktoso Sep 29, 2025
9283f57
Rename "javakitvm" to just JVM; and add JavaReflectArray
ktoso Oct 8, 2025
fe84b0a
fix throwable to print class type and message
ktoso Oct 30, 2025
8da01de
work towards handling generic methods with generic return type
ktoso Oct 30, 2025
7608b7a
handle the return type being the generic type
ktoso Oct 30, 2025
49e5949
multiple generic types on a method
ktoso Oct 31, 2025
64d3e18
wrap-java: prune not used generic parameters from methods
ktoso Oct 31, 2025
eca6bc5
cleanup assert output for wrap-java to be not whitespace sensitive
ktoso Oct 31, 2025
a13656c
revamp testing infra for wrap-java, use classloader per test
ktoso Oct 31, 2025
883969f
[jextract/jni] Add support for importing nested types (#429)
madsodgaard Nov 7, 2025
0765c74
fix rendering of inheritance clause when parameterized superclass
ktoso Nov 10, 2025
e9cfec1
further correct generic handling and type variables
ktoso Nov 10, 2025
3b87d8f
test fixes
ktoso Nov 10, 2025
2d932e6
try debugging JNI on CI
ktoso Nov 11, 2025
d81ff4f
undo work directory changes in resolve command
ktoso Nov 11, 2025
010db5e
disable experimental prebuilts in example run
ktoso Nov 11, 2025
b3aa62f
get more detailed output from JavaDependencySampleApp sample
ktoso Nov 11, 2025
070ae87
wip on enums so we can not crash in JavaDependencySampleApp
ktoso Nov 11, 2025
94c70c3
implement improved include/exclude filtering for wrap-java
ktoso Nov 11, 2025
e054f36
move JavaType equality extensions to separate file
ktoso Nov 11, 2025
b5de9d9
rename to SWIFT_JAVA_JAVA_OPTS
ktoso Nov 11, 2025
636387a
remove verbose output options
ktoso Nov 11, 2025
31e1d9b
shouldn't we use the deferEnv here?
ktoso Nov 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ func findJavaHome() -> String {
print("JAVA_HOME = \(home)")
return home
}
if let opts = ProcessInfo.processInfo.environment["SWIFT_JAVA_JAVA_OPTS"] {
print("SWIFT_JAVA_JAVA_OPTS = \(opts)")
}

// This is a workaround for envs (some IDEs) which have trouble with
// picking up env variables during the build process
Expand Down Expand Up @@ -420,7 +423,6 @@ let package = Package(
.executableTarget(
name: "SwiftJavaTool",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "SwiftBasicFormat", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
Expand Down
31 changes: 31 additions & 0 deletions Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ struct SwiftJavaBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
log("No dependencies to fetch for target \(sourceModule.name)")
}

// Add all the core Java stdlib modules as --depends-on
let javaStdlibModules = getExtractedJavaStdlibModules()
log("Include Java standard library SwiftJava modules: \(javaStdlibModules)")
arguments += javaStdlibModules.flatMap { ["--depends-on", $0] }

if !outputSwiftFiles.isEmpty {
arguments += [ configFile.path(percentEncoded: false) ]

Expand Down Expand Up @@ -236,3 +241,29 @@ extension SwiftJavaBuildToolPlugin {
outputDirectory(context: context, generated: generated).appending(path: filename)
}
}

func getExtractedJavaStdlibModules() -> [String] {
let fileManager = FileManager.default
let sourcesPath = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.deletingLastPathComponent()
.appendingPathComponent("Sources")
.appendingPathComponent("JavaStdlib")

guard let stdlibDirContents = try? fileManager.contentsOfDirectory(
at: sourcesPath,
includingPropertiesForKeys: [.isDirectoryKey],
options: [.skipsHiddenFiles]
) else {
return []
}

return stdlibDirContents.compactMap { url in
guard let resourceValues = try? url.resourceValues(forKeys: [.isDirectoryKey]),
let isDirectory = resourceValues.isDirectory,
isDirectory else {
return nil
}
return url.lastPathComponent
}.sorted()
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
{
"classes" : {
"org.apache.commons.io.FilenameUtils" : "FilenameUtils",
"org.apache.commons.io.IOCase" : "IOCase",
"org.apache.commons.csv.CSVFormat" : "CSVFormat",
"org.apache.commons.csv.CSVParser" : "CSVParser",
"org.apache.commons.csv.CSVRecord" : "CSVRecord"
},
"filterExclude" : [
"org.apache.commons.csv.CSVFormat$Predefined",
],
"dependencies" : [
"org.apache.commons:commons-csv:1.12.0"
]
Expand Down
4 changes: 3 additions & 1 deletion Samples/JavaDependencySampleApp/ci-validate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ set -e
set -x

# invoke resolve as part of a build run
swift run --disable-sandbox
swift build \
--disable-experimental-prebuilts \
--disable-sandbox

# explicitly invoke resolve without explicit path or dependency
# the dependencies should be uses from the --swift-module
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ public enum NestedEnum {
public struct OneStruct {
public init() {}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ extension JNISwift2JavaGenerator {
// Defer might on any thread, so we need to attach environment.
printer.print("let deferEnvironment = try! JavaVirtualMachine.shared().environment()")
for globalRef in globalRefs {
printer.print("environment.interface.DeleteGlobalRef(deferEnvironment, \(globalRef))")
printer.print("deferEnvironment.interface.DeleteGlobalRef(deferEnvironment, \(globalRef))")
}
}
if isThrowing {
Expand Down
26 changes: 22 additions & 4 deletions Sources/JavaStdlib/JavaLangReflect/Method+Utilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,41 @@
//===----------------------------------------------------------------------===//

extension Method {

/// Whether this is a 'public' method.
public var isPublic: Bool {
return (getModifiers() & 1) != 0
return (getModifiers() & 0x00000001) != 0
}

/// Whether this is a 'private' method.
public var isPrivate: Bool {
return (getModifiers() & 0x00000002) != 0
}

/// Whether this is a 'protected' method.
public var isProtected: Bool {
return (getModifiers() & 4) != 0
return (getModifiers() & 0x00000004) != 0
}

/// Whether this is a 'package' method.
///
/// The "default" access level in Java is 'package', it is signified by lack of a different access modifier.
public var isPackage: Bool {
return !isPublic && !isPrivate && !isProtected
}

/// Whether this is a 'static' method.
public var isStatic: Bool {
return (getModifiers() & 0x08) != 0
return (getModifiers() & 0x00000008) != 0
}

/// Whether this is a 'native' method.
public var isNative: Bool {
return (getModifiers() & 256) != 0
return (getModifiers() & 0x00000100) != 0
}

/// Whether this is a 'final' method.
public var isFinal: Bool {
return (getModifiers() & 0x00000010) != 0
}
}
63 changes: 63 additions & 0 deletions Sources/JavaStdlib/JavaLangReflect/TypeVariable+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//===----------------------------------------------------------------------===//
//
// 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 CSwiftJavaJNI
import SwiftJava

// FIXME: all interfaces should ahve these https://github.com/swiftlang/swift-java/issues/430
extension TypeVariable {

@JavaMethod
public func toString() -> String

@JavaMethod
public func getClass() -> JavaClass<JavaObject>!

@JavaMethod
public func equals(_ arg0: JavaObject?) -> Bool

@JavaMethod
public func hashCode() -> Int32

}

// FIXME: All Java objects are Hashable, we should handle that accordingly.
extension TypeVariable: Hashable {

public func hash(into hasher: inout Hasher) {
guard let pojo = self.as(JavaObject.self) else {
return
}

hasher.combine(pojo.hashCode())
}

public static func == (lhs: TypeVariable<D>, rhs: TypeVariable<D>) -> Bool {
guard let lhpojo: JavaObject = lhs.as(JavaObject.self) else {
return false
}
guard let rhpojo: JavaObject = rhs.as(JavaObject.self) else {
return false
}

return lhpojo.equals(rhpojo)
}

}

extension TypeVariable {
public var description: String {
toString()
}
}
3 changes: 0 additions & 3 deletions Sources/JavaStdlib/JavaLangReflect/generated/Executable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ open class Executable: AccessibleObject {
@JavaMethod
open func getModifiers() -> Int32

@JavaMethod
open func getTypeParameters() -> [TypeVariable<JavaObject>?]

@JavaMethod
open func getParameterTypes() -> [JavaClass<JavaObject>?]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,24 @@ public struct ParameterizedType {
@JavaMethod
public func getTypeName() -> String
}

extension ParameterizedType {

@JavaMethod
public func toString() -> String

@JavaMethod
public func getClass() -> JavaClass<JavaObject>!

@JavaMethod
public func equals(_ arg0: JavaObject?) -> Bool

@JavaMethod
public func hashCode() -> Int32
}

extension ParameterizedType: CustomStringConvertible {
public var description: String {
toString()
}
}
9 changes: 9 additions & 0 deletions Sources/JavaStdlib/JavaLangReflect/generated/Type.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,13 @@ import CSwiftJavaJNI
public struct Type {
@JavaMethod
public func getTypeName() -> String

@JavaMethod
public func toString() -> String
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to properly fix this for all interfaces #430

understanding what's going on without being able to get toString of the java types is quite a problem, i'll tackle it next. This is obviously going to be thrown away (the edit in the generated source)

}

extension Type: CustomStringConvertible {
public var description: String {
"JavaLangReflect.Type(\(self.toString()))"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import SwiftJava
import CSwiftJavaJNI

@JavaInterface("java.lang.reflect.TypeVariable", extends: Type.self)
public struct TypeVariable<D: AnyJavaObject> {
public struct TypeVariable<D: AnyJavaObject>: CustomStringConvertible {
@JavaMethod
public func getGenericDeclaration() -> GenericDeclaration!

@JavaMethod
public func getAnnotatedBounds() -> [AnnotatedType?]

Expand Down
34 changes: 34 additions & 0 deletions Sources/JavaStdlib/JavaNet/URL+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 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 SwiftJava
import CSwiftJavaJNI

import Foundation
public typealias SwiftJavaFoundationURL = Foundation.URL

extension SwiftJavaFoundationURL {
public static func fromJava(_ url: URL) throws -> SwiftJavaFoundationURL {
guard let converted = SwiftJavaFoundationURL(string: try url.toURI().toString()) else {
throw SwiftJavaConversionError("Failed to convert \(URL.self) to \(SwiftJavaFoundationURL.self)")
}
return converted
}
}

extension URL {
public static func fromSwift(_ url: SwiftJavaFoundationURL) throws -> URL {
return try URL(url.absoluteString)
}
}
22 changes: 22 additions & 0 deletions Sources/JavaStdlib/JavaNet/URLClassLoader+Workaround.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 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 CSwiftJavaJNI
import SwiftJava

// FIXME: workaround until importing properly would make UCL inherit from CL https://github.com/swiftlang/swift-java/issues/423
extension URLClassLoader /* workaround for missing inherits from ClassLoader */ {
@JavaMethod
public func loadClass(_ name: String) throws -> JavaClass<JavaObject>?
}
6 changes: 3 additions & 3 deletions Sources/SwiftJava/AnyJavaObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public protocol AnyJavaObject {
/// Protocol that allows Swift types to specify a custom Java class loader on
/// initialization. This is useful for platforms (e.g. Android) where the default
/// class loader does not make all application classes visible.
public protocol CustomJavaClassLoader: AnyJavaObject {
public protocol AnyJavaObjectWithCustomClassLoader: AnyJavaObject {
static func getJavaClassLoader(in environment: JNIEnvironment) throws -> JavaClassLoader!
}

Expand Down Expand Up @@ -118,8 +118,8 @@ extension AnyJavaObject {
in environment: JNIEnvironment,
_ body: (jclass) throws -> Result
) throws -> Result {
if let customJavaClassLoader = self as? CustomJavaClassLoader.Type,
let customClassLoader = try customJavaClassLoader.getJavaClassLoader(in: environment) {
if let AnyJavaObjectWithCustomClassLoader = self as? AnyJavaObjectWithCustomClassLoader.Type,
let customClassLoader = try AnyJavaObjectWithCustomClassLoader.getJavaClassLoader(in: environment) {
try _withJNIClassFromCustomClassLoader(customClassLoader, in: environment, body)
} else {
try _withJNIClassFromDefaultClassLoader(in: environment, body)
Expand Down
Loading
Loading