java.util.List.isAssignableFrom(java.util.ArrayList) returns false on xCode 9 beta

612 views
Skip to first unread message

Niv Stolarski

unread,
Aug 29, 2017, 8:41:06 AM8/29/17
to j2objc-discuss
Hi,

I'm using an obj-c translated code, which was translated using j2objc 1.2.
Everything works smoothly when using xcode (up to) 8.3.3, but when i'm trying the xcode 9 beta (4) the func isAssignableFrom returns false when being called for List with the param ArrayList. notice that when using xcode 9, i've defined swift version as 3.2, not 4.

Does someone has any idea what could cause this issue? what could be different between xcode 9 and 8.3?
Did anyone ever tackled a similar issue?

Thanks in advance,
Niv

Tom Ball

unread,
Aug 29, 2017, 10:53:07 AM8/29/17
to j2objc-discuss
One possibility is that the Swift's Objective C importer, which converts .h files into Swift classes, has changed between the two versions. We've had trouble get documentation on what exactly the importer expects in from an Objective C header, and so have changed j2objc's header generation based on how Foundation framework headers have changed, as well as suggestions from Swift developers. Do you know of any Xcode 9 Swift importer links we should review?

Here's the ArrayList declaration, which should be imported correctly based on our limited knowledge of Swift importing:

@interface JavaUtilArrayList : JavaUtilAbstractList < JavaUtilList, JavaUtilRandomAccess, NSCopying, JavaIoSerializable >

Since JavaUtilArrayList implements the JavaUtilList protocol, any method that has a JavaUtilList argument should accept a JavaUtilArrayList, right? Remove the "Java-isms" from the names, and it's normal-looking, uncomplicated Objective C. 

I encourage you to file a bug against Xcode 9, since you have the test case that demonstrates the issue, and do so quickly since the final release may happen soon. My guess is that there is a new bug in the Swift importer, and the more developers who provide test cases, the more likely it will be fixed.

--
You received this message because you are subscribed to the Google Groups "j2objc-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to j2objc-discus...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Niv Stolarski

unread,
Aug 29, 2017, 2:08:34 PM8/29/17
to j2objc-discuss
Hi Tom,

Actually when i'm looking on the ArrayList declaration on my machine (my mistake - it's j2objc 1.1, not 1.2) i see the following declaration:

@interface JavaUtilArrayList : JavaUtilAbstractList < NSCopying, JavaIoSerializable, JavaUtilRandomAccess >


When i'm going deeper to the AbstractList declaration i find the below:

@interface JavaUtilAbstractList : JavaUtilAbstractCollection < JavaUtilList >


Now i'm a bit confused, cause i'm not sure how come the isAssignableFrom func returns true on Xcode 8.3 and below when JavaArrayList's obj-c implementation doesn't implement directly JavaUtilList? maybe that could be the root cause?


reg. the obj-c's swift importer - how could it be the root cause? as far as i understand the issue is within the obj-c code, not when using an obj-c code from within a swift code...


is there any way i can debug the JRE_emul implementation? can i find somewhere the obj-c implementation of the JavaUtilArrayList?


thanks again,

Niv

Keith Stanger

unread,
Aug 29, 2017, 2:21:26 PM8/29/17
to j2objc-discuss
You can download the source and build as per https://developers.google.com/j2objc/guides/building-j2objc. If you want to debug at a particular version you can use the Github tag. The code of interest will be in IOSProtocolClass.m, IOSConcreteClass.m and IOSClass.m. The isAssignableFrom implementation hasn't changed significantly since 1.1. that I can think of. I haven't installed XCode 9 yet but when I do I can try to reproduce this.

Daniel Dickison

unread,
Aug 30, 2017, 4:35:08 PM8/30/17
to j2objc-discuss
I'm seeing this too, with our use of translated gson. In our case java.util.Collection.isAssignableFrom(java.util.List) is returning false. Will post if I figure out any more details.

I'm currently trying to get Xcode to be able to step into jre_emul sources in the debugger, but without success yet. I've added the jre_emul.xcodeproj to my app project, but I'm still not able to step into e.g. isAssignableFrom(). I'm guessing Xcode needs to know about debug symbols for jre_emul. Any tips on that? 

Tom Ball

unread,
Aug 30, 2017, 5:50:05 PM8/30/17
to j2objc-discuss
In jre_emul/environment.mk, set DEBUGGING_SYMBOLS=YES and OPTIMIZATION_LEVEL=0, then rebuild. The isAssignableFrom implementation for protocols is here. When checking List.isAssignableFrom(ArrayList), ArrayList's list of protocols is fetched here. Hopefully class_copyProtocolList() isn't broken in Xcode 9, since that function provides the main support for this functionality.

Daniel Dickison

unread,
Aug 31, 2017, 4:01:17 AM8/31/17
to j2objc-discuss
Thanks for the debugging tip—that did do the trick for stepping through jre_emul in Xcode.

Unfortunately it looks like class_copyProtocolList() is behaving strangely: it's only returning 1 protocol when called with JavaUtilList or JavaUtilCollection, and the returned protocol is not JavaObject. Therefore IsJavaInterface() returns false for these interfaces and get excluded from the [IOSProtocolClass getInterfacesInternal] array, which in turn makes [IOSProtocolClass isAssignableFrom] return false.

So far I've failed to reproduce this behavior in a simple test app. Even if I do something as simple as: 
  BOOL assignable = [JavaUtilCollection_class_() isAssignableFrom:JavaUtilList_class_()];
it returns true as expected. That's as far as I've gotten, with no idea why code like this is failing in my app code but not in the test app.

Niv Stolarski

unread,
Aug 31, 2017, 4:27:03 AM8/31/17
to j2objc-discuss
I had no time to dive deeper to our use case (we've translated jackson, but the issue of course is the same). Hopefully i'll have some time during the weekend...

Did you experience the issue also when you used a real device?
cause it happened to me when i used a simulator, but not sure what happens on a real device...

also - did you check if it happens also when using obj-c only app, without swift? it could give us a clue if Tom's assumption is true and the issue is within the swift importer.

You received this message because you are subscribed to a topic in the Google Groups "j2objc-discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/j2objc-discuss/avy79pz1XxU/unsubscribe.
To unsubscribe from this group and all its topics, send an email to j2objc-discuss+unsubscribe@googlegroups.com.

Keith Stanger

unread,
Aug 31, 2017, 11:06:13 AM8/31/17
to j2objc-discuss
Just a theory, could this be an initialization order thing? Is isAssignableFrom being called in static initialization code that might execute before all protocols are initialized in the runtime?

To unsubscribe from this group and all its topics, send an email to j2objc-discus...@googlegroups.com.

Tom Ball

unread,
Aug 31, 2017, 12:02:26 PM8/31/17
to j2objc-discuss
Ignore my earlier comments about Swift importing, as I was way-off with that idea. The jre_emul runtime isn't affected by Swift importing, isAssignableFrom() either works correctly or it doesn't.

Daniel Dickison

unread,
Aug 31, 2017, 1:14:53 PM8/31/17
to j2objc-...@googlegroups.com
It definitely seems to be Swift-specific from my testing. I’ve narrowed it down a bit more, though it’s still quite mysterious: the problem only seems to occur in Swift if you call, via Swift, a Java method that references the interface in questions. Equivalent code in ObjC does not cause the missing class protocols.

Here are two iOS Xcode 9 projects including a very simple j2objc-translated class that should do exactly the same thing, one in objc and one in swift:
https://github.com/danieldickison/Xcode9ObjcProtocolTest
https://github.com/danieldickison/Xcode9SwiftProtocolTest

In the swift example, the first output prints “NO?!”. Strangely enough, if you comment out the line that calls the method that returns a List, the first output changes to the correct output. It works fine in objc.

It definitely smells like a Swift bug, but I’m still confused enough to be uncertain.

Daniel Dickison

unread,
Aug 31, 2017, 5:18:20 PM8/31/17
to j2objc-discuss
Well I've found a workaround if not the cause: if you have an explicit @protocol() reference in some Objective-C code, then the class_copyProtocolList() result is complete and fixes isAssignableFrom(). Create an empty .m file, make sure it's compiled in your target, and add some dummy code like this:

#import "java/util/Collection.h"
void workaround() {
  @protocol(JavaUtilCollection);
}

I think this is pretty strong indication that it's a Swift compiler bug, but it would be nice to reproduce this without reference to the entire jre_emul translation for filing a bug with Apple, which I haven't been able to do yet. (Not to mention Apple's radar system sometimes feels like a black hole.)

Niv Stolarski

unread,
Sep 3, 2017, 6:26:09 AM9/3/17
to j2objc-discuss
Hi Daniel,

I'm not sure i'm following your workaround...
I've tried to add a file with the content you mentioned, related it to my target and even add it to the bridging-header.

but no success....
The code below still returns 'false':

        let clazz = IOSClass(forIosName: "JavaUtilList")

        let clazz2 = JavaUtilArrayList().getClass()

        let ans = clazz?.isAssignable(from: clazz2)


Anything i'm missing?

Daniel Dickison

unread,
Sep 3, 2017, 8:54:02 AM9/3/17
to j2objc-...@googlegroups.com
Did you add @protocol() statements for List and ArrayList? Maybe also Collection and AbstractList for good measure, too. 
--

Niv Stolarski

unread,
Sep 13, 2017, 4:27:15 AM9/13/17
to j2objc-discuss
Thanks, Daniel!
Adding @protocol for List did solve the issue :-)

Did you have any progress with opening a bug for Apple?

Daniel Dickison

unread,
Sep 13, 2017, 9:04:15 AM9/13/17
to j2objc-discuss
Glad to hear that worked. Alas I haven't had a chance to whittle this down into a simpler test case or file a bug with Apple (and I probably won't for a while, too, now that I have a workaround for our immediate concerns). I did just confirm that the problem still occurs with Xcode 9 GM though.

danielc...@gmail.com

unread,
Oct 11, 2017, 2:14:06 PM10/11/17
to j2objc-discuss
Daniel, could you explain why that workaround works?! I'm worried about updating my project to Swift3.2 but having problems in the future.

Daniel Dickison

unread,
Oct 11, 2017, 2:18:14 PM10/11/17
to j2objc-...@googlegroups.com
My guess would be that it has something to do with how the swift/objc compiler generates runtime metadata for objective-c protocols. Probably as an optimization it skips generating that metadata for protocols it thinks are not accessed, and only looks for explicit @protocol used in objective-c code.

That level of hand-waviness is about all I've got.


Diego Ferreira da Silva

unread,
Dec 19, 2017, 7:25:06 PM12/19/17
to j2objc-discuss
I was faced with same problem, I solved with your tip Daniel.

florent...@ampme.com

unread,
Mar 6, 2018, 2:42:15 PM3/6/18
to j2objc-discuss
On Tuesday, August 29, 2017 at 8:41:06 AM UTC-4, Niv Stolarski wrote:

Reached out to the Swift compiler team, and it definitely looks like a compiler bug.

https://twitter.com/uint_min/status/971105499415392257

Reply all
Reply to author
Forward
0 new messages