Serialization utility.

This class is a iterator like container for ObjectOutputStream, that also delegates to factories if there are no object in the stream, and has a static method to write object to a file. There are two kind of factories allowed, callable and class (uses no arg constructors).
What is the utility?
The read() methods are generic method with inference, so you can do this. It’s not actually type safe, however serialization can never be.


        ObjectsReader it = new ObjectsReader(programStateLocation);
        Car c;
        Integer i;
        try {
        //if you need to use another constructor than the no-args, or don't want to use reflection.
            i = it.readOrReturn(new Integer(3));
            app = it.readOrLazyCreate(Car.class);
        } finally {
            close(it);
        }
        //to write back.
        ObjectsReader.writeObjects(programStateLocation, i, c);


package util.io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.channels.FileChannel;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This class reads objects from a file.
 * It also needs to be close()-ed.
 * It has a static method providing the inverse operation,
 * writing a set of objects to a file.
 */
public final class ObjectsReader implements Closeable {

    private final File objectLocation;
    private ObjectInputStream stream;
    private FileChannel innerChannel;
    private final long fileSize;

    /**
     * @param file contains the objects or doesn't exist.
     * @throws NullPointerException if the file is null.
     */
    public ObjectsReader(File file) {
        super();
        this.objectLocation = file;
        this.fileSize = file.length();
        try {
            FileInputStream innerStream = new FileInputStream(objectLocation);
            innerChannel = innerStream.getChannel();
            stream = new ObjectInputStream(new BufferedInputStream(innerStream));
        } catch (IOException ex) {
        }
    }

    public boolean hasNext() {
        try {
            return innerChannel != null && stream != null && innerChannel.position() < fileSize;
        } catch (IOException ex) {
            return false;
        }
    }

    /**
     * Use this method if you want to use
     * the a constructor other than the no-args
     * one or don't want to use reflection.
     * Can use laziness or not according to the
     * ClassCallable implementation.
     * @param <T> return type
     * @param instance the factory of the return lazy or not,
     * in case of read error.
     * @throws NullPointerException if the factory given is null.
     * @throws IllegalArgumentException
     * if the expected type
     * is not on the stream and the factory throws
     * a exception.
     * @return a object of the return type
     */
    public <T> T readOrLazyCreate(ClassCallable<T> factory) {
        Class<T> expectedClass = factory.getReturnClass();
        Object raw = readObjectQuietly();
        if (raw != null && expectedClass.isInstance(raw)) {
            return (T) raw;
        }
        try {
            return factory.call();
        } catch (Exception ex) {
            throw new IllegalArgumentException(ex);
        }
    }

    /**
     * Use this method if you want to use
     * the no arg constructor and don't mind
     * using reflection.
     * @param <T> return type
     * @param instance the class of the lazy return
     * in case of read error.
     * @throws NullPointerException if the class given is null.
     * @throws AssertionError
     * if the expected type is not on the stream
     * and there is no public no-args constructor.
     * @return a object of the return type
     */
    public <T> T readOrLazyCreate(Class<T> factory) {
        Object raw = readObjectQuietly();
        if (raw != null && factory.isInstance(raw)) {
            return (T) raw;
        }
        //try with the class no args constructor instead.
        try {
            return (T) factory.newInstance();
        } catch (Exception ex) {
            Error e = new AssertionError("The type " + factory + " couldn't be instantiated");
            e.initCause(ex);
            throw e;
        }
    }

    /**
     * Use this method if you don't want lazyness
     * for the return value in case of read error.
     * @param <T> return type
     * @param instance the value of the return in
     * case of read error.
     * @throws NullPointerException if instance given is null.
     * @return a object of the return type
     */
    public <T> T readOrReturn(T instance) {
        Object raw = readObjectQuietly();
        if (raw != null && instance.getClass().isInstance(raw)) {
            return (T) raw;
        }
        return instance;
    }

    private Object readObjectQuietly() {
        try {
            return (stream == null)? null : stream.readObject();
        } catch (IOException ex) {
            Logger.getLogger(ObjectsReader.class.getName()).log(Level.SEVERE, ex.getClass()+" "+ex.getMessage());
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(ObjectsReader.class.getName()).log(Level.SEVERE, ex.getClass()+" "+ex.getMessage());
        }
        return null;
    }

    @Override
    public void close() throws IOException {
        if (stream != null) {
            stream.close();
        }
    }

    /**
     * If possible writes objects. Allows null objects
     */
    public static void writeObjects(File objectLocation, Serializable... obj) {
        ObjectOutputStream s = null;
        try {
            s = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(objectLocation)));
            for (Serializable a : obj) {
                s.writeObject(a);
            }
            s.flush();
        } catch (Exception ex) {
            Logger.getLogger(IoUtils.class.getName()).log(Level.SEVERE, "Couldn't write object", ex);
        } finally {
            if (s != null) {
                try {
                    s.close();
                } catch (IOException ex) {
                    Logger.getLogger(ObjectsReader.class.getName()).log(Level.SEVERE, "Couldn't close stream", ex);
                }
            }
        }
    }

    public static abstract class ClassCallable<T> implements Callable<T> {
        Class c;
        public ClassCallable(Class<T> given){
            if(given == null)
                throw new IllegalArgumentException("given class cannot be null");
            c = given;
        }

        public Class<T> getReturnClass(){
            return c;
        }
    }
}

Well, i’m still going to use this, but you should be aware that this code has a serious bug/limitation.

[s]The cast in the next() method there is (by erasure) translated into a cast into Object, and only outside it is cast into the correct value. So my way of catching the method and returning the callable result doesn’t work, since the exception is actually outside.

So this will only work for null (not there) or end of File or these kinds of situations, but not for class cast.
I think this totally sucks, but whatever.[/s]

Edit: I modified the code to use a provided class to avoid erasure. Its a little ugly in the Callable case. Meh.

BTW way i really genuinely thought that erasure replaced all the casts, by duplicating the method body for each call at a compiler level. Why can’t it do that?

I turn off all the generics warnings I don’t care about (eg warnings about the RHS of an initialization). IMO it is stupid to put a bunch of nasty stuff in your code to avoid ClassCastExceptions at runtime, which aren’t a huge problem anyway.

Just do the cast with the expected type and it blows up at runtime if the developer messes up.

But this is in serialization, where the classes change alot. If i now expect a Foo and have a Fee in the stream, i would like to avoid the classcast exception and get a Foo from the factory.

I think that the last version i posted above is more type safe.

If you want a Foo and get a Fee, it should explode. Otherwise what you really want is an Object and then you can do instanceof to act on it.

Explodes at the wrong place.

Actually i guess this is just erasure, but couldn’t erasure be eliminated from these kinds of types just by replicating the method for each different call site (with a different name obviously).

I guess it’s too slow for the compiler.

I couldn’t disagree more.

I write code in such a way that it crashes as soon as possible.

If it doesn’t crash, it works!

If a library tries to fix things for you, you won’t get notified of severe problems. If anything occurs that is not supposed to happen, STOP RIGHT THERE! Before you write data to disk, a socket, or a database. Terminate the usersession/httpsession/JVM and leave it at that. That… or, get corrupted data, which you figure out too late to rollback or repair.

Seriously. Don’t let code fix your mistakes at runtime, because it probably can’t.

That’s how C++ does templates. It leads to exponential increases in the size of the compiled code.

BTW updated the code for a more descriptive methods (not happy about the class name yet, since the write function is there too).

And compile time i assume. Still, it would be nice. But bah, class name/special callables are good enough for this lazyness use case.

Well, in this particular case, i will use this, but i know what you mean.
I prefer going back to the default state than writing readObject methods everywhere (but actually still do, huh?).