1 /* 2 * Copyright (c) 2003, 2013, 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 sun.reflect.CallerSensitive; 34 import sun.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 * <h3> Thread safety </h3> 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 */ 58 public class SerialJavaObject implements Serializable, Cloneable { 59 60 /** 61 * Placeholder for object to be serialized. 62 */ 63 private Object obj; 64 65 66 /** 67 * Placeholder for all fields in the <code>JavaObject</code> being serialized. 68 */ 69 private transient Field[] fields; 70 71 /** 72 * Constructor for <code>SerialJavaObject</code> helper class. 73 * <p> 74 * 75 * @param obj the Java <code>Object</code> to be serialized 76 * @throws SerialException if the object is found not to be serializable 77 */ 78 public SerialJavaObject(Object obj) throws SerialException { 79 80 // if any static fields are found, an exception 81 // should be thrown 82 83 84 // get Class. Object instance should always be available 85 Class<?> c = obj.getClass(); 86 87 // determine if object implements Serializable i/f 88 if (!(obj instanceof java.io.Serializable)) { 89 setWarning(new RowSetWarning("Warning, the object passed to the constructor does not implement Serializable")); 90 } 91 92 // can only determine public fields (obviously). If 93 // any of these are static, this should invalidate 94 // the action of attempting to persist these fields 95 // in a serialized form 96 fields = c.getFields(); 97 98 if (hasStaticFields(fields)) { 99 throw new SerialException("Located static fields in " + 100 "object instance. Cannot serialize"); 101 } 102 103 this.obj = obj; 104 } 105 106 /** 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 an 111 * <code>Object</code> in the Java programming language 112 * @throws SerialException if the instance is corrupt 113 */ 114 public Object getObject() throws SerialException { 115 return this.obj; 116 } 117 118 /** 119 * Returns an array of <code>Field</code> objects that contains each 120 * field of the object that this helper class is serializing. 121 * 122 * @return an array of <code>Field</code> objects 123 * @throws SerialException if an error is encountered accessing 124 * the serialized object 125 * @throws SecurityException If a security manager, <i>s</i>, is present 126 * and the caller's class loader is not the same as or an 127 * ancestor of the class loader for the class of the 128 * {@linkplain #getObject object} being serialized 129 * and invocation of {@link SecurityManager#checkPackageAccess 130 * s.checkPackageAccess()} denies access to the package 131 * of that class. 132 * @see Class#getFields 133 */ 134 @CallerSensitive 135 public Field[] getFields() throws SerialException { 136 if (fields != null) { 137 Class<?> c = this.obj.getClass(); 138 SecurityManager sm = System.getSecurityManager(); 139 if (sm != null) { 140 /* 141 * Check if the caller is allowed to access the specified class's package. 142 * If access is denied, throw a SecurityException. 143 */ 144 Class<?> caller = sun.reflect.Reflection.getCallerClass(); 145 if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), 146 c.getClassLoader())) { 147 ReflectUtil.checkPackageAccess(c); 148 } 149 } 150 return c.getFields(); 151 } else { 152 throw new SerialException("SerialJavaObject does not contain" + 153 " a serialized object instance"); 154 } 155 } 156 157 /** 158 * The identifier that assists in the serialization of this 159 * <code>SerialJavaObject</code> object. 160 */ 161 static final long serialVersionUID = -1465795139032831023L; 162 163 /** 164 * A container for the warnings issued on this <code>SerialJavaObject</code> 165 * object. When there are multiple warnings, each warning is chained to the 166 * previous warning. 167 */ 168 Vector<RowSetWarning> chain; 169 170 /** 171 * Compares this SerialJavaObject to the specified object. 172 * The result is {@code true} if and only if the argument 173 * is not {@code null} and is a {@code SerialJavaObject} 174 * object that is identical to this object 175 * 176 * @param o The object to compare this {@code SerialJavaObject} against 177 * 178 * @return {@code true} if the given object represents a {@code SerialJavaObject} 179 * equivalent to this SerialJavaObject, {@code false} otherwise 180 * 181 */ 182 public boolean equals(Object o) { 183 if (this == o) { 184 return true; 185 } 186 if (o instanceof SerialJavaObject) { 187 SerialJavaObject sjo = (SerialJavaObject) o; 188 return obj.equals(sjo.obj); 189 } 190 return false; 191 } 192 193 /** 194 * Returns a hash code for this SerialJavaObject. The hash code for a 195 * {@code SerialJavaObject} object is taken as the hash code of 196 * the {@code Object} it stores 197 * 198 * @return a hash code value for this object. 199 */ 200 public int hashCode() { 201 return 31 + obj.hashCode(); 202 } 203 204 /** 205 * Returns a clone of this {@code SerialJavaObject}. 206 * 207 * @return a clone of this SerialJavaObject 208 */ 209 210 public Object clone() { 211 try { 212 SerialJavaObject sjo = (SerialJavaObject) super.clone(); 213 sjo.fields = Arrays.copyOf(fields, fields.length); 214 if (chain != null) 215 sjo.chain = new Vector<>(chain); 216 return sjo; 217 } catch (CloneNotSupportedException ex) { 218 // this shouldn't happen, since we are Cloneable 219 throw new InternalError(); 220 } 221 } 222 223 /** 224 * Registers the given warning. 225 */ 226 private void setWarning(RowSetWarning e) { 227 if (chain == null) { 228 chain = new Vector<>(); 229 } 230 chain.add(e); 231 } 232 233 /** 234 * readObject is called to restore the state of the {@code SerialJavaObject} 235 * from a stream. 236 */ 237 private void readObject(ObjectInputStream s) 238 throws IOException, ClassNotFoundException { 239 240 ObjectInputStream.GetField fields1 = s.readFields(); 241 @SuppressWarnings("unchecked") 242 Vector<RowSetWarning> tmp = (Vector<RowSetWarning>)fields1.get("chain", null); 243 if (tmp != null) 244 chain = new Vector<>(tmp); 245 246 obj = fields1.get("obj", null); 247 if (obj != null) { 248 fields = obj.getClass().getFields(); 249 if(hasStaticFields(fields)) 250 throw new IOException("Located static fields in " + 251 "object instance. Cannot serialize"); 252 } else { 253 throw new IOException("Object cannot be null!"); 254 } 255 256 } 257 258 /** 259 * writeObject is called to save the state of the {@code SerialJavaObject} 260 * to a stream. 261 */ 262 private void writeObject(ObjectOutputStream s) 263 throws IOException { 264 ObjectOutputStream.PutField fields = s.putFields(); 265 fields.put("obj", obj); 266 fields.put("chain", chain); 267 s.writeFields(); 268 } 269 270 /* 271 * Check to see if there are any Static Fields in this object 272 */ 273 private static boolean hasStaticFields(Field[] fields) { 274 for (Field field : fields) { 275 if ( field.getModifiers() == Modifier.STATIC) { 276 return true; 277 } 278 } 279 return false; 280 } 281 }