001/*
002 * #%L
003 * Netarchivesuite - common - test
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library,
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023package dk.netarkivet.testutils;
024
025import java.io.ByteArrayInputStream;
026import java.io.ByteArrayOutputStream;
027import java.io.IOException;
028import java.io.ObjectInputStream;
029import java.io.ObjectOutputStream;
030import java.io.Serializable;
031import java.lang.reflect.Field;
032import java.lang.reflect.Modifier;
033import java.util.Arrays;
034
035import junit.framework.TestCase;
036
037/**
038 * Created by IntelliJ IDEA. User: csr Date: Mar 4, 2005 Time: 2:26:06 PM To change this template use File | Settings |
039 * File Templates.
040 */
041public class Serial {
042
043    /**
044     * Serializes an Object, deserializes it, and then returns it.
045     *
046     * @param input_object
047     * @return Object
048     * @throws IOException
049     * @throws ClassNotFoundException
050     */
051    @SuppressWarnings("unchecked")
052    public static <T extends Serializable> T serial(T input_object) throws IOException, ClassNotFoundException {
053        ByteArrayOutputStream baos = new ByteArrayOutputStream();
054
055        ObjectOutputStream ous = new ObjectOutputStream(baos);
056        ous.writeObject(input_object);
057        ous.close();
058        baos.close();
059        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
060        return (T) ois.readObject();
061    }
062
063    /**
064     * Check that transient fields are properly initialized after the object has been serialized and deserialized.
065     *
066     * @param obj A Serializable object to test.
067     * @param excludedFields Names of fields that we do not care are not initialized after deserialization. Could be
068     * integers that are properly initialized to 0 or the like. Only include fields here if you are sure that
069     * initialization is not required!
070     * @throws IOException
071     * @throws ClassNotFoundException
072     * @throws IllegalAccessException
073     */
074    public static <T extends Serializable> void assertTransientFieldsInitialized(T obj, String... excludedFields)
075            throws IOException, ClassNotFoundException, IllegalAccessException {
076        T obj2 = serial(obj);
077        Field[] fields = obj2.getClass().getDeclaredFields();
078        for (Field f : fields) {
079            if (Modifier.isTransient(f.getModifiers())) {
080                if (!Arrays.asList(excludedFields).contains(f.getName())) {
081                    f.setAccessible(true);
082                    final Class<?> type = f.getType();
083                    final Object value = f.get(obj2);
084                    if (type.isPrimitive()) {
085                        if (value == null) {
086                            TestCase.fail("Primitive field " + f + " is strangely null after deserialization");
087                        }
088                        if (type == Boolean.TYPE && value.equals(Boolean.valueOf(false)) || type == Byte.TYPE
089                                && value.equals(Byte.valueOf((byte) 0)) || type == Character.TYPE
090                                && value.equals(Character.valueOf('\0')) || type == Short.TYPE
091                                && value.equals(Short.valueOf((short) 0)) || type == Integer.TYPE
092                                && value.equals(Integer.valueOf(0)) || type == Long.TYPE
093                                && value.equals(Long.valueOf(0L)) || type == Float.TYPE
094                                && value.equals(Float.valueOf(0.0f)) || type == Double.TYPE
095                                && value.equals(Double.valueOf(0.0))) {
096                            TestCase.fail("Primitive field " + f + " has default value " + value
097                                    + " after deserialization");
098                        }
099                    } else {
100                        if (value == null) {
101                            TestCase.fail("Field " + f + " is null after deserialization");
102                        }
103                    }
104                }
105            }
106        }
107    }
108}