j2objc: ClassCastException in iOS11

Hi, I will use fake code to describe the problem.

I use j2objc in a framework【FrameworkA】. a protocol【ProcotolA】(translate from java interface) and I have a class like this

class ClassA : NSObject, ProtocolA {
    //ProtocolA implemention code.
}

in java code have some code like this

//obj is ClassA instance
public void method(Object obj) {
    otherMethod((ProtocolA) obj);
}

when I use frameworkA in my project it says

java.lang.ClassCastException: Cannot cast object of type FrameworkA.ClassA to ProtocolA

My j2objc version is 2.0.4. Swift version is 3.2. (use 3.1 before iOS11) But before iOS11 update it is ok, very weird. Can you give me some suggestions about this? Thank you very much.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 27 (5 by maintainers)

Most upvoted comments

The j2objc translator generates Objective C .h files which are read by the Swift importer. These files worked before iOS 11, and broke when it was released.

While we’re happy to change what’s generated if iOS 11’s version of Swift needs something different, we’ve found no documentation describing what that change should be. If anyone knows of new attributes or annotations that a protocol declaration should have to be Swift-compatible, please share them.

On Wed, Feb 21, 2018 at 10:05 AM Daniel Carlos notifications@github.com wrote:

Was it really confirmed as a Swift problem?

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/google/j2objc/issues/889#issuecomment-367416437, or mute the thread https://github.com/notifications/unsubscribe-auth/AC2kr2mJR8F1AOLv7bQJrb56eDAxGaiGks5tXFr2gaJpZM4PoMLY .

I think I’m faced with a similar issue, which is related to Xcode 9 (the error occurs in both iOS 10 and iOS 11, and did not occur with Xcode 8).

I have a Java class A which extends an abstract class B, and the class B implements an interface C. I get a ClassCastException when trying to cast A to C:

id<C> obj2 = (id<C>) cast_check(obj1, C_class_());

In cast_check (in J2Objc_source.h), I’ve found that [cls isInstance:p] returns nil. cls being an interface, I’ve looked at the implementation of isInstance: and ConformsToProtocol in IOSProtocolClass.m, and put a breakpoint on the [cls isInstance:p] line to check what was happening. Here is what I got:

(lldb) po [p java_getClass]
class A

(lldb) po [[p java_getClass] getSuperclass]
class B

(lldb) po [[[p java_getClass] getSuperclass] getInterfacesInternal]
[]

The bug seems to be in getInterfacesInternal, which should return a list containing my interface C.

I hope this helps understand the issue!

PS: bug occurs with both j2objc 1.3.1 and 2.0.4

Did you try the workaround other developers have posted?

@clementmangin Thanks for your reply. Maybe it is related with xcode version. Now I use a trick to resolve this problem. add this code below to java file

/*-[
#define cast_check(x, y) my_cast_check(x, y)
__attribute__((always_inline)) inline id my_cast_check(id __unsafe_unretained p, IOSClass *cls) {
  return p;
}
]-*/

this will replace cast_check method implemention. Hope can help.