Class: Java::ObjectInputStream

Inherits:
Object
  • Object
show all
Includes:
ObjectStream
Defined in:
lib/javaobs.rb

Overview

The Ruby version of the Java ObjectInputStream. Creates a Ruby proxy class for each Java Class.

Constant Summary

Constants included from ObjectStream

Java::ObjectStream::PRIM_ARRAY, Java::ObjectStream::PRIM_BOOL, Java::ObjectStream::PRIM_BYTE, Java::ObjectStream::PRIM_CHAR, Java::ObjectStream::PRIM_DOUBLE, Java::ObjectStream::PRIM_FLOAT, Java::ObjectStream::PRIM_INT, Java::ObjectStream::PRIM_LONG, Java::ObjectStream::PRIM_OBJECT, Java::ObjectStream::PRIM_SHORT, Java::ObjectStream::SC_BLOCKDATA, Java::ObjectStream::SC_EXTERNALIZABLE, Java::ObjectStream::SC_SERIALIZABLE, Java::ObjectStream::SC_WRITE_METHOD, Java::ObjectStream::STREAM_MAGIC, Java::ObjectStream::STREAM_VERSION, Java::ObjectStream::TC_ARRAY, Java::ObjectStream::TC_BLOCKDATA, Java::ObjectStream::TC_BLOCKDATALONG, Java::ObjectStream::TC_CLASS, Java::ObjectStream::TC_CLASSDESC, Java::ObjectStream::TC_ENDBLOCKDATA, Java::ObjectStream::TC_EXCEPTION, Java::ObjectStream::TC_LONGSTRING, Java::ObjectStream::TC_NULL, Java::ObjectStream::TC_OBJECT, Java::ObjectStream::TC_PROXYCLASSDESC, Java::ObjectStream::TC_REFERENCE, Java::ObjectStream::TC_RESET, Java::ObjectStream::TC_STRING

Instance Method Summary collapse

Constructor Details

#initialize(str) ⇒ ObjectInputStream

Initialize from a stream.



395
396
397
398
399
400
401
402
403
404
# File 'lib/javaobs.rb', line 395

def initialize(str)
  @str = str
  magic =  readUShort
  streamVersion = readShort
  @objects = []

  raise "Bad stream #{magic.to_s(16)}:#{streamVersion.to_s(16)}" if magic != STREAM_MAGIC ||
  streamVersion != STREAM_VERSION

end

Instance Method Details

#readArray(klass) ⇒ Object

Read an array of objects.



287
288
289
290
291
292
293
294
295
# File 'lib/javaobs.rb', line 287

def readArray(klass)
  size = readInt
  a = klass.rubyClass.new
  type = klass.arrayType
  1.upto(size) do
    a << readType(type)
  end
  a
end

#readBlockDataObject

Read a Java block of data with a size and then the following data.

Raises:



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/javaobs.rb', line 192

def readBlockData
  byte = readByte
  size = nil
  case byte
  when TC_BLOCKDATA
    size = readByte
    
  when TC_BLOCKDATALONG
    size = readInt
    
  else
    raise SerializationError, "Expecting TC_BLOCKDATA" unless byte == TC_BLOCKDATA
  end
  
  data = @str.read(size)
  byte = readByte
  raise SerializationError, "Unexpected byte #{byte}" unless byte == TC_ENDBLOCKDATA
  data
end

#readBoolObject



187
# File 'lib/javaobs.rb', line 187

def readBool; @str.read(1)[0] != 0; end

#readByteObject



180
# File 'lib/javaobs.rb', line 180

def readByte; @str.read(1)[0]; end

#readClassAnnotationObject

Read the class annotation. We do not currently handle annotations.

Raises:



229
230
231
232
# File 'lib/javaobs.rb', line 229

def readClassAnnotation
  ebd = readByte
  raise SerializationError, "We do not handle annotations!" unless ebd == TC_ENDBLOCKDATA
end

#readClassData(klass, object = nil) ⇒ Object

Read class data and recursively read parent classes.



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/javaobs.rb', line 333

def readClassData(klass, object = nil)
  # Handle special case for Date
  if object == nil
    if (klass.javaName == 'java.util.Date')
      object = Java::Date.new
    else
      object = klass.rubyClass.new()
    end
    @objects << object
  end
  
  readClassData(klass.superClass, object) if (klass.superClass)
  
  if klass.flags == SC_SERIALIZABLE
    klass.fields.each do |f|
      v = readType(f.type, f.subtype, f)
      object.send((f.name + '=').intern, v)
    end
  else
    data = readBlockData
    object.time = data
  end
  
  object
end

#readClassDescObject

Read the Java class description and create a Ruby class to proxy it in this name-space. Added special handling for the Date class.



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/javaobs.rb', line 236

def readClassDesc
  name = readString
  uid = readUID
  flags = readByte
  klass = JavaClass.new(name, uid, flags)
  
  @objects << klass
  
  readFields(klass)
  readClassAnnotation
  
  klass.superClass = readObject

  # Create Ruby object representing class
  if name == 'java.util.Date'
    rclass = Java::Date
    rclass.class_eval "@javaClass = klass"
    klass.rubyClass = rclass
  elsif name =~ /^[A-Z.]+/i
    unless Java.constants.index(klass.name)
      rclass = Java.module_eval "#{klass.name} = Class.new(#{klass.superClass.to_s})"
    else
      rclass = Java.const_get(klass.name)
    end

    unless rclass.methods.index('javaClass')
      rclass.class_eval "extend JavaObject"
    end
    
    rclass.class_eval "@javaClass = klass"
    vars = klass.fields.map do |f|
      ':' + f.name
    end
    rclass.class_eval "attr_accessor #{vars.join(',')}"
    klass.rubyClass = rclass
  else
    # Arrays
    newName = 'JavaArray' + klass.name[1..klass.name.length]
    unless Java.constants.index(newName)
      rclass = Java.module_eval "#{newName} = Class.new(JavaArray)"
    else
      rclass = Java.const_get(newName)
    end
    rclass.class_eval "@javaClass = klass"
    klass.rubyClass = rclass
  end
  
  klass
end

#readDoubleObject



184
# File 'lib/javaobs.rb', line 184

def readDouble; @str.read(8).unpack("G")[0]; end

#readFields(klass) ⇒ Object

Read all the fields from the stream and add them to the class.



213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/javaobs.rb', line 213

def readFields(klass)
  fieldCount = readShort
  1.upto(fieldCount) do
    type = readByte
    name = readString
    field = JavaField.new(name, type)
    
    # Check for array and object types
    if type == PRIM_OBJECT || type == PRIM_ARRAY
      field.subtype = readObject
    end
    klass.addField(field)
  end
end

#readFloatObject



185
# File 'lib/javaobs.rb', line 185

def readFloat; @str.read(4).unpack("g")[0]; end

#readIntObject



183
# File 'lib/javaobs.rb', line 183

def readInt; @str.read(4).unpack("i")[0]; end

#readLongObject



189
# File 'lib/javaobs.rb', line 189

def readLong; @str.read(8).unpack("Q").first; end

#readObjectObject

Read an object from the stream.



360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
# File 'lib/javaobs.rb', line 360

def readObject
  object = nil
  byte = readByte
  case byte
  when TC_OBJECT
    klass = readObject
    object = readClassData(klass)
    
  when TC_REFERENCE
    readShort
    object = @objects[readShort]
    
  when TC_ARRAY
    klass = readObject
    object = readArray(klass)
    @objects << object
    
  when TC_STRING
    object = readString
    @objects << object

  when TC_CLASSDESC
    object = readClassDesc

  when TC_NULL
    object = nil
    
  else
    raise SerializationError, "Unexpected byte #{byte} at #{@str.pos}"
  end

  object
end

#readObjectsObject

Read all objects in the stream. Calls readObject until the stream eof is reached.



408
409
410
411
412
413
414
# File 'lib/javaobs.rb', line 408

def readObjects
  objs = []
  until (@str.eof)
    objs << readObject
  end
  objs
end

#readShortObject



182
# File 'lib/javaobs.rb', line 182

def readShort; @str.read(2).unpack("s")[0]; end

#readStringObject



186
# File 'lib/javaobs.rb', line 186

def readString; @str.read(readShort); end

#readType(type, arrayType = nil, field = nil) ⇒ Object

Read a primitive data type.



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/javaobs.rb', line 298

def readType(type, arrayType = nil, field = nil)
  case type
  when PRIM_BYTE
    readByte
    
  when PRIM_CHAR
    readByte
    
  when PRIM_DOUBLE
    readDouble
    
  when PRIM_FLOAT
    readFloat
    
  when PRIM_INT
    readInt
    
  when PRIM_LONG
    readLong
    
  when PRIM_SHORT
    readShort
    
  when PRIM_BOOL
    readBool
    
  when PRIM_OBJECT, PRIM_ARRAY
    readObject
    
  else
    raise SerializationError, "Unknown type #{type}"
  end
end

#readUIDObject



188
# File 'lib/javaobs.rb', line 188

def readUID; @str.read(8); end

#readUShortObject



181
# File 'lib/javaobs.rb', line 181

def readUShort; @str.read(2).unpack("n")[0]; end