简体   繁体   中英

NotSerializableException when classes implement Serializable

TL;DR

I get a java.io.NotSerializableException when I try to de-serialize a PullSheet object (classes below). Where am I going wrong?

EDIT: After adding an empty constructor to the problem class I am now getting an "incompatible" exception.

StackTrace:

java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:606)
java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1772)
java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
com.campusden.learning.movingdata.ScannerActivity.loadSheet(ScannerActivity.java:271)
com.campusden.learning.movingdata.ScannerActivity.onCreate(ScannerActivity.java:79)
android.app.Activity.performCreate(Activity.java:6679)
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
android.app.ActivityThread.-wrap12(ActivityThread.java)
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
android.os.Handler.dispatchMessage(Handler.java:102)
android.os.Looper.loop(Looper.java:154)
android.app.ActivityThread.main(ActivityThread.java:6119)
java.lang.reflect.Method.invoke(Native Method)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

The Problem

I am trying to serialize a PullSheet object so that a simple backup of data is stored and as a functional requirement for users. I am able to serialize the object without exception, but when I try to deserialize I get a java.io.NotSerializableException on the PullItem class.

The Code

PullSheet.java

import ...

public class PullSheet implements Serializable{

protected String pullerName;
protected String role;
protected String store;
protected String sheetId;
protected String runItId;
protected String date;
protected UUID uuid;
protected String serialName;
protected Long startTime = System.currentTimeMillis();
protected ArrayList<PullItem> SheetItems = new ArrayList<PullItem>();


public void createSheet(String _pullerName, String _role, String _store, String _runItId){
    setPullerName(_pullerName);
    setRole(_role);
    setStore(_store);
    setRunItId(_runItId);
    setSerialName();
    setDate();
    setUuid();
    setSheetId();
}

protected void addItem(String sku, Integer qty){
    SheetItems.add(new PullItem(sku, qty));
}
protected void removeItem(PullItem item){
    this.SheetItems.remove(item);
}

//Getters and setters

public String getPullerName(){ return pullerName; }
public String getRole(){ return role; }
public String getStore(){ return store; }
public String getRunItId(){ return runItId; }
public String getSheetId(){ return sheetId; }
public Long getStartTime(){ return startTime; }
public UUID getUuid() { return uuid; }


private void setPullerName(String _pullerName){ pullerName = _pullerName; }
private void setRole(String _role){ pullerName = _role; }
private void setStore(String _store){ store = _store; }
private void setRunItId(String _runItId){ runItId = _runItId; }
private void setSerialName(){ serialName = this.store + "-" + this.date + "_" + this.uuid; }
private void setUuid(){ uuid = UUID.randomUUID(); }
private void setDate() {
    SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
    this.date = formatter.format(new Date(this.startTime));
}

private void setSheetId(){

    String randUUID = uuid.toString();
    sheetId = this.date + "-" + this.store + "-" + this.pullerName + "-" + randUUID + "-" + this.runItId;

}

}

PullItem.java

import ...

public class PullItem implements Serializable {

protected String sku;
protected Integer qty;


public PullItem(String sku, Integer qty) {
    setSku(sku);
    setQty(qty);
}

public PullItem(String sku) {
    setSku(sku);
    this.qty = 1;
}


String getSku(){
    return sku;
}

Integer getQty(){
    return qty;
}

void setSku(String _sku){
    sku = _sku;
}

void setQty(Integer _qty){
    qty = _qty;
}
void incrementQty(){
    qty += 1;
}
}

The functions that serialize and deserialize the PullSheet object:

public static boolean saveSheet(Context context, PullSheet sheet){
    String fileName = "saved.szs";
    try {
        FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        Log.d("rep", fileName);
        oos.writeObject(sheet);
        oos.close();
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }

    return true;
}

public static PullSheet loadSheet(Context context, String fileName) {
    try {
        FileInputStream fis = context.openFileInput(fileName);
        ObjectInputStream is = new ObjectInputStream(fis);
        Object readObject = is.readObject();
        is.close();

        if(readObject != null && readObject instanceof PullSheet) {
            return (PullSheet) readObject;
        }
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    return null;
}

What I Need

Please let me know where I'm going wrong. I assume it's not the types that are causing the exception because all the classes implement Serializable, but I could be off. Thanks in advance for any help

While the class may implement Serializable, that means every field[1] inside it has to be either:

  • Serializable or
  • Transient

Meaning for an instance UUID (a field in your class). Is that serializable? Every field you have in your class has to implement Serializable as well. If they don't implement serializable, they have to be transient . If it is a static or final field, it doesn't have to be. Static and final fields aren't serialized anyways.

[1] : Every field means every field that is serializable. This excludes final and static fields, or fields that are marked transient


Working example:

(All fields mentioned are of importance, and are not static, final or transient for the purpose of this example)

  • Class1 implements Serializable. Has fields of type Class2, Class3, int, double and ArrayList
  • Class2 implements Serializable has fields of type COntext
  • Class3 implements serializable has fields of type int, double, Class2

Serializing Class1 would lead to an exception. Let us break this down quickly:

  • Class2 is serializable
  • Class3 is serializable
  • int is serializable
  • double is serializable
  • ArrayList (can) be serializable if the class it holds is serializable
  • Context is not serializable

Because Class2 has a Context field (not serializable) and is serialized along with Class1 (because Class1 has a field of type Class2) you end up with an exception

It didn't implement Serializable when you serialized it. You got an exception at that time. You fixed it to implement Serializable . Then you tried to deserialize the old stream. It doesn't work.

EDIT

After adding an empty constructor to the problem class I am now getting an "incompatible" exception.

Because you changed the implicit serialVersionUID . You don't need an empty constructor in a Serializable class.

EDIT 2

Some folk here appear to be unaware that when you attempt to serialize a non-serializable object, a NotSerializableException is (1) thrown and (2) written into the data stream in such a way that when you reach it when reading with readObject() , it is thrown again, exactly as shown in the OP's stack trace.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM