diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift index 78a4fb6c9..a12bb4e05 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift @@ -31,7 +31,7 @@ extension JNISwift2JavaGenerator { return // no need to write any empty files, yay } - logger.info("[swift-java] Write empty [\(self.expectedOutputSwiftFileNames.count)] 'expected' files in: \(swiftOutputDirectory)/") + logger.info("Write empty [\(self.expectedOutputSwiftFileNames.count)] 'expected' files in: \(swiftOutputDirectory)/") for expectedFileName in self.expectedOutputSwiftFileNames { logger.info("Write SwiftPM-'expected' empty file: \(expectedFileName.bold)") diff --git a/Sources/SwiftJavaTool/Commands/WrapJavaCommand.swift b/Sources/SwiftJavaTool/Commands/WrapJavaCommand.swift index 3e4e482b3..50b1c801f 100644 --- a/Sources/SwiftJavaTool/Commands/WrapJavaCommand.swift +++ b/Sources/SwiftJavaTool/Commands/WrapJavaCommand.swift @@ -339,10 +339,10 @@ extension SwiftJava.WrapJavaCommand { let anyIncludeFilterMatched = includes.contains { include in if javaClassName.starts(with: include) { // TODO: lower to trace level - log.info("Skip Java type: \(javaClassName) (does not match any include filter)") return true } + log.info("Skip Java type: \(javaClassName) (does not match any include filter)") return false } @@ -362,4 +362,5 @@ extension SwiftJava.WrapJavaCommand { // The class matches import filters, if any, and was not excluded. return true } + } diff --git a/Sources/SwiftJavaTool/CommonOptions.swift b/Sources/SwiftJavaTool/CommonOptions.swift index 4627381e0..4c48acfe6 100644 --- a/Sources/SwiftJavaTool/CommonOptions.swift +++ b/Sources/SwiftJavaTool/CommonOptions.swift @@ -65,7 +65,7 @@ extension SwiftJava { @Option(name: .long, help: "While scanning a classpath, inspect ONLY types included in these packages") var filterInclude: [String] = [] - @Option(name: .long, help: "While scanning a classpath, skip types which match the filter prefix") + @Option(name: .long, help: "While scanning a classpath, skip types which match the filter prefix. You can exclude specific methods by using the `com.example.MyClass#method` format.") var filterExclude: [String] = [] @Option(help: "A path to a custom swift-java.config to use") diff --git a/Sources/SwiftJavaToolLib/JavaClassTranslator.swift b/Sources/SwiftJavaToolLib/JavaClassTranslator.swift index b355fc0c2..1ea1c205d 100644 --- a/Sources/SwiftJavaToolLib/JavaClassTranslator.swift +++ b/Sources/SwiftJavaToolLib/JavaClassTranslator.swift @@ -214,7 +214,7 @@ struct JavaClassTranslator { for method in methods { guard let method else { continue } - guard shouldExtract(method: method) else { + guard shouldExtract(method: method, config: translator.config) else { continue } @@ -257,7 +257,34 @@ extension JavaClassTranslator { /// Determines whether a method should be extracted for translation. /// Only look at public and protected methods here. - private func shouldExtract(method: Method) -> Bool { + private func shouldExtract(method: Method, config: Configuration) -> Bool { + // Check exclude filters, if they're applicable to methods: + for exclude in config.filterExclude ?? [] where exclude.contains("#") { + let split = exclude.split(separator: "#") + guard split.count == 2 else { + self.log.warning("Malformed method exclude filter, must have only one '#' marker: \(exclude)") + continue // cannot use this filter, malformed + } + + let javaClassName = method.getDeclaringClass().getName() + let javaMemberName = method.getName() + + let className = split.first! + let excludedName = split.dropFirst().first! + + self.log.warning("Exclude filter: \(exclude) ||| \(javaClassName) / \(javaMemberName)") + + if javaClassName.starts(with: className) { + if excludedName.hasSuffix("*"), javaMemberName.starts(with: excludedName.dropLast()) { + log.info("Skip Java member '\(javaClassName)#\(javaMemberName)', prefix exclude matched: \(exclude)") + return false + } else if javaMemberName == excludedName { + log.info("Skip Java member '\(javaClassName)#\(javaMemberName)', exact exclude matched: \(exclude)") + return false + } + } + } + switch self.translator.config.effectiveMinimumInputAccessLevelMode { case .internal: return method.isPublic || method.isProtected || method.isPackage @@ -579,7 +606,8 @@ extension JavaClassTranslator { package func renderConstructor( _ javaConstructor: Constructor ) throws -> DeclSyntax { - let parameters = try translateJavaParameters(javaConstructor.getParameters()) + ["environment: JNIEnvironment? = nil"] + let parameters: [FunctionParameterSyntax] + parameters = try translateJavaParameters(javaConstructor.getParameters()) + ["environment: JNIEnvironment? = nil"] let parametersStr = parameters.map { $0.description }.joined(separator: ", ") let throwsStr = javaConstructor.throwsCheckedException ? "throws" : "" let accessModifier = javaConstructor.isPublic ? "public " : "" @@ -987,7 +1015,7 @@ extension JavaClassTranslator { continue } - guard shouldExtract(method: overriddenMethod) else { + guard shouldExtract(method: overriddenMethod, config: translator.config) else { continue }