1 /* 2 * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.sql.rowset.serial; 27 28 import java.io.*; 29 import java.lang.reflect.*; 30 import java.util.Arrays; 31 import java.util.Vector; 32 import javax.sql.rowset.RowSetWarning; 33 import jdk.internal.reflect.CallerSensitive; 34 import jdk.internal.reflect.Reflection; 35 import sun.reflect.misc.ReflectUtil; 36 37 /** 38 * A serializable mapping in the Java programming language of an SQL 39 * <code>JAVA_OBJECT</code> value. Assuming the Java object 40 * implements the <code>Serializable</code> interface, this class simply wraps the 41 * serialization process. 42 * <P> 43 * If however, the serialization is not possible because 44 * the Java object is not immediately serializable, this class will 45 * attempt to serialize all non-static members to permit the object 46 * state to be serialized. 47 * Static or transient fields cannot be serialized; an attempt to serialize 48 * them will result in a <code>SerialException</code> object being thrown. 49 * 50 * <h2> Thread safety </h2> 51 * 52 * A SerialJavaObject is not safe for use by multiple concurrent threads. If a 53 * SerialJavaObject is to be used by more than one thread then access to the 54 * SerialJavaObject should be controlled by appropriate synchronization. 55 * 56 * @author Jonathan Bruce 57 * @since 1.5 58 */ 59 public class SerialJavaObject implements Serializable, Cloneable { 60 61 /** 62 * Placeholder for object to be serialized. 63 */ 64 @SuppressWarnings("serial") // Not statically typed as Serializable 65 private Object obj; 66 67 68 /** 69 * Placeholder for all fields in the <code>JavaObject</code> being serialized. 70 */ 71 private transient Field[] fields; 72 73 /** 74 * Constructor for <code>SerialJavaObject</code> helper class. 75 * 76 * @param obj the Java <code>Object</code> to be serialized 77 * @throws SerialException if the object is found not to be serializable 78 */ 79 public SerialJavaObject(Object obj) throws SerialException { 80 81 // if any static fields are found, an exception 82 // should be thrown 83 84 85 // get Class. Object instance should always be available 86 Class<?> c = obj.getClass(); 87 88 // determine if object implements Serializable i/f 89 if (!(obj instanceof java.io.Serializable)) { 90 setWarning(new RowSetWarning("Warning, the object passed to the constructor does not implement Serializable")); 91 } 92 93 // can only determine public fields (obviously). If 94 // any of these are static, this should invalidate 95 // the action of attempting to persist these fields 96 // in a serialized form 97 fields = c.getFields(); 98 99 if (hasStaticFields(fields)) { 100 throw new SerialException("Located static fields in " + 101 "object instance. Cannot serialize"); 102 } 103 104 this.obj = obj; 105 } 106 107 /** 108 * Returns an <code>Object</code> that is a copy of this <code>SerialJavaObject</code> 109 * object. 110 * 111 * @return a copy of this <code>SerialJavaObject</code> object as an 112 * <code>Object</code> in the Java programming language 113 * @throws SerialException if the instance is corrupt 114 */ 115 public Object getObject() throws SerialException { 116 return this.obj; 117 } 118 119 /** 120 * Returns an array of <code>Field</code> objects that contains each 121 * field of the object that this helper class is serializing. 122 * 123 * @return an array of <code>Field</code> objects 124 * @throws SerialException if an error is encountered accessing 125 * the serialized object 126 * @throws SecurityException If a security manager, <i>s</i>, is present 127 * and the caller's class loader is not the same as or an 128 * ancestor of the class loader for the class of the 129 * {@linkplain #getObject object} being serialized 130 * and invocation of {@link SecurityManager#checkPackageAccess 131 * s.checkPackageAccess()} denies access to the package 132 * of that class. 133 * @see Class#getFields 134 */ 135 @CallerSensitive 136 public Field[] getFields() throws SerialException { 137 if (fields != null) { 138 Class<?> c = this.obj.getClass(); 139 SecurityManager sm = System.getSecurityManager(); 140 if (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 */ 145 Class<?> caller = Reflection.getCallerClass(); 146 if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), 147 c.getClassLoader())) { 148 ReflectUtil.checkPackageAccess(c); 149 } 150 } 151 return c.getFields(); 152 } else { 153 throw new SerialException("SerialJavaObject does not contain" + 154 " a serialized object instance"); 155 } 156 } 157 158 /** 159 * The identifier that assists in the serialization of this 160 * <code>SerialJavaObject</code> object. 161 */ 162 static final long serialVersionUID = -1465795139032831023L; 163 164 /** 165 * A container for the warnings issued on this <code>SerialJavaObject</code> 166 * object. When there are multiple warnings, each warning is chained to the 167 * previous warning. 168 */ 169 Vector<RowSetWarning> chain; 170 171 /** 172 * Compares this SerialJavaObject to the specified object. 173 * The result is {@code true} if and only if the argument 174 * is not {@code null} and is a {@code SerialJavaObject} 175 * object that is identical to this object 176 * 177 * @param o The object to compare this {@code SerialJavaObject} against 178 * 179 * @return {@code true} if the given object represents a {@code SerialJavaObject} 180 * equivalent to this SerialJavaObject, {@code false} otherwise 181 * 182 */ 183 public boolean equals(Object o) { 184 if (this == o) { 185 return true; 186 } 187 if (o instanceof SerialJavaObject) { 188 SerialJavaObject sjo = (SerialJavaObject) o; 189 return obj.equals(sjo.obj); 190 } 191 return false; 192 } 193 194 /** 195 * Returns a hash code for this SerialJavaObject. The hash code for a 196 * {@code SerialJavaObject} object is taken as the hash code of 197 * the {@code Object} it stores 198 * 199 * @return a hash code value for this object. 200 */ 201 public int hashCode() { 202 return 31 + obj.hashCode(); 203 } 204 205 /** 206 * Returns a clone of this {@code SerialJavaObject}. 207 * 208 * @return a clone of this SerialJavaObject 209 */ 210 211 public Object clone() { 212 try { 213 SerialJavaObject sjo = (SerialJavaObject) super.clone(); 214 sjo.fields = Arrays.copyOf(fields, fields.length); 215 if (chain != null) 216 sjo.chain = new Vector<>(chain); 217 return sjo; 218 } catch (CloneNotSupportedException ex) { 219 // this shouldn't happen, since we are Cloneable 220 throw new InternalError(); 221 } 222 } 223 224 /** 225 * Registers the given warning. 226 */ 227 private void setWarning(RowSetWarning e) { 228 if (chain == null) { 229 chain = new Vector<>(); 230 } 231 chain.add(e); 232 } 233 234 /** 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 object 240 * could not be found. 241 * @throws IOException if an I/O error occurs. 242 */ 243 private void readObject(ObjectInputStream s) 244 throws IOException, ClassNotFoundException { 245 246 ObjectInputStream.GetField fields1 = s.readFields(); 247 @SuppressWarnings("unchecked") 248 Vector<RowSetWarning> tmp = (Vector<RowSetWarning>)fields1.get("chain", null); 249 if (tmp != null) 250 chain = new Vector<>(tmp); 251 252 obj = fields1.get("obj", null); 253 if (obj != null) { 254 fields = obj.getClass().getFields(); 255 if(hasStaticFields(fields)) 256 throw new IOException("Located static fields in " + 257 "object instance. Cannot serialize"); 258 } else { 259 throw new IOException("Object cannot be null!"); 260 } 261 262 } 263 264 /** 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 I/O errors occur. 269 */ 270 private void writeObject(ObjectOutputStream s) 271 throws IOException { 272 ObjectOutputStream.PutField fields = s.putFields(); 273 fields.put("obj", obj); 274 fields.put("chain", chain); 275 s.writeFields(); 276 } 277 278 /* 279 * Check to see if there are any Static Fields in this object 280 */ 281 private static boolean hasStaticFields(Field[] fields) { 282 for (Field field : fields) { 283 if ( field.getModifiers() == Modifier.STATIC) { 284 return true; 285 } 286 } 287 return false; 288 } 289 }