All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openide.util.io.NbObjectOutputStream Maven / Gradle / Ivy

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
 * Other names may be trademarks of their respective owners.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common
 * Development and Distribution License("CDDL") (collectively, the
 * "License"). You may not use this file except in compliance with the
 * License. You can obtain a copy of the License at
 * http://www.netbeans.org/cddl-gplv2.html
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 * specific language governing permissions and limitations under the
 * License.  When distributing the software, include this License Header
 * Notice in each file and include the License file at
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the
 * License Header, with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Contributor(s):
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 *
 * If you wish your version of this file to be governed by only the CDDL
 * or only the GPL Version 2, indicate your decision by adding
 * "[Contributor] elects to include this software in this distribution
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 * single choice of license, a recipient has the option to distribute
 * your version of this file under either the CDDL, the GPL Version 2 or
 * to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 * Version 2 license, then the option applies only if the new code is
 * made subject to such option by the copyright holder.
 */

package org.openide.util.io;

import java.awt.Image;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.logging.Logger;
import org.openide.util.WeakSet;

// note: keep method NbObjectInputStream.resolveObject
// consistent with replaceObject method

/** Object output stream that could in the future be smart about saving certain objects.
* Also static methods to safely write an object that could cause problems during later deserialization.
*/
public class NbObjectOutputStream extends ObjectOutputStream {
    private static final String SVUID = "serialVersionUID"; // NOI18N
    private static final Set alreadyReported = new WeakSet();

    static {
        // See below.
        alreadyReported.add("java.lang.Exception"); // NOI18N
        alreadyReported.add("java.io.IOException"); // NOI18N
        alreadyReported.add("java.util.TreeSet"); // NOI18N
        alreadyReported.add("java.awt.geom.AffineTransform"); // NOI18N
    }

    private static Map examinedClasses = new WeakHashMap(250);
    private final List serializing = new ArrayList(50);

    /** Create a new object output.
    * @param os the underlying output stream
    * @throws IOException for the usual reasons
    */
    public NbObjectOutputStream(OutputStream os) throws IOException {
        super(os);

        try {
            enableReplaceObject(true);
        } catch (SecurityException ex) {
            throw (IOException) new IOException(ex.toString()).initCause(ex);
        }
    }

    /*
    * @param obj is an Object to be checked for replace
    */
    public Object replaceObject(Object obj) throws IOException {
        if (obj instanceof Image) {
            return null;

            // [LIGHT]
            // additional code needed for full version
        }

        return super.replaceObject(obj);
    }

    /** Writes an object safely to the object output.
     * Can be read by {@link NbObjectInputStream#readSafely}.
    * @param oo object output to write to
    * @param obj the object to write
    * @exception SafeException if the object simply fails to be serialized
    * @exception IOException if something more serious fails
    */
    public static void writeSafely(ObjectOutput oo, Object obj)
    throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream(200);

        try {
            NbObjectOutputStream oos = new NbObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.flush();
            bos.close();
        } catch (Exception exc) {
            // exception during safe of the object
            // encapsulate all exceptions into safe exception
            oo.writeInt(0);
            throw new SafeException(exc);
        }

        oo.writeInt(bos.size());
        oo.write(bos.toByteArray());
    }

    protected void annotateClass(Class cl) throws IOException {
        super.annotateClass(cl);

        if (cl.isArray()) {
            return;
        }

        if (cl.isInterface()) {
            // TheInterface.class is being serialized, not an instance;
            // no need for svuid.
            return;
        }

        serializing.add(cl);

        if (isSerialVersionUIDDeclared(cl)) {
            return;
        }

        if (IOException.class.isAssignableFrom(cl)) {
            // ObjectOutputStream for some reason stores IOException's that are
            // thrown during serialization (they are rethrown later maybe?).
            // It's no problem, just ignore them here.
            return;
        }

        String classname = cl.getName();

        if (alreadyReported.add(classname)) {
            Set serializingUniq = new HashSet();
            StringBuffer b = new StringBuffer("Serializable class "); // NOI18N
            b.append(classname);
            b.append(" does not declare serialVersionUID field. Encountered while storing: ["); // NOI18N

            Iterator it = serializing.iterator();
            boolean first = true;

            while (it.hasNext()) {
                Class c = (Class) it.next();

                if ((c != cl) && serializingUniq.add(c)) {
                    if (first) {
                        first = false;
                    } else {
                        b.append(", "); // NOI18N
                    }

                    b.append(c.getName());
                }
            }

            b.append("] See also http://www.netbeans.org/issues/show_bug.cgi?id=19915"); // NOI18N

            String file = System.getProperty("InstanceDataObject.current.file"); // NOI18N

            if ((file != null) && (file.length() > 0)) {
                b.append(" [may have been writing "); // NOI18N
                b.append(file);
                b.append("]"); // NOI18N
            }

            Logger.getLogger(NbObjectOutputStream.class.getName()).warning(b.toString());
        }
    }
    
    /* Package private for testing */
    static boolean isSerialVersionUIDDeclared(Class clazz) {
        String classname = clazz.getName();
        Boolean okay = examinedClasses.get(classname);
        
        if (okay == null) {
            if (classname.equals("java.util.HashSet") || classname.equals("java.util.ArrayList") || // NOI18N
                clazz.isEnum() || classname.equals("java.lang.Enum")) { // NOI18N
                okay = Boolean.TRUE;
            } else {
                okay = Boolean.FALSE;

                java.lang.reflect.Field[] flds = clazz.getDeclaredFields();

                for (int i = 0; i < flds.length; i++) {
                    if (flds[i].getName().equals(SVUID)) {
                        okay = Boolean.TRUE;

                        break;
                    }
                }
            }

            examinedClasses.put(clazz.getName(), okay);
        }
        
        return okay.booleanValue();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy