0

Update - You can find a sample project to recreate the issue here: https://github.com/benf1977/j2objc-serialization-example/releases/tag/1.0

I'm trying to serialize an object in Java and pass the bytes over to my Objective-C layer to write to the filesystem. My relevant Java code is this:

/**
 * Created by benjamin.flynn on 10/7/15.
 */
public class TestData implements Serializable {

    private String mName;
    private int mAge;

    public TestData(String pName, int pAge) {
        mName = pName;
        mAge = pAge;
    }

    public String getName() {
        return mName;
    }

    public int getAge() {
        return mAge;
    }

    public byte[] bytes() {
        byte[] bytes = null;
        try (ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
             ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);) { // Application will break on this line when run on Xcode
            objectOutputStream.writeObject(this);
            bytes = byteOutputStream.toByteArray();
        } catch (IOException ioe) {
            System.err.println("Aww snap: " + ioe);
        }
        return bytes;
    }

}

I've unit tested this class in Java (which I also have a deserializer for) and it passes. In Objective-C, I'm doing this:

ComMycompanyTestData *testData = [[ComMycompanyTestData alloc] initWithNSString:@"Daryl" withInt:47];
IOSByteArray *bytes = testData.bytes; // Exception here

The exception is:

(lldb) po $arg1
java.lang.NoSuchMethodException: writeReplace

The relevant trace is:

frame #0: 0x000000019a2cbf48 libobjc.A.dylib`objc_exception_throw
    frame #1: 0x0000000100214bb0 MyApp `-[IOSClass getDeclaredMethod:parameterTypes:] + 124
    frame #2: 0x00000001000c9188 MyApp`JavaIoObjectStreamClass_findMethodWithIOSClass_withNSString_ + 144
    frame #3: 0x00000001000c71dc MyApp`JavaIoObjectStreamClass_createClassDescWithIOSClass_ + 984
    frame #4: 0x00000001000c909c MyApp`JavaIoObjectStreamClass_lookupStreamClassWithIOSClass_ + 88
    frame #5: 0x00000001000c8f88 MyApp`JavaIoObjectStreamClass_lookupWithIOSClass_ + 44
    frame #6: 0x00000001000c6f30 MyApp`JavaIoObjectStreamClass_createClassDescWithIOSClass_ + 300
    frame #7: 0x00000001000c909c MyApp`JavaIoObjectStreamClass_lookupStreamClassWithIOSClass_ + 88
    frame #8: 0x00000001000c8f88 MyApp`JavaIoObjectStreamClass_lookupWithIOSClass_ + 44
    frame #9: 0x00000001000c284c MyApp`JavaIoObjectOutputStream_initWithJavaIoOutputStream_ + 56
    frame #10: 0x00000001000c6a20 MyApp`new_JavaIoObjectOutputStream_initWithJavaIoOutputStream_ + 48
  * frame #11: 0x00000001000a666c MyApp`-[ComMycompanyTestData bytes](self=0x000000013fd51a50, _cmd="bytes") + 76 at TestData.java:49

Thoughts on what might be happening?

Ben Flynn
  • 18,524
  • 20
  • 97
  • 142

1 Answers1

0

What version of j2objc are you using? We've made recent improvements in serialization, and running your example works after adding this test added:

public static void main(String[] args) { TestData td = new TestData("Jane Doe", 30); byte[] serialized = td.bytes(); System.out.println("serialized: " + Arrays.toString(serialized)); }

I ran this with a translator/runtime built using "make dist" on the current j2objc source:

$ javac TestData.java $ java TestData serialized: [-84, -19, 0, ... $ j2objc TestData.java translating TestData.java Translated 1 file: 0 errors, 0 warnings $ j2objcc TestData.m $ ./a.out TestData serialized: [-84, -19, 0, ...

tball
  • 1,984
  • 11
  • 21
  • I'll give this a try, thanks. I'm using j2objc 0.9.8.2.1. – Ben Flynn Oct 08 '15 at 19:14
  • Hmm. That is working from the command line. It is not working when I am running on an iOS device. I will dig into my project file for a moment. FYI I'm using Xcode 7.0.1, iOS SDK 9.0, I am including libjre_emul.a in my build. I was able to pass a string from Java to Objective-C, but with this method I've hit a bit of a wall. – Ben Flynn Oct 08 '15 at 19:28
  • I've now also tried compiling the latest source from GitLab, using the instructions for including JreEmulation as a subproject, but am seeing the same error. – Ben Flynn Oct 08 '15 at 23:00
  • I created a project on GitHub that demonstrates the behavior I'm seeing (see my update question). – Ben Flynn Oct 12 '15 at 20:39
  • I don't know if this is good news or bad, but your project runs fine on my system. I even copied the println from runTest() (line 59) to after byteOutputStream.toByteArray() line (67), and it printed out a byte array rather than crashing. – tball Oct 13 '15 at 22:10
  • Good-ish? =) I'll see if anyone else on my team can recreate it and comment again. – Ben Flynn Oct 13 '15 at 22:13
  • 1
    I think I found it: do you have "break on all exceptions" set in the debugger? If so, this exception is not a failure -- it's normal Java behavior. ObjectStreamClass.findMethod() checks each class in a class hierarchy for a writeReplace method by calling Class.getDeclaredMethod() and catching any NoSuchMethodExceptions. So remove that "all exceptions" breakpoint -- you can instead break on a specific exception class when you need to. – tball Oct 13 '15 at 22:16
  • That's it! I never played through the application execution to realize it was a non-critical exception. Thanks much. – Ben Flynn Oct 13 '15 at 23:26