Skip to content

Commit db247ef

Browse files
authored
jextract/jni: add support for optional Date and Date (#568)
* add support for optional date and data * format * add logging
1 parent 292af76 commit db247ef

4 files changed

Lines changed: 202 additions & 115 deletions

File tree

‎Samples/SwiftJavaExtractJNISampleApp/Sources/MySwiftLibrary/Optionals.swift‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414

1515
import SwiftJava
1616

17+
#if canImport(FoundationEssentials)
18+
import FoundationEssentials
19+
#else
20+
import Foundation
21+
#endif
22+
1723
public func optionalBool(input: Bool?) -> Bool? {
1824
input
1925
}
@@ -54,6 +60,14 @@ public func optionalClass(input: MySwiftClass?) -> MySwiftClass? {
5460
input
5561
}
5662

63+
public func optionalDate(input: Date?) -> Date? {
64+
input
65+
}
66+
67+
public func optionalData(input: Data?) -> Data? {
68+
input
69+
}
70+
5771
public func optionalJavaKitLong(input: JavaLong?) -> Int64? {
5872
if let input {
5973
return input.longValue()

‎Samples/SwiftJavaExtractJNISampleApp/src/test/java/com/example/swift/OptionalsTest.java‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.junit.jupiter.api.Test;
1919
import org.swift.swiftkit.core.SwiftArena;
2020

21+
import java.time.Instant;
2122
import java.util.Optional;
2223
import java.util.OptionalDouble;
2324
import java.util.OptionalInt;
@@ -80,6 +81,26 @@ void optionalString() {
8081
assertEquals(Optional.of("Hello Swift!"), MySwiftLibrary.optionalString(Optional.of("Hello Swift!")));
8182
}
8283

84+
@Test
85+
void optionalDate() {
86+
try (var arena = SwiftArena.ofConfined()) {
87+
assertEquals(Optional.empty(), MySwiftLibrary.optionalDate(Optional.empty(), arena));
88+
var date = Date.fromInstant(Instant.now(), arena);
89+
Optional<Date> optionalDate = MySwiftLibrary.optionalDate(Optional.of(date), arena);
90+
assertTrue(optionalDate.isPresent());
91+
}
92+
}
93+
94+
@Test
95+
void optionalData() {
96+
try (var arena = SwiftArena.ofConfined()) {
97+
assertEquals(Optional.empty(), MySwiftLibrary.optionalData(Optional.empty(), arena));
98+
var data = Data.fromByteArray(new byte[] { 1, 2 }, arena);
99+
Optional<Data> optionalData = MySwiftLibrary.optionalData(Optional.of(data), arena);
100+
assertTrue(optionalData.isPresent());
101+
}
102+
}
103+
83104
@Test
84105
void optionalClass() {
85106
try (var arena = SwiftArena.ofConfined()) {

‎Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaTranslation.swift‎

Lines changed: 86 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ extension JNISwift2JavaGenerator {
2323
javaPackage: self.javaPackage,
2424
javaClassLookupTable: self.javaClassLookupTable,
2525
knownTypes: SwiftKnownTypes(symbolTable: lookupContext.symbolTable),
26-
protocolWrappers: self.interfaceProtocolWrappers
26+
protocolWrappers: self.interfaceProtocolWrappers,
27+
logger: self.logger
2728
)
2829
}
2930

@@ -61,7 +62,8 @@ extension JNISwift2JavaGenerator {
6162
javaPackage: self.javaPackage,
6263
javaClassLookupTable: self.javaClassLookupTable,
6364
knownTypes: SwiftKnownTypes(symbolTable: lookupContext.symbolTable),
64-
protocolWrappers: self.interfaceProtocolWrappers
65+
protocolWrappers: self.interfaceProtocolWrappers,
66+
logger: self.logger
6567
)
6668
translated = try translation.translate(enumCase: decl)
6769
} catch {
@@ -80,14 +82,16 @@ extension JNISwift2JavaGenerator {
8082
let javaClassLookupTable: JavaClassLookupTable
8183
var knownTypes: SwiftKnownTypes
8284
let protocolWrappers: [ImportedNominalType: JavaInterfaceSwiftWrapper]
85+
let logger: Logger
8386

8487
func translate(enumCase: ImportedEnumCase) throws -> TranslatedEnumCase {
8588
let nativeTranslation = NativeJavaTranslation(
8689
config: self.config,
8790
javaPackage: self.javaPackage,
8891
javaClassLookupTable: self.javaClassLookupTable,
8992
knownTypes: self.knownTypes,
90-
protocolWrappers: self.protocolWrappers
93+
protocolWrappers: self.protocolWrappers,
94+
logger: self.logger
9195
)
9296

9397
let methodName = "" // TODO: Used for closures, replace with better name?
@@ -197,7 +201,8 @@ extension JNISwift2JavaGenerator {
197201
javaPackage: self.javaPackage,
198202
javaClassLookupTable: self.javaClassLookupTable,
199203
knownTypes: self.knownTypes,
200-
protocolWrappers: self.protocolWrappers
204+
protocolWrappers: self.protocolWrappers,
205+
logger: self.logger
201206
)
202207

203208
// Types with no parent will be outputted inside a "module" class.
@@ -651,26 +656,37 @@ extension JNISwift2JavaGenerator {
651656
let nominalTypeName = nominalType.nominalTypeDecl.name
652657

653658
if let knownType = nominalType.nominalTypeDecl.knownTypeKind {
654-
guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType, config: self.config) else {
655-
throw JavaTranslationError.unsupportedSwiftType(swiftType)
656-
}
659+
switch knownType {
660+
case .foundationDate, .essentialsDate:
661+
// Handled as wrapped struct
662+
break
657663

658-
guard let translatedClass = javaType.optionalType, let placeholderValue = javaType.optionalPlaceholderValue
659-
else {
660-
throw JavaTranslationError.unsupportedSwiftType(swiftType)
661-
}
664+
case .foundationData, .essentialsData:
665+
// Handled as wrapped struct
666+
break
662667

663-
return TranslatedParameter(
664-
parameter: JavaParameter(
665-
name: parameterName,
666-
type: JavaType(className: translatedClass),
667-
annotations: parameterAnnotations
668-
),
669-
conversion: .commaSeparated([
670-
.isOptionalPresent,
671-
.method(.placeholder, function: "orElse", arguments: [.constant(placeholderValue)]),
672-
])
673-
)
668+
default:
669+
guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType, config: self.config) else {
670+
throw JavaTranslationError.unsupportedSwiftType(swiftType)
671+
}
672+
673+
guard let translatedClass = javaType.optionalType, let placeholderValue = javaType.optionalPlaceholderValue
674+
else {
675+
throw JavaTranslationError.unsupportedSwiftType(swiftType)
676+
}
677+
678+
return TranslatedParameter(
679+
parameter: JavaParameter(
680+
name: parameterName,
681+
type: JavaType(className: translatedClass),
682+
annotations: parameterAnnotations
683+
),
684+
conversion: .commaSeparated([
685+
.isOptionalPresent,
686+
.method(.placeholder, function: "orElse", arguments: [.constant(placeholderValue)]),
687+
])
688+
)
689+
}
674690
}
675691

676692
if nominalType.isSwiftJavaWrapper {
@@ -809,47 +825,58 @@ extension JNISwift2JavaGenerator {
809825
let nominalTypeName = nominalType.nominalTypeDecl.name
810826

811827
if let knownType = nominalType.nominalTypeDecl.knownTypeKind {
812-
guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType, config: self.config) else {
813-
throw JavaTranslationError.unsupportedSwiftType(swiftType)
814-
}
828+
switch knownType {
829+
case .foundationDate, .essentialsDate:
830+
// Handled as wrapped struct
831+
break
815832

816-
guard let returnType = javaType.optionalType, let optionalClass = javaType.optionalWrapperType else {
817-
throw JavaTranslationError.unsupportedSwiftType(swiftType)
818-
}
833+
case .foundationData, .essentialsData:
834+
// Handled as wrapped struct
835+
break
819836

820-
// Check if we can fit the value and a discriminator byte in a primitive.
821-
// so the return JNI value will be (value, discriminator)
822-
if let nextIntergralTypeWithSpaceForByte = javaType.nextIntergralTypeWithSpaceForByte {
823-
return TranslatedResult(
824-
javaType: .class(package: nil, name: returnType),
825-
annotations: parameterAnnotations,
826-
outParameters: [],
827-
conversion: .combinedValueToOptional(
828-
.placeholder,
829-
nextIntergralTypeWithSpaceForByte.javaType,
830-
resultName: resultName,
831-
valueType: javaType,
832-
valueSizeInBytes: nextIntergralTypeWithSpaceForByte.valueBytes,
833-
optionalType: optionalClass
837+
default:
838+
guard let javaType = JNIJavaTypeTranslator.translate(knownType: knownType, config: self.config) else {
839+
throw JavaTranslationError.unsupportedSwiftType(swiftType)
840+
}
841+
842+
guard let returnType = javaType.optionalType, let optionalClass = javaType.optionalWrapperType else {
843+
throw JavaTranslationError.unsupportedSwiftType(swiftType)
844+
}
845+
846+
// Check if we can fit the value and a discriminator byte in a primitive.
847+
// so the return JNI value will be (value, discriminator)
848+
if let nextIntergralTypeWithSpaceForByte = javaType.nextIntergralTypeWithSpaceForByte {
849+
return TranslatedResult(
850+
javaType: .class(package: nil, name: returnType),
851+
annotations: parameterAnnotations,
852+
outParameters: [],
853+
conversion: .combinedValueToOptional(
854+
.placeholder,
855+
nextIntergralTypeWithSpaceForByte.javaType,
856+
resultName: resultName,
857+
valueType: javaType,
858+
valueSizeInBytes: nextIntergralTypeWithSpaceForByte.valueBytes,
859+
optionalType: optionalClass
860+
)
834861
)
835-
)
836-
} else {
837-
// Otherwise, we return the result as normal, but
838-
// use an indirect return for the discriminator.
839-
return TranslatedResult(
840-
javaType: .class(package: nil, name: returnType),
841-
annotations: parameterAnnotations,
842-
outParameters: [
843-
OutParameter(name: discriminatorName, type: .array(.byte), allocation: .newArray(.byte, size: 1))
844-
],
845-
conversion: .toOptionalFromIndirectReturn(
846-
discriminatorName: .combinedName(component: "discriminator$"),
847-
optionalClass: optionalClass,
848-
javaType: javaType,
849-
toValue: .placeholder,
850-
resultName: resultName
862+
} else {
863+
// Otherwise, we return the result as normal, but
864+
// use an indirect return for the discriminator.
865+
return TranslatedResult(
866+
javaType: .class(package: nil, name: returnType),
867+
annotations: parameterAnnotations,
868+
outParameters: [
869+
OutParameter(name: discriminatorName, type: .array(.byte), allocation: .newArray(.byte, size: 1))
870+
],
871+
conversion: .toOptionalFromIndirectReturn(
872+
discriminatorName: .combinedName(component: "discriminator$"),
873+
optionalClass: optionalClass,
874+
javaType: javaType,
875+
toValue: .placeholder,
876+
resultName: resultName
877+
)
851878
)
852-
)
879+
}
853880
}
854881
}
855882

0 commit comments

Comments
 (0)