1 /* 2 * Copyright (c) 2003, 2012, 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 34 /** 35 * A serializable mapping in the Java programming language of an SQL 36 * <code>JAVA_OBJECT</code> value. Assuming the Java object 37 * implements the <code>Serializable</code> interface, this class simply wraps the 38 * serialization process. 39 * <P> 40 * If however, the serialization is not possible because 41 * the Java object is not immediately serializable, this class will 42 * attempt to serialize all non-static members to permit the object 43 * state to be serialized. 44 * Static or transient fields cannot be serialized; an attempt to serialize 45 * them will result in a <code>SerialException</code> object being thrown. 46 * 47 * @author Jonathan Bruce 48 */ 49 public class SerialJavaObject implements Serializable, Cloneable { 50 51 /** 52 * Placeholder for object to be serialized. 53 */ 54 private Object obj; 55 56 57 /** 58 * Placeholder for all fields in the <code>JavaObject</code> being serialized. 59 */ 60 private transient Field[] fields; 61 62 /** 63 * Constructor for <code>SerialJavaObject</code> helper class. 64 * <p> 65 * 66 * @param obj the Java <code>Object</code> to be serialized 67 * @throws SerialException if the object is found not to be serializable 68 */ 69 public SerialJavaObject(Object obj) throws SerialException { 70 71 // if any static fields are found, an exception 72 // should be thrown 73 74 75 // get Class. Object instance should always be available 76 Class<?> c = obj.getClass(); 77 78 // determine if object implements Serializable i/f 79 if (!(obj instanceof java.io.Serializable)) { 80 setWarning(new RowSetWarning("Warning, the object passed to the constructor does not implement Serializable")); 81 } 82 83 // can only determine public fields (obviously). If 84 // any of these are static, this should invalidate 85 // the action of attempting to persist these fields 86 // in a serialized form 87 88 boolean anyStaticFields = false; 89 fields = c.getFields(); 90 91 for (int i = 0; i < fields.length; i++ ) { 92 if ( fields[i].getModifiers() == Modifier.STATIC ) { 93 anyStaticFields = true; 94 } 95 } 96 97 98 if (anyStaticFields) { 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 */ 126 public Field[] getFields() throws SerialException { 127 if (fields != null) { 128 Class<?> c = this.obj.getClass(); 129 return c.getFields(); 130 } else { 131 throw new SerialException("SerialJavaObject does not contain" + 132 " a serialized object instance"); 133 } 134 } 135 136 /** 137 * The identifier that assists in the serialization of this 138 * <code>SerialJavaObject</code> object. 139 */ 140 static final long serialVersionUID = -1465795139032831023L; 141 142 /** 143 * A container for the warnings issued on this <code>SerialJavaObject</code> 144 * object. When there are multiple warnings, each warning is chained to the 145 * previous warning. 146 */ 147 Vector<RowSetWarning> chain; 148 149 /** 150 * Compares this SerialJavaObject to the specified object. 151 * The result is {@code true} if and only if the argument 152 * is not {@code null} and is a {@code SerialJavaObject} 153 * object that is identical to this object 154 * 155 * @param o The object to compare this {@code SerialJavaObject} against 156 * 157 * @return {@code true} if the given object represents a {@code SerialJavaObject} 158 * equivalent to this SerialJavaObject, {@code false} otherwise 159 * 160 */ 161 public boolean equals(Object o) { 162 if (this == o) { 163 return true; 164 } 165 if (o instanceof SerialJavaObject) { 166 if(this.obj.equals( ((SerialJavaObject)o).obj)) 167 return true; 168 } 169 return false; 170 } 171 172 /** 173 * Returns a hash code for this SerialJavaObject. The hash code for a 174 * {@code SerialJavaObject} object is taken as the hash code of 175 * the {@code Object} it stores 176 * 177 * @return a hash code value for this object. 178 */ 179 public int hashCode() { 180 return 31 + obj.hashCode(); 181 } 182 183 /** 184 * Returns a clone of this {@code SerialJavaObject}. 185 * 186 * @return a clone of this SerialJavaObject 187 */ 188 189 public Object clone() { 190 try { 191 SerialJavaObject sjo = (SerialJavaObject) super.clone(); 192 sjo.fields = Arrays.copyOf(fields, fields.length); 193 if (chain != null) 194 sjo.chain = new Vector<RowSetWarning>(chain); 195 return sjo; 196 } catch (CloneNotSupportedException ex) { 197 // this shouldn't happen, since we are Cloneable 198 throw new InternalError(); 199 } 200 } 201 202 /** 203 * Registers the given warning. 204 */ 205 private void setWarning(RowSetWarning e) { 206 if (chain == null) { 207 chain = new Vector<RowSetWarning>(); 208 } 209 chain.add(e); 210 } 211 212 /** 213 * readObject is called to restore the state of the {@code SerialJavaObject} 214 * from a stream. 215 */ 216 private void readObject(ObjectInputStream s) 217 throws IOException, ClassNotFoundException { 218 219 ObjectInputStream.GetField fields1 = s.readFields(); 220 @SuppressWarnings("unchecked") 221 Vector<RowSetWarning> tmp = (Vector<RowSetWarning>)fields1.get("chain", null); 222 if (tmp != null) 223 chain = new Vector<RowSetWarning>(tmp); 224 obj = fields1.get("obj", null); 225 fields = obj.getClass().getFields(); 226 } 227 228 /** 229 * writeObject is called to save the state of the {@code SerialJavaObject} 230 * to a stream. 231 */ 232 private void writeObject(ObjectOutputStream s) 233 throws IOException { 234 ObjectOutputStream.PutField fields = s.putFields(); 235 fields.put("obj", obj); 236 fields.put("chain", chain); 237 s.writeFields(); 238 } 239 }