120 |
* @exception IOException Exception from underlying |
* @exception IOException Exception from underlying |
121 |
* <code>InputStream</code>. |
* <code>InputStream</code>. |
122 |
*/ |
*/ |
123 |
public final Object readObject() throws ClassNotFoundException, IOException |
public final Object readObject() |
124 |
|
throws ClassNotFoundException, IOException |
125 |
{ |
{ |
126 |
if (this.useSubclassMethod) |
if (this.useSubclassMethod) |
127 |
return readObjectOverride(); |
return readObjectOverride(); |
131 |
Object ret_val; |
Object ret_val; |
132 |
was_deserializing = this.isDeserializing; |
was_deserializing = this.isDeserializing; |
133 |
|
|
|
boolean is_consumed = false; |
|
134 |
boolean old_mode = setBlockDataMode(false); |
boolean old_mode = setBlockDataMode(false); |
135 |
|
|
136 |
this.isDeserializing = true; |
this.isDeserializing = true; |
143 |
|
|
144 |
try |
try |
145 |
{ |
{ |
146 |
switch (marker) |
ret_val = parseContent(marker); |
147 |
|
} |
148 |
|
finally |
149 |
|
{ |
150 |
|
setBlockDataMode(old_mode); |
151 |
|
|
152 |
|
this.isDeserializing = was_deserializing; |
153 |
|
|
154 |
|
depth -= 2; |
155 |
|
|
156 |
|
if (! was_deserializing) |
157 |
{ |
{ |
158 |
case TC_ENDBLOCKDATA: |
if (validators.size() > 0) |
159 |
|
invokeValidators(); |
160 |
|
} |
161 |
|
} |
162 |
|
|
163 |
|
return ret_val; |
164 |
|
} |
165 |
|
|
166 |
|
/** |
167 |
|
* Handles a content block within the stream, which begins with a marker |
168 |
|
* byte indicating its type. |
169 |
|
* |
170 |
|
* @param byte the byte marker. |
171 |
|
* @return an object which represents the parsed content. |
172 |
|
* @throws ClassNotFoundException if the class of an object being |
173 |
|
* read in cannot be found. |
174 |
|
* @throws IOException if invalid data occurs or one is thrown by the |
175 |
|
* underlying <code>InputStream</code>. |
176 |
|
*/ |
177 |
|
private Object parseContent(byte marker) |
178 |
|
throws ClassNotFoundException, IOException |
179 |
|
{ |
180 |
|
Object ret_val; |
181 |
|
boolean is_consumed = false; |
182 |
|
|
183 |
|
switch (marker) |
184 |
|
{ |
185 |
|
case TC_ENDBLOCKDATA: |
186 |
|
{ |
187 |
|
ret_val = null; |
188 |
|
is_consumed = true; |
189 |
|
break; |
190 |
|
} |
191 |
|
|
192 |
|
case TC_BLOCKDATA: |
193 |
|
case TC_BLOCKDATALONG: |
194 |
|
{ |
195 |
|
if (marker == TC_BLOCKDATALONG) |
196 |
|
{ if(dump) dumpElementln("BLOCKDATALONG"); } |
197 |
|
else |
198 |
|
{ if(dump) dumpElementln("BLOCKDATA"); } |
199 |
|
readNextBlock(marker); |
200 |
|
throw new StreamCorruptedException("Unexpected blockData"); |
201 |
|
} |
202 |
|
|
203 |
|
case TC_NULL: |
204 |
|
{ |
205 |
|
if(dump) dumpElementln("NULL"); |
206 |
|
ret_val = null; |
207 |
|
break; |
208 |
|
} |
209 |
|
|
210 |
|
case TC_REFERENCE: |
211 |
|
{ |
212 |
|
if(dump) dumpElement("REFERENCE "); |
213 |
|
Integer oid = new Integer(this.realInputStream.readInt()); |
214 |
|
if(dump) dumpElementln(Integer.toHexString(oid.intValue())); |
215 |
|
ret_val = ((ObjectIdentityWrapper) |
216 |
|
this.objectLookupTable.get(oid)).object; |
217 |
|
break; |
218 |
|
} |
219 |
|
|
220 |
|
case TC_CLASS: |
221 |
|
{ |
222 |
|
if(dump) dumpElementln("CLASS"); |
223 |
|
ObjectStreamClass osc = (ObjectStreamClass)readObject(); |
224 |
|
Class clazz = osc.forClass(); |
225 |
|
assignNewHandle(clazz); |
226 |
|
ret_val = clazz; |
227 |
|
break; |
228 |
|
} |
229 |
|
|
230 |
|
case TC_PROXYCLASSDESC: |
231 |
|
{ |
232 |
|
if(dump) dumpElementln("PROXYCLASS"); |
233 |
|
int n_intf = this.realInputStream.readInt(); |
234 |
|
String[] intfs = new String[n_intf]; |
235 |
|
for (int i = 0; i < n_intf; i++) |
236 |
|
{ |
237 |
|
intfs[i] = this.realInputStream.readUTF(); |
238 |
|
System.out.println(intfs[i]); |
239 |
|
} |
240 |
|
|
241 |
|
boolean oldmode = setBlockDataMode(true); |
242 |
|
Class cl = resolveProxyClass(intfs); |
243 |
|
setBlockDataMode(oldmode); |
244 |
|
|
245 |
|
ObjectStreamClass osc = lookupClass(cl); |
246 |
|
assignNewHandle(osc); |
247 |
|
|
248 |
|
if (!is_consumed) |
249 |
|
{ |
250 |
|
byte b = this.realInputStream.readByte(); |
251 |
|
if (b != TC_ENDBLOCKDATA) |
252 |
|
throw new IOException("Data annotated to class was not consumed." + b); |
253 |
|
} |
254 |
|
else |
255 |
|
is_consumed = false; |
256 |
|
ObjectStreamClass superosc = (ObjectStreamClass)readObject(); |
257 |
|
osc.setSuperclass(superosc); |
258 |
|
ret_val = osc; |
259 |
|
break; |
260 |
|
} |
261 |
|
|
262 |
|
case TC_CLASSDESC: |
263 |
|
{ |
264 |
|
ObjectStreamClass osc = readClassDescriptor(); |
265 |
|
|
266 |
|
if (!is_consumed) |
267 |
|
{ |
268 |
|
byte b = this.realInputStream.readByte(); |
269 |
|
if (b != TC_ENDBLOCKDATA) |
270 |
|
throw new IOException("Data annotated to class was not consumed." + b); |
271 |
|
} |
272 |
|
else |
273 |
|
is_consumed = false; |
274 |
|
|
275 |
|
osc.setSuperclass ((ObjectStreamClass)readObject()); |
276 |
|
ret_val = osc; |
277 |
|
break; |
278 |
|
} |
279 |
|
|
280 |
|
case TC_STRING: |
281 |
|
case TC_LONGSTRING: |
282 |
|
{ |
283 |
|
if(dump) dumpElement("STRING="); |
284 |
|
String s = this.realInputStream.readUTF(); |
285 |
|
if(dump) dumpElementln(s); |
286 |
|
ret_val = processResolution(null, s, assignNewHandle(s)); |
287 |
|
break; |
288 |
|
} |
289 |
|
|
290 |
|
case TC_ARRAY: |
291 |
|
{ |
292 |
|
if(dump) dumpElementln("ARRAY"); |
293 |
|
ObjectStreamClass osc = (ObjectStreamClass)readObject(); |
294 |
|
Class componentType = osc.forClass().getComponentType(); |
295 |
|
if(dump) dumpElement("ARRAY LENGTH="); |
296 |
|
int length = this.realInputStream.readInt(); |
297 |
|
if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType); |
298 |
|
Object array = Array.newInstance(componentType, length); |
299 |
|
int handle = assignNewHandle(array); |
300 |
|
readArrayElements(array, componentType); |
301 |
|
if(dump) |
302 |
|
for (int i = 0, len = Array.getLength(array); i < len; i++) |
303 |
|
dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i)); |
304 |
|
ret_val = processResolution(null, array, handle); |
305 |
|
break; |
306 |
|
} |
307 |
|
|
308 |
|
case TC_OBJECT: |
309 |
|
{ |
310 |
|
if(dump) dumpElementln("OBJECT"); |
311 |
|
ObjectStreamClass osc = (ObjectStreamClass)readObject(); |
312 |
|
Class clazz = osc.forClass(); |
313 |
|
|
314 |
|
if (!osc.realClassIsSerializable) |
315 |
|
throw new NotSerializableException |
316 |
|
(clazz + " is not Serializable, and thus cannot be deserialized."); |
317 |
|
|
318 |
|
if (osc.realClassIsExternalizable) |
319 |
{ |
{ |
320 |
ret_val = null; |
Externalizable obj = osc.newInstance(); |
|
is_consumed = true; |
|
|
break; |
|
|
} |
|
|
|
|
|
case TC_BLOCKDATA: |
|
|
case TC_BLOCKDATALONG: |
|
|
{ |
|
|
if (marker == TC_BLOCKDATALONG) |
|
|
{ if(dump) dumpElementln("BLOCKDATALONG"); } |
|
|
else |
|
|
{ if(dump) dumpElementln("BLOCKDATA"); } |
|
|
readNextBlock(marker); |
|
|
throw new StreamCorruptedException("Unexpected blockData"); |
|
|
} |
|
|
|
|
|
case TC_NULL: |
|
|
{ |
|
|
if(dump) dumpElementln("NULL"); |
|
|
ret_val = null; |
|
|
break; |
|
|
} |
|
|
|
|
|
case TC_REFERENCE: |
|
|
{ |
|
|
if(dump) dumpElement("REFERENCE "); |
|
|
Integer oid = new Integer(this.realInputStream.readInt()); |
|
|
if(dump) dumpElementln(Integer.toHexString(oid.intValue())); |
|
|
ret_val = ((ObjectIdentityWrapper) |
|
|
this.objectLookupTable.get(oid)).object; |
|
|
break; |
|
|
} |
|
|
|
|
|
case TC_CLASS: |
|
|
{ |
|
|
if(dump) dumpElementln("CLASS"); |
|
|
ObjectStreamClass osc = (ObjectStreamClass)readObject(); |
|
|
Class clazz = osc.forClass(); |
|
|
assignNewHandle(clazz); |
|
|
ret_val = clazz; |
|
|
break; |
|
|
} |
|
|
|
|
|
case TC_PROXYCLASSDESC: |
|
|
{ |
|
|
if(dump) dumpElementln("PROXYCLASS"); |
|
|
int n_intf = this.realInputStream.readInt(); |
|
|
String[] intfs = new String[n_intf]; |
|
|
for (int i = 0; i < n_intf; i++) |
|
|
{ |
|
|
intfs[i] = this.realInputStream.readUTF(); |
|
|
} |
|
321 |
|
|
322 |
boolean oldmode = setBlockDataMode(true); |
int handle = assignNewHandle(obj); |
|
Class cl = resolveProxyClass(intfs); |
|
|
setBlockDataMode(oldmode); |
|
323 |
|
|
324 |
ObjectStreamClass osc = lookupClass(cl); |
boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0); |
|
assignNewHandle(osc); |
|
325 |
|
|
326 |
if (!is_consumed) |
boolean oldmode = this.readDataFromBlock; |
327 |
{ |
if (read_from_blocks) |
328 |
byte b = this.realInputStream.readByte(); |
setBlockDataMode(true); |
|
if (b != TC_ENDBLOCKDATA) |
|
|
throw new IOException("Data annotated to class was not consumed." + b); |
|
|
} |
|
|
else |
|
|
is_consumed = false; |
|
|
ObjectStreamClass superosc = (ObjectStreamClass)readObject(); |
|
|
osc.setSuperclass(superosc); |
|
|
osc.firstNonSerializableParentConstructor = |
|
|
superosc.firstNonSerializableParentConstructor; |
|
|
osc.fieldMapping = new ObjectStreamField[0]; |
|
|
osc.realClassIsSerializable = true; |
|
|
ret_val = osc; |
|
|
break; |
|
|
} |
|
|
|
|
|
case TC_CLASSDESC: |
|
|
{ |
|
|
ObjectStreamClass osc = readClassDescriptor(); |
|
329 |
|
|
330 |
if (!is_consumed) |
obj.readExternal(this); |
331 |
{ |
|
332 |
byte b = this.realInputStream.readByte(); |
if (read_from_blocks) |
333 |
if (b != TC_ENDBLOCKDATA) |
{ |
334 |
throw new IOException("Data annotated to class was not consumed." + b); |
setBlockDataMode(oldmode); |
335 |
|
if (!oldmode) |
336 |
|
if (this.realInputStream.readByte() != TC_ENDBLOCKDATA) |
337 |
|
throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method."); |
338 |
} |
} |
|
else |
|
|
is_consumed = false; |
|
|
|
|
|
osc.setSuperclass ((ObjectStreamClass)readObject()); |
|
|
ret_val = osc; |
|
|
break; |
|
|
} |
|
339 |
|
|
340 |
case TC_STRING: |
ret_val = processResolution(osc, obj, handle); |
341 |
case TC_LONGSTRING: |
break; |
|
{ |
|
|
if(dump) dumpElement("STRING="); |
|
|
String s = this.realInputStream.readUTF(); |
|
|
if(dump) dumpElementln(s); |
|
|
ret_val = processResolution(null, s, assignNewHandle(s)); |
|
|
break; |
|
|
} |
|
|
|
|
|
case TC_ARRAY: |
|
|
{ |
|
|
if(dump) dumpElementln("ARRAY"); |
|
|
ObjectStreamClass osc = (ObjectStreamClass)readObject(); |
|
|
Class componentType = osc.forClass().getComponentType(); |
|
|
if(dump) dumpElement("ARRAY LENGTH="); |
|
|
int length = this.realInputStream.readInt(); |
|
|
if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType); |
|
|
Object array = Array.newInstance(componentType, length); |
|
|
int handle = assignNewHandle(array); |
|
|
readArrayElements(array, componentType); |
|
|
if(dump) |
|
|
for (int i = 0, len = Array.getLength(array); i < len; i++) |
|
|
dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i)); |
|
|
ret_val = processResolution(null, array, handle); |
|
|
break; |
|
|
} |
|
|
|
|
|
case TC_OBJECT: |
|
|
{ |
|
|
if(dump) dumpElementln("OBJECT"); |
|
|
ObjectStreamClass osc = (ObjectStreamClass)readObject(); |
|
|
Class clazz = osc.forClass(); |
|
|
|
|
|
if (!osc.realClassIsSerializable) |
|
|
throw new NotSerializableException |
|
|
(clazz + " is not Serializable, and thus cannot be deserialized."); |
|
342 |
|
|
343 |
if (osc.realClassIsExternalizable) |
} // end if (osc.realClassIsExternalizable) |
344 |
{ |
|
345 |
Externalizable obj = osc.newInstance(); |
Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor); |
346 |
|
|
347 |
int handle = assignNewHandle(obj); |
int handle = assignNewHandle(obj); |
348 |
|
Object prevObject = this.currentObject; |
349 |
boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0); |
ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass; |
350 |
|
|
351 |
boolean oldmode = this.readDataFromBlock; |
this.currentObject = obj; |
352 |
if (read_from_blocks) |
ObjectStreamClass[] hierarchy = |
353 |
setBlockDataMode(true); |
inputGetObjectStreamClasses(clazz); |
354 |
|
|
355 |
obj.readExternal(this); |
for (int i = 0; i < hierarchy.length; i++) |
356 |
|
{ |
357 |
if (read_from_blocks) |
this.currentObjectStreamClass = hierarchy[i]; |
358 |
{ |
if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ()); |
359 |
setBlockDataMode(oldmode); |
|
360 |
if (!oldmode) |
// XXX: should initialize fields in classes in the hierarchy |
361 |
if (this.realInputStream.readByte() != TC_ENDBLOCKDATA) |
// that aren't in the stream |
362 |
throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method."); |
// should skip over classes in the stream that aren't in the |
363 |
} |
// real classes hierarchy |
364 |
|
|
365 |
ret_val = processResolution(osc, obj, handle); |
Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod; |
366 |
break; |
if (readObjectMethod != null) |
367 |
} // end if (osc.realClassIsExternalizable) |
{ |
368 |
|
fieldsAlreadyRead = false; |
369 |
Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor); |
boolean oldmode = setBlockDataMode(true); |
370 |
|
callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj); |
371 |
int handle = assignNewHandle(obj); |
setBlockDataMode(oldmode); |
372 |
Object prevObject = this.currentObject; |
} |
373 |
ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass; |
else |
374 |
|
{ |
375 |
this.currentObject = obj; |
readFields(obj, currentObjectStreamClass); |
376 |
ObjectStreamClass[] hierarchy = |
} |
377 |
inputGetObjectStreamClasses(clazz); |
|
378 |
|
if (this.currentObjectStreamClass.hasWriteMethod()) |
379 |
for (int i = 0; i < hierarchy.length; i++) |
{ |
380 |
{ |
if(dump) dumpElement("ENDBLOCKDATA? "); |
381 |
this.currentObjectStreamClass = hierarchy[i]; |
try |
382 |
|
{ |
383 |
if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ()); |
/* Read blocks until an end marker */ |
384 |
|
byte writeMarker = this.realInputStream.readByte(); |
385 |
// XXX: should initialize fields in classes in the hierarchy |
while (writeMarker != TC_ENDBLOCKDATA) |
386 |
// that aren't in the stream |
{ |
387 |
// should skip over classes in the stream that aren't in the |
parseContent(writeMarker); |
388 |
// real classes hierarchy |
writeMarker = this.realInputStream.readByte(); |
|
|
|
|
Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod; |
|
|
if (readObjectMethod != null) |
|
|
{ |
|
|
fieldsAlreadyRead = false; |
|
|
boolean oldmode = setBlockDataMode(true); |
|
|
callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj); |
|
|
setBlockDataMode(oldmode); |
|
|
} |
|
|
else |
|
|
{ |
|
|
readFields(obj, currentObjectStreamClass); |
|
|
} |
|
|
|
|
|
if (this.currentObjectStreamClass.hasWriteMethod()) |
|
|
{ |
|
|
if(dump) dumpElement("ENDBLOCKDATA? "); |
|
|
try |
|
|
{ |
|
|
// FIXME: XXX: This try block is to |
|
|
// catch EOF which is thrown for some |
|
|
// objects. That indicates a bug in |
|
|
// the logic. |
|
|
|
|
|
if (this.realInputStream.readByte() != TC_ENDBLOCKDATA) |
|
|
throw new IOException |
|
|
("No end of block data seen for class with readObject (ObjectInputStream) method."); |
|
|
if(dump) dumpElementln("yes"); |
|
|
} |
|
|
// catch (EOFException e) |
|
|
// { |
|
|
// if(dump) dumpElementln("no, got EOFException"); |
|
|
// } |
|
|
catch (IOException e) |
|
|
{ |
|
|
if(dump) dumpElementln("no, got IOException"); |
|
389 |
} |
} |
390 |
|
if(dump) dumpElementln("yes"); |
391 |
|
} |
392 |
|
catch (EOFException e) |
393 |
|
{ |
394 |
|
throw (IOException) new IOException |
395 |
|
("No end of block data seen for class with readObject (ObjectInputStream) method.").initCause(e); |
396 |
} |
} |
397 |
} |
} |
|
|
|
|
this.currentObject = prevObject; |
|
|
this.currentObjectStreamClass = prevObjectStreamClass; |
|
|
ret_val = processResolution(osc, obj, handle); |
|
|
|
|
|
break; |
|
398 |
} |
} |
399 |
|
|
400 |
case TC_RESET: |
this.currentObject = prevObject; |
401 |
if(dump) dumpElementln("RESET"); |
this.currentObjectStreamClass = prevObjectStreamClass; |
402 |
clearHandles(); |
ret_val = processResolution(osc, obj, handle); |
403 |
ret_val = readObject(); |
|
404 |
break; |
break; |
405 |
|
} |
|
case TC_EXCEPTION: |
|
|
{ |
|
|
if(dump) dumpElement("EXCEPTION="); |
|
|
Exception e = (Exception)readObject(); |
|
|
if(dump) dumpElementln(e.toString()); |
|
|
clearHandles(); |
|
|
throw new WriteAbortedException("Exception thrown during writing of stream", e); |
|
|
} |
|
|
|
|
|
default: |
|
|
throw new IOException("Unknown marker on stream: " + marker); |
|
|
} |
|
|
} |
|
|
finally |
|
|
{ |
|
|
setBlockDataMode(old_mode); |
|
406 |
|
|
407 |
this.isDeserializing = was_deserializing; |
case TC_RESET: |
408 |
|
if(dump) dumpElementln("RESET"); |
409 |
|
clearHandles(); |
410 |
|
ret_val = readObject(); |
411 |
|
break; |
412 |
|
|
413 |
depth -= 2; |
case TC_EXCEPTION: |
414 |
|
{ |
415 |
|
if(dump) dumpElement("EXCEPTION="); |
416 |
|
Exception e = (Exception)readObject(); |
417 |
|
if(dump) dumpElementln(e.toString()); |
418 |
|
clearHandles(); |
419 |
|
throw new WriteAbortedException("Exception thrown during writing of stream", e); |
420 |
|
} |
421 |
|
|
422 |
if (! was_deserializing) |
default: |
423 |
{ |
throw new IOException("Unknown marker on stream: " + marker); |
|
if (validators.size() > 0) |
|
|
invokeValidators(); |
|
|
} |
|
424 |
} |
} |
|
|
|
425 |
return ret_val; |
return ret_val; |
426 |
} |
} |
427 |
|
|