1

I'm trying to serialize and deserialize an object. This object can contain references to other objects, and to ArrayList and HashMap.

When I attempt to execute my code, serialization works fine, but deserialization does not. It causes the following exception:

Exception in thread "main" java.lang.ClassNotFoundException: experiment.Experiment$1
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at javax.crypto.extObjectInputStream.resolveClass(SealedObject.java:490)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1613)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2000)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1924)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1801)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
    at javax.crypto.SealedObject.getObject(SealedObject.java:302)
    at experiment.Experiment.main(Experiment.java:52)
Java Result: 1

I have the main class, Experiment, as follows:

public class Experiment {  
    public static void main(String[] args) throws Exception {
        File data = new File("C:\\Users\\Furze\\Desktop\\experiment.dat");   
        // I only execute the following to encrypt the file, which works fine:
        Test test = new Test(new VariableMap<String, String>() {{
            put("Name", "Furze");
        }});   
        Cipher cipher = Cipher.getInstance("Blowfish");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[] {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}, "Blowfish"));
        SealedObject sealedObject = new SealedObject(test, cipher);
        CipherOutputStream outputStream = new CipherOutputStream(new BufferedOutputStream(new FileOutputStream(data.getPath())), cipher);
        ObjectOutputStream objectOutput = new ObjectOutputStream(outputStream);
        objectOutput.writeObject(sealedObject);     
        objectOutput.close();
        // I then comment out the above code to test the file, which fails.
        Cipher cipher = Cipher.getInstance("Blowfish");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(new byte[] {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}, "Blowfish"));
        CipherInputStream inputStream = new CipherInputStream(new BufferedInputStream(new FileInputStream(data.getPath())), cipher);
        ObjectInputStream objectInput = new ObjectInputStream(inputStream);
        SealedObject sealedObject = (SealedObject) objectInput.readObject();
        Test test = (Test) sealedObject.getObject(cipher);
        System.out.println(test.variables.get("Name"));
    }
}

Curiously, if I leave the Test test = new Test(...); section intact while reading back, but change the name to something like test_old, it seems to work correctly.

The object classes are as follows:

// The VariableMap class is something I added during debugging to test if HashMap simply isn't serializable. It didn't help. It does have to stay a HashMap (or VariableMap!) however, for my code to operate correctly.
class VariableMap<Name, Value> extends HashMap<String, String> implements java.io.Serializable {
    public VariableMap() {
        super();
    }
}

public class Test implements java.io.Serializable {
    VariableMap<String, String> variables = new VariableMap<>();
    public Test() {}
    public Test(VariableMap<String, String> variables) {
        this.variables = variables;
    }
}

Can anybody explain what could be going wrong with my code here? I've read things about changing the CLASSPATH, but when I attempted that it made no difference.

2
  • i think you are missing something as below answer because i put all of your code in one file and it is running fine. Commented Sep 12, 2015 at 22:46
  • @Prashant did you put ALL of the code in? Because it runs fine with the double brace element in place. I've removed that as per the accepted answer, and it resolved the problem. Commented Sep 12, 2015 at 23:12

2 Answers 2

2

Situation

What is Double Brace initialization in Java?

new VariableMap<String, String>() {{
    put("Name", "Furze");
}}

creates an anonymous inner class (subclass of the class VariableMap) and creates its object.

Both class and object are created at the same spot.

It is still Serializable since all subtypes of a serializable class are themselves serializable.


Problem

When you comment it out, the class definition itself vanishes.

This results in the aforementioned ClassNotFoundException.


Solutions

  1. Try to avoid Serialization if you can. Implement your own data storage mechanism.
  2. Avoid double brace initialization if you must use Serialization.
  3. Maintain the declaration without using it (test_old way). However it is an ad-hoc solution and bad practice. It is confusing and impossible to remember. Also a possible cause for future bug.
Sign up to request clarification or add additional context in comments.

Comments

2

You're missing the package declaration on top of your class, it should read:

package experiment;

public class Experiment implements Serializable {
    public static void main(String[] args) throws Exception {
        File data = new File("C:\\Users\\Furze\\Desktop\\experiment.dat");   
        // I only execute the following to encrypt the file, which works fine:
        Test test = new Test(new VariableMap<String, String>() {{
            put("Name", "Furze");
        }});   
        Cipher cipher = Cipher.getInstance("Blowfish");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[] {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}, "Blowfish"));
        SealedObject sealedObject = new SealedObject(test, cipher);
        CipherOutputStream outputStream = new CipherOutputStream(new BufferedOutputStream(new FileOutputStream(data.getPath())), cipher);
        ObjectOutputStream objectOutput = new ObjectOutputStream(outputStream);
        objectOutput.writeObject(sealedObject);     
        objectOutput.close();
        // I then comment out the above code to test the file, which fails.
        Cipher cipher = Cipher.getInstance("Blowfish");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(new byte[] {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}, "Blowfish"));
        CipherInputStream inputStream = new CipherInputStream(new BufferedInputStream(new FileInputStream(data.getPath())), cipher);
        ObjectInputStream objectInput = new ObjectInputStream(inputStream);
        SealedObject sealedObject = (SealedObject) objectInput.readObject();
        Test test = (Test) sealedObject.getObject(cipher);
        System.out.println(test.variables.get("Name"));
    }
}

1 Comment

Sorry, I skipped that bit of my code for here, but I probably should have left it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.