Как проверить на Java, что класс реализует Serializable правильно (не просто экземпляр Serializable)

Я реализую класс для Serializable (так что это объект значения для использования w/RMI). Но мне нужно проверить это. Есть ли способ сделать это легко?

пояснение. Я реализую класс, поэтому тривиально придерживаться Serializable в определении класса. Мне нужно вручную сериализовать/десериализовать его, чтобы увидеть, работает ли он.

Я нашел этот вопрос С#, есть ли аналогичный ответ для Java?

Ответ 1

Простым способом является проверка того, что объект является экземпляром java.io.Serializable или java.io.Externalizable, но это на самом деле не доказывает, что объект действительно сериализуем.

Единственный способ быть уверенным в том, чтобы попробовать это по-настоящему. Самый простой тест - это что-то вроде:

new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(myObject);

и проверить, не генерирует ли исключение.

Apache Commons Lang предоставляет более краткую версию:

SerializationUtils.serialize(myObject);

и снова проверьте исключение.

Вы можете быть еще более уравновешенным и проверить, что он десериализуется обратно во что-то равное оригиналу:

Serializable original = ...
Serializable copy = SerializationUtils.clone(original);
assertEquals(original, copy);

и т.д.

Ответ 2

утилиты, основанные на ответе скаффмана:

private static <T extends Serializable> byte[] pickle(T obj) 
       throws IOException 
{
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(obj);
    oos.close();
    return baos.toByteArray();
}

private static <T extends Serializable> T unpickle(byte[] b, Class<T> cl)
       throws IOException, ClassNotFoundException 
{
    ByteArrayInputStream bais = new ByteArrayInputStream(b);
    ObjectInputStream ois = new ObjectInputStream(bais);
    Object o = ois.readObject();
    return cl.cast(o);
}

Ответ 3

Этот код должен сделать это...

import java.io.ByteArrayOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;

public class Main
{
    public static void main(String[] args)
    {
        System.out.println(isSerializable("Hello"));
        System.out.println(isSerializable(new Main()));
    }

    public static boolean isSerializable(final Object o)
    {
        final boolean retVal;

        if(implementsInterface(o))
        {
            retVal = attemptToSerialize(o);
        }
        else
        {
            retVal = false;
        }

        return (retVal);
    }

    private static boolean implementsInterface(final Object o)
    {
        final boolean retVal;

        retVal = ((o instanceof Serializable) || (o instanceof Externalizable));

        return (retVal);
    }

    private static boolean attemptToSerialize(final Object o)
    {
        final OutputStream sink;
        ObjectOutputStream stream;

        stream = null;

        try
        {
            sink   = new ByteArrayOutputStream();
            stream = new ObjectOutputStream(sink);
            stream.writeObject(o);
            // could also re-serilalize at this point too
        }
        catch(final IOException ex)
        {
            return (false);
        }
        finally
        {
            if(stream != null)
            {
                try
                {
                    stream.close();
                }
                catch(final IOException ex)
                {
                    // should not be able to happen
                }
            }
        }

        return (true);
    }
}

Ответ 4

Вы можете выполнить следующий тест:

  • Сериализовать объект в файл и сделать конечно, исключение не будет выбрано.
  • Кроме того, десериализуйте объект назад и сравните с оригинальным объектом.

Вот пример для сериализации и десериализации объекта в файл:

http://www.rgagnon.com/javadetails/java-0075.html

http://www.javapractices.com/topic/TopicAction.do?Id=57

Ответ 5

Короткий ответ: вы можете найти некоторые объекты-кандидаты и на самом деле попытаться их сериализовать, используя механизм по вашему выбору. Тест здесь заключается в том, что во время сортировки/разборки не возникает ошибок и что полученный "регидратированный" объект равен оригиналу.

В качестве альтернативы, если у вас нет каких-либо объектов-кандидатов, вы можете реализовать тест на основе отражения, который исследует (нестатические, не-переходные) поля вашего класса, чтобы гарантировать, что они тоже являются Serializable. Говоря по опыту, это на удивление сложно на удивление быстро, но это можно сделать в разумной степени.

Недостатком этого последнего подхода является то, что если поле является, например, полем. List<String>, то вы можете либо отказаться от класса, чтобы не иметь строго сериализуемое поле, либо просто предположить, что будет использоваться сериализуемая реализация List. Ничто не идеально. (Имейте в виду, что последняя проблема существует и для примеров: если в каждом примере, используемом в тесте, используются сериализуемые списки, нет ничего, что могло бы предотвратить использование несериализуемой версии каким-либо другим кодом на практике).

Ответ 6

Это работает только для полностью заполненных объектов, если вам требуется, чтобы любые объекты, состоящие из вашего объекта верхнего уровня, также были сериализованы, тогда они не могут быть пустыми, чтобы этот тест был действительным, поскольку сериализация/десериализация пропускает нулевые объекты