Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Sources/Java2Swift/JavaToSwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ struct JavaToSwift: ParsableCommand {
allClassesToVisit.append(contentsOf: nestedClasses)
}

// Validate configurations before writing any files
try translator.validateClassConfiguration()

// Translate all of the Java classes into Swift classes.
for javaClass in javaClasses {
translator.startNewFile()
Expand Down
72 changes: 72 additions & 0 deletions Sources/Java2SwiftLib/JavaTranslator+Validation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//===----------------------------------------------------------------------===//
//
// 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 Foundation

package extension JavaTranslator {
struct SwiftTypeName: Hashable {
let swiftType: String
let swiftModule: String?

package init(swiftType: String, swiftModule: String?) {
self.swiftType = swiftType
self.swiftModule = swiftModule
}
}

struct SwiftToJavaMapping: Equatable {
let swiftType: SwiftTypeName
let javaTypes: [String]

package init(swiftType: SwiftTypeName, javaTypes: [String]) {
self.swiftType = swiftType
self.javaTypes = javaTypes
}
}

enum ValidationError: Error, CustomStringConvertible {
case multipleClassesMappedToSameName(swiftToJavaMapping: [SwiftToJavaMapping])

package var description: String {
switch self {
case .multipleClassesMappedToSameName(let swiftToJavaMapping):
"""
The following Java classes were mapped to the same Swift type:
\(swiftToJavaMapping.map { mapping in
"Swift Type: \(mapping.swiftType.swiftModule ?? "").\(mapping.swiftType.swiftType), Java Types: \(mapping.javaTypes.sorted().joined(separator: ", "))"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
"Swift Type: \(mapping.swiftType.swiftModule ?? "").\(mapping.swiftType.swiftType), Java Types: \(mapping.javaTypes.sorted().joined(separator: ", "))"
"Swift Type: '\(mapping.swiftType.swiftModule ?? "")'.\(mapping.swiftType.swiftType), Java Types: \(mapping.javaTypes.sorted().map({ "'\($0)'" })joined(separator: ", "))"

I'd split out the creating of the names into separate lines, this is a bit busy inside the string interpolation

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated and made a helper function to split it out even more

}.joined(separator: "\n"))
"""
}
}

}
func validateClassConfiguration() throws {
// Group all classes by swift name
let groupedDictionary: [SwiftTypeName: [(String, (String, String?))]] = Dictionary(grouping: translatedClasses, by: { SwiftTypeName(swiftType: $0.value.swiftType, swiftModule: $0.value.swiftModule) })
// Find all that are mapped to multiple names
let multipleClassesMappedToSameName: [SwiftTypeName: [(String, (String, String?))]] = groupedDictionary.filter { (key: SwiftTypeName, value: [(String, (String, String?))]) in
value.count > 1
}

if !multipleClassesMappedToSameName.isEmpty {
// Convert them to swift object and throw
var errorMappings = [SwiftToJavaMapping]()
for (swiftType, swiftJavaMappings) in multipleClassesMappedToSameName {
errorMappings.append(SwiftToJavaMapping(swiftType: swiftType, javaTypes: swiftJavaMappings.map(\.0)))
}
throw ValidationError.multipleClassesMappedToSameName(swiftToJavaMapping: errorMappings)
}

}
}
40 changes: 40 additions & 0 deletions Tests/Java2SwiftTests/JavaTranslatorValidationTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// 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 Java2SwiftLib
import XCTest

final class JavaTranslatorValidationTests: XCTestCase {
func testValidationError() throws {
let translator = try JavaTranslator(swiftModuleName: "SwiftModule", environment: jvm.environment())
translator.translatedClasses = [
"TestClass": ("Class1", "Module1"),
"TestClass2": ("Class1", "Module2"),
"TestClass3": ("Class1", "Module1"),
"TestClass4": ("Class1", nil)
]

XCTAssertThrowsError(try translator.validateClassConfiguration()) { error in
XCTAssertTrue(error is JavaTranslator.ValidationError)
let validationError = error as! JavaTranslator.ValidationError
switch validationError {
case .multipleClassesMappedToSameName(let swiftToJavaMapping):
XCTAssertEqual(swiftToJavaMapping, [
JavaTranslator.SwiftToJavaMapping(swiftType: .init(swiftType: "Class1", swiftModule: "Module1"),
javaTypes: ["TestClass", "TestClass3"])
])
}
}
}
}
Loading