4

I have a class:

public class MyEntity implements Serializable {

    public MyInterface myInterface;

    public String name;
    public int    value;

    public MyEntity(String name, int value) {
        this.name = name;
        this.value = value;
    }
}

And an Interface:

public interface MyInterface {
    void customFunction(int value);
}

The point of this structure would be to fulfill the purpose of each and every instance of MyClass could have different implementation of customFunction(value).

So just like:

MyEntity myEntity = new MyEntity("My entity", 100);
    myEntity.myInterface = new MyInterface() {
        @Override
        public void customFunction(int value) {
            //This is my custom function.
            //This can be different for every instance of MyEntity class
        }
    };

However If I would like to serialize an instance of MyClass, I get NotSerializableException.

java.io.NotSerializableException: com.adamvarhegyi.duelsofcodrer.controller.MainActivity$1 at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1344) at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1651) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1497) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1461) at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:959) at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:360) at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1054) at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1384) at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1651) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1497) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1461) at com.adamvarhegyi.duelsofcodrer.controller.MainActivity.onCreate(MainActivity.java:62) at android.app.Activity.performCreate(Activity.java:6251) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) at android.app.ActivityThread.-wrap11(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

So my question is how could I achieve this? How could I serialize class instances with Interface instance attributes?

Update:

This is the full code to make it clearer:

(I have made inner classes from MyEntity and MyInterface to make it more simplified.)

package com.adamvarhegyi.duelsofcodrer.controller;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;

import com.adamvarhegyi.duelsofcodrer.R;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class MainActivity extends Activity {

public interface MyInterface extends Serializable {
    void customFunction(int value);
}

public class MyEntity implements Serializable {

    public MyInterface myInterface;

    public String name;
    public int    value;

    public MyEntity(String name, int value) {
        this.name = name;
        this.value = value;
    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    MyEntity myEntity = new MyEntity("My entity", 100);

    myEntity.myInterface = new MyInterface() {
        @Override
        public void customFunction(int value) {
            //This is my custom function.
            //This can be different for every instance of MyEntity class
        }
    };


    //Trying to serialize
    try {
        FileOutputStream fos = openFileOutput("myfile", Context.MODE_PRIVATE);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(myEntity);
        oos.close();
        fos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

}
}
Adam Varhegyi
  • 11,307
  • 33
  • 124
  • 222
  • Have you managed to get it right? – rafaelc Mar 06 '16 at 19:19
  • @RafaelCardoso No, I still got the exception with your advise as well. Can you try this method whether is it work? – Adam Varhegyi Mar 06 '16 at 19:27
  • @RafaelCardoso I have updated the question with the full code. – Adam Varhegyi Mar 06 '16 at 19:55
  • Adam, read this: http://stackoverflow.com/questions/7144912/why-is-a-serializable-inner-class-not-serializable . There is a problem in serializing inner classes. Try moving them to separate files and get back with the results ;) – rafaelc Mar 06 '16 at 20:04
  • @RafaelCardoso Well the classes were in separate package, I just moved them to the activity to post the code in whole. So the error still on. Sadly. – Adam Varhegyi Mar 06 '16 at 20:24
  • I have your exact code running ok here. I just cant seem why you have a problem. Are you using other data structures in your interface? – rafaelc Mar 06 '16 at 20:52
  • @RafaelCardoso I have the same code as above, try it and look the log for that exception it must be there. Drives me insane. Gona add bounty in 2 days. – Adam Varhegyi Mar 06 '16 at 23:44
  • I have found the problem. I will not get this bounty reward but I hope I could be able to help anyways! *:)* Check my edited post below. – rafaelc Mar 07 '16 at 03:53

2 Answers2

6

When you define your class as a public class MyEntity implements Serializable you are basically defining that all atributes of MyEntity should be serializable. However, MyInterface is not, thus, the attribute public MyInterface myInterface cannot be serialized, and you get the NotSerializableException .

To fix that, your interface should be an instace of Serializable, so it should extend it.

public interface MyInterface extends Serializable 
{
    void customFunction(int value);
}

That way, MyEntity will have all attributes serializable, and no errors will be thrown. It is important to notice that all basic data types such as int, float etc can be serialized, as well as Strings.

EDIT

After much thinking and reading and re-reading the code, I've found your problem. When you do the following :

myEntity.myInterface = new MyInterface() {
    @Override
    public void customFunction(int value) {
        //This is my custom function.
        //This can be different for every instance of MyEntity class
    }
};

you are actually creating a brand-new nameless inner class which implements MyInterface. However, as this is an inner class, it makes reference to its parent class which is Activity. Activity is not serializable, so that is why it throws NotSerializableException.

How to fix that?

It will not be possible for you to create custom classes to-go which are Serializable. However, there is one way out.

You can either create a new Class (e.g. named CustomInterfaceImplementation ) in a separate file, and make instances of it, or make an inner class of your Activity which is static (note that this Activity will not be created inside your onCreate() method, because that wouldn't make any sense. It should be created outside any method's scope and inside the Activity scope).

So, for instance, you could have something like:

CustomInterfaceImplementation customImpl = new CustomInterfaceImplementation();
myEntity.myInterface = customImpl;

The above code would work, being CustomInterfaceImplementation either a static class within your MainActivity or a separate public java class.

But what if I want to make on-the-go classes that varies from obj to obj?

As I said, it will be dificult to make completely new classes that are Serializable. HOWEVER, you could extract all common code between all possible implementations, and just pass variables that could, well, vary. That way, you would maintain the Serializable characteristic, and may be able to achieve your goal.

Community
  • 1
  • 1
rafaelc
  • 57,686
  • 15
  • 58
  • 82
  • If I try to simply write " implements Serializable" to my Interface just like to my class I got error message. "No implements clause allowed for interface" How do I make an interface serializable? – Adam Varhegyi Mar 06 '16 at 19:04
  • @AdamVarhegyi Im sorry, it should be `extends` instead of `implements` as an interface inherits from other – rafaelc Mar 06 '16 at 19:07
  • I still got the exception, could you try this method please to check whether is it really work? – Adam Varhegyi Mar 06 '16 at 19:20
  • @AdamVarhegyi could you post your project structure? Like, how your files as disposed? – rafaelc Mar 06 '16 at 19:33
  • Well I got these 2 classes in the package named "com.adamvarhegyi.myprojectname.junk" Nothing complicated. And I got an Activity to test the functionality. – Adam Varhegyi Mar 06 '16 at 19:43
  • 1
    Yes it is working. Thank you for your effort Rafael. – Adam Varhegyi Mar 07 '16 at 08:58
0

Either make MyInterface Serializable, or add transient to myInterface like so:

    public class MyEntity implements Serializable {
        public transient MyInterface myInterface;
        // ...
    }

Making myInterface transient marks the variable to not be serialized.

DMO-NZ
  • 71
  • 4