readdle / swift-java-coder Goto Github PK
View Code? Open in Web Editor NEWSwift-Java Encoder Decoder
License: MIT License
Swift-Java Encoder Decoder
License: MIT License
Given a swift struct that contains an enum-typed property (see below), its kotlin @SwiftValue
-annotated counterparts, a single instance bridges perfectly back and forth over the bridge, via the JavaDecoder/JavaEncoder, with no loss in data. But when you have an ArrayList
of instances of the kotlin data class that represents the swift struct, the value for the enum-typed property is lost and is nil
on the swift side. I've chased this issue all the way down through JavaDecoder to where it tries to get the Field ID for the java object for the enum type. It fails to find the Field ID and prints an error (it's just logged because the missing field strategy that gets generated by swift-java-codegen is always .ignored
) that says Ignored error: fieldNotFoundException for ....
Here's an example. Consider a scenario where you have a Swift and their Kotlin counterparts like below:
enum Category: String, Codable {
case sedan, suv
}
struct Car: Codable {
let description: String
let category: Category
}
struct CarCollection: Codable {
let cars: [Car]
}
Consider also their kotlin counterparts:
@SwiftValue
enum class Category(val rawValue: String) {
sedan("sedan"),
suv("suv")
}
@SwiftValue
data class Car(var description: String = "", var category: Category = null)
@SwiftValue
data class CarCollection(var cars: ArrayList<Car> = arrayListOf())
If I were to try to passing a CarCollection
over the bridge from the kotlin side to the swift side, JavaDecoder
would eventually try to decode a Car
from the array list of Car
s, and furthermore, eventually try to decode the category
field on Car
. This is where the problem shows up. The JNI bridging code tries to look up the FieldID for the category
field on Car
. However, when a type like Car
that has a property that is an enum (maybe even just a string backed enum, not sure though), is in an array, the decoding process essentially fails to decode the whole object over the bridge because these properties that are enums end up failing to decode. If you were simply trying to decode a singular Car
, that wasn't in an array list, everything would work properly.
I haven't been able to pin it down yet, but could there be a state issue with JavaDecoder
when it creates JavaArrayContainer
and then a JavaObjectContainer
or is there something going on deeper in the JNI support code. Or could it be an issue with the bytecode generated by kotlin?
Thanks in advance for looking into this.
cc: @zayass @andriydruk
The sample application https://github.com/readdle/swift-android-architecture has several comments remove after JavaCoder 2.0
or similar. But looking at the tags in this repository there is no such version.
Could you clarify what's the current state and whether JavaCoder will be further developed?
I realize that support for 32-bit is probably not much of a concern as we move towards almost all 64-bit devices, but I am curious about how to fix the error below (I've abbreviated the file paths with /.../
).
I am using the dev/kotlin-support
. I found that by only building for arm64-v8a
& x86_64
, I don't get this error. You can get the same error in @andriydruk's [swift-weather-app] by adding armeabi-v7a
to the abiFilter
list in the swift-android gradle configuration block.
/.../swift-android/swift-java-coder/Sources/JavaCoderConfig.swift:97:41: error: cannot convert value of type 'jint' (aka 'Int') to expected argument type 'Int32'
UInt(UInt32(bitPattern: JNI.CallIntMethod(value, methodID: NumberIntValueMethod)))
~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Int32( )
/.../swift-android/swift-java-coder/Sources/JavaCoderConfig.swift:118:36: error: cannot convert value of type 'jint' (aka 'Int') to expected argument type 'Int32'
UInt32(bitPattern: JNI.CallIntMethod(value, methodID: NumberIntValueMethod))
~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Int32( )
/.../swift-android/swift-java-coder/Sources/JavaPrimitive.swift:83:38: error: cannot convert value of type 'jint' (aka 'Int') to expected argument type 'Int32'
self.init(UInt32(bitPattern: javaPrimitive))
^~~~~~~~~~~~~
Int32( )
/.../swift-android/swift-java-coder/Sources/JavaPrimitive.swift:93:16: error: initializer 'init(bitPattern:)' requires that 'UInt32' conform to '_Pointer'
return jint(bitPattern: uint32)
^
Swift.Int:2:23: note: where 'P' = 'UInt32'
@inlinable public init<P>(bitPattern pointer: P?) where P : _Pointer
^
/.../swift-android/swift-java-coder/Sources/JavaPrimitive.swift:122:31: error: cannot convert value of type 'jint' (aka 'Int') to expected argument type 'Int32'
self.init(bitPattern: javaPrimitive)
^~~~~~~~~~~~~
Int32( )
/.../swift-android/swift-java-coder/Sources/JavaPrimitive.swift:126:16: error: initializer 'init(bitPattern:)' requires that 'UInt32' conform to '_Pointer'
return jint(bitPattern: self)
^
Swift.Int:2:23: note: where 'P' = 'UInt32'
@inlinable public init<P>(bitPattern pointer: P?) where P : _Pointer
^
/.../swift-android/swift-java-coder/Sources/JavaDecoder.swift:154:24: error: cannot convert return expression of type 'jint' (aka 'Int') to return type 'Int32'
return JNI.api.GetIntField(JNI.env, javaObject, fieldID)
~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Int32( )
Hi @andriydruk
Before, it was possible to bridge String-backed enums. From what I can see in the diff of JavaDecoder.swift in the dev/kotlin-support
branch, only number-backed enums are bridgeable. How do we bridge string-backed enums like the one below in kotlin? sealed classes?
enum Direction: String, Codable {
case north, south, east, west
}
cc: @elkasvirElka
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.