Path: blob/master/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SerialJavaObject.java
40948 views
/*1* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.sql.rowset.serial;2627import java.io.*;28import java.lang.reflect.*;29import java.util.Arrays;30import java.util.Vector;31import javax.sql.rowset.RowSetWarning;32import jdk.internal.reflect.CallerSensitive;33import jdk.internal.reflect.Reflection;34import sun.reflect.misc.ReflectUtil;3536/**37* A serializable mapping in the Java programming language of an SQL38* <code>JAVA_OBJECT</code> value. Assuming the Java object39* implements the <code>Serializable</code> interface, this class simply wraps the40* serialization process.41* <P>42* If however, the serialization is not possible because43* the Java object is not immediately serializable, this class will44* attempt to serialize all non-static members to permit the object45* state to be serialized.46* Static or transient fields cannot be serialized; an attempt to serialize47* them will result in a <code>SerialException</code> object being thrown.48*49* <h2> Thread safety </h2>50*51* A SerialJavaObject is not safe for use by multiple concurrent threads. If a52* SerialJavaObject is to be used by more than one thread then access to the53* SerialJavaObject should be controlled by appropriate synchronization.54*55* @author Jonathan Bruce56* @since 1.557*/58public class SerialJavaObject implements Serializable, Cloneable {5960/**61* Placeholder for object to be serialized.62*/63@SuppressWarnings("serial") // Not statically typed as Serializable64private Object obj;656667/**68* Placeholder for all fields in the <code>JavaObject</code> being serialized.69*/70private transient Field[] fields;7172/**73* Constructor for <code>SerialJavaObject</code> helper class.74*75* @param obj the Java <code>Object</code> to be serialized76* @throws SerialException if the object is found not to be serializable77*/78public SerialJavaObject(Object obj) throws SerialException {7980// if any static fields are found, an exception81// should be thrown828384// get Class. Object instance should always be available85Class<?> c = obj.getClass();8687// determine if object implements Serializable i/f88if (!(obj instanceof java.io.Serializable)) {89setWarning(new RowSetWarning("Warning, the object passed to the constructor does not implement Serializable"));90}9192// can only determine public fields (obviously). If93// any of these are static, this should invalidate94// the action of attempting to persist these fields95// in a serialized form96fields = c.getFields();9798if (hasStaticFields(fields)) {99throw new SerialException("Located static fields in " +100"object instance. Cannot serialize");101}102103this.obj = obj;104}105106/**107* Returns an <code>Object</code> that is a copy of this <code>SerialJavaObject</code>108* object.109*110* @return a copy of this <code>SerialJavaObject</code> object as an111* <code>Object</code> in the Java programming language112* @throws SerialException if the instance is corrupt113*/114public Object getObject() throws SerialException {115return this.obj;116}117118/**119* Returns an array of <code>Field</code> objects that contains each120* field of the object that this helper class is serializing.121*122* @return an array of <code>Field</code> objects123* @throws SerialException if an error is encountered accessing124* the serialized object125* @throws SecurityException If a security manager, <i>s</i>, is present126* and the caller's class loader is not the same as or an127* ancestor of the class loader for the class of the128* {@linkplain #getObject object} being serialized129* and invocation of {@link SecurityManager#checkPackageAccess130* s.checkPackageAccess()} denies access to the package131* of that class.132* @see Class#getFields133*/134@CallerSensitive135public Field[] getFields() throws SerialException {136if (fields != null) {137Class<?> c = this.obj.getClass();138@SuppressWarnings("removal")139SecurityManager sm = System.getSecurityManager();140if (sm != null) {141/*142* Check if the caller is allowed to access the specified class's package.143* If access is denied, throw a SecurityException.144*/145Class<?> caller = Reflection.getCallerClass();146if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(),147c.getClassLoader())) {148ReflectUtil.checkPackageAccess(c);149}150}151return c.getFields();152} else {153throw new SerialException("SerialJavaObject does not contain" +154" a serialized object instance");155}156}157158/**159* The identifier that assists in the serialization of this160* <code>SerialJavaObject</code> object.161*/162static final long serialVersionUID = -1465795139032831023L;163164/**165* A container for the warnings issued on this <code>SerialJavaObject</code>166* object. When there are multiple warnings, each warning is chained to the167* previous warning.168*/169Vector<RowSetWarning> chain;170171/**172* Compares this SerialJavaObject to the specified object.173* The result is {@code true} if and only if the argument174* is not {@code null} and is a {@code SerialJavaObject}175* object that is identical to this object176*177* @param o The object to compare this {@code SerialJavaObject} against178*179* @return {@code true} if the given object represents a {@code SerialJavaObject}180* equivalent to this SerialJavaObject, {@code false} otherwise181*182*/183public boolean equals(Object o) {184if (this == o) {185return true;186}187if (o instanceof SerialJavaObject) {188SerialJavaObject sjo = (SerialJavaObject) o;189return obj.equals(sjo.obj);190}191return false;192}193194/**195* Returns a hash code for this SerialJavaObject. The hash code for a196* {@code SerialJavaObject} object is taken as the hash code of197* the {@code Object} it stores198*199* @return a hash code value for this object.200*/201public int hashCode() {202return 31 + obj.hashCode();203}204205/**206* Returns a clone of this {@code SerialJavaObject}.207*208* @return a clone of this SerialJavaObject209*/210211public Object clone() {212try {213SerialJavaObject sjo = (SerialJavaObject) super.clone();214sjo.fields = Arrays.copyOf(fields, fields.length);215if (chain != null)216sjo.chain = new Vector<>(chain);217return sjo;218} catch (CloneNotSupportedException ex) {219// this shouldn't happen, since we are Cloneable220throw new InternalError();221}222}223224/**225* Registers the given warning.226*/227private void setWarning(RowSetWarning e) {228if (chain == null) {229chain = new Vector<>();230}231chain.add(e);232}233234/**235* readObject is called to restore the state of the {@code SerialJavaObject}236* from a stream.237* @param s the {@code ObjectInputStream} to read from.238*239* @throws ClassNotFoundException if the class of a serialized object240* could not be found.241* @throws IOException if an I/O error occurs.242*/243private void readObject(ObjectInputStream s)244throws IOException, ClassNotFoundException {245246ObjectInputStream.GetField fields1 = s.readFields();247@SuppressWarnings("unchecked")248Vector<RowSetWarning> tmp = (Vector<RowSetWarning>)fields1.get("chain", null);249if (tmp != null)250chain = new Vector<>(tmp);251252obj = fields1.get("obj", null);253if (obj != null) {254fields = obj.getClass().getFields();255if(hasStaticFields(fields))256throw new IOException("Located static fields in " +257"object instance. Cannot serialize");258} else {259throw new IOException("Object cannot be null!");260}261262}263264/**265* writeObject is called to save the state of the {@code SerialJavaObject}266* to a stream.267* @param s the {@code ObjectOutputStream} to write to.268* @throws IOException if an I/O error occurs.269*/270private void writeObject(ObjectOutputStream s)271throws IOException {272ObjectOutputStream.PutField fields = s.putFields();273fields.put("obj", obj);274fields.put("chain", chain);275s.writeFields();276}277278/*279* Check to see if there are any Static Fields in this object280*/281private static boolean hasStaticFields(Field[] fields) {282for (Field field : fields) {283if ( field.getModifiers() == Modifier.STATIC) {284return true;285}286}287return false;288}289}290291292