[armedbear-devel] is there a good method to read/write java byte arrays?

Alessio Stalla alessiostalla at gmail.com
Wed Mar 17 16:04:31 UTC 2010


On Wed, Mar 17, 2010 at 12:06 AM, David Kirkman <dkirkman at ucsd.edu> wrote:
> Does anybody know of a good way to serialize lisp objects into
> java byte arrays?  I've got a method that almost works, but if anybody
> has a better/canonical way of doing this I'd love to know!
>
> I've been trying to use cl-store, outputting to a stream I create with
> sys::%make-byte-array-output-stream, and then getting the byte array with
> sys::%get-output-stream-bytes.  I've only been using abcl for a few days,
> and I found those functions by grepping through the sources, so I apologize
> if I'm inviting trouble by messing around with functions you never meant users
> to play with.
>
> Anyway, the output works fine.  But I can't find the equivalent of
> sys::%make-byte-array-output-stream to create an input stream, so I
> attempted to make my own
>
> (defun make-byte-array-input-stream (bytes)
>  (let ((bis (jnew (jconstructor "java.io.ByteArrayInputStream" "[B") bytes)))
>    (jnew
>     (jconstructor "org.armedbear.lisp.Stream" "java.io.InputStream") bis)))
>
> This almost seems to work, but if I try to use it I get a java
> exception and a (very long) java stack trace.  I put a copy of
> the stack trace at the end of this message.  Here is an
> expression which will produce the problem in abcl-18.1
>
> (let ((outbytes (with-open-stream
>                 (stream (sys::%make-byte-array-output-stream))
>                 (write-byte 101 stream)
>                 (sys::%get-output-stream-bytes stream))))
>  ;; now open the byte array as an input stream
>  (with-open-stream
>   (stream (make-byte-array-input-stream outbytes))
>   ;; all works fine until here
>   (read-byte stream)))
>
> I don't need to read the stream, asking for the element type of the input
> stream is enough to cause trouble ...
>
> (let ((outbytes (with-open-stream
>                 (stream (sys::%make-byte-array-output-stream))
>                 (write-byte 101 stream)
>                 (sys::%get-output-stream-bytes stream))))
>  (with-open-stream
>   (stream (make-byte-array-input-stream outbytes))
>   (stream-element-type stream)))
>
>
> I can fix the problem and make my code work, but I have to change Stream.java
> to make it work.  I added
>
> elementType = UNSIGNED_BYTE_8;
>
> to the initAsBinaryInputStream(InputStream in) method.  I did this because
> the stack trace suggested that the problem was stream_element_type.execute()
> was returning null.
>
> Anyway, that fixes the problem, and I'm happily serializing/deserializing
> lisp objects to a Berkeley DB ... so I guess I'm happy!  But I don't know how
> rational that fix is, because I don't really know how Stream is supposed to
> work.  I suspect that my 'fix' probably breaks something else that I'm just not
> using yet.
>
> Any ideas?

I wrote sys::%make-byte-array-output-stream in order to make the
runtime compiler capable of generating bytecode without using
temporary files; it wasn't meant to be used by the ABCL user, and as
such it's not very polished (for example, the type of a
byte-array-output-stream is simply STREAM). In any case, it's defined
in the ByteArrayOutputStream Java class, and as you correctly noted,
it explicitly sets the element type to (unsigned-byte 8). As a quick
and dirty solution, you could more or less copy-paste that class and
replace "output" with "input" :) (as well as update Autoload.java to
make ABCL know of the new primitives).

We should probably polish it a bit and release it as an extension.

Alessio

> Thanks,
>
> -david k.
>
> Here's the first few lines of the stack trace ...
>
> CL-USER(2): Debugger invoked on condition of type SIMPLE-TYPE-ERROR:
> java.lang.NullPointerException
>        at org.armedbear.lisp.Primitives$49.execute(Primitives.java:795)
>        at org.armedbear.lisp.Symbol.execute(Symbol.java:781)
>        at org.armedbear.lisp.LispThread.execute(LispThread.java:579)
>        at org.armedbear.lisp.print_8.execute(print.lisp:127)
>        at org.armedbear.lisp.Symbol.execute(Symbol.java:781)
>        at org.armedbear.lisp.LispThread.execute(LispThread.java:579)
>        at org.armedbear.lisp.print_14.execute(print.lisp:279)
>
> ...  (and it ends with)
>
>        at org.armedbear.lisp.AutoloadedFunctionProxy.execute(AutoloadedFunctionProxy.java:139)
>        at org.armedbear.lisp.Symbol.execute(Symbol.java:760)
>        at org.armedbear.lisp.LispThread.execute(LispThread.java:546)
>        at org.armedbear.lisp.top_level_51.execute(top-level.lisp:415)
>        at org.armedbear.lisp.AutoloadedFunctionProxy.execute(AutoloadedFunctionProxy.java:139)
>        at org.armedbear.lisp.LispThread.execute(LispThread.java:546)
>        at org.armedbear.lisp.Interpreter.run(Interpreter.java:310)
>        at org.armedbear.lisp.Main$1.run(Main.java:50)
>        at java.lang.Thread.run(Thread.java:613)
>  READ-BYTE: unsupported element type
> Debugger invoked on condition of type ERROR:
>  Caught java.lang.NullPointerException.
> Restarts:
>  0: TOP-LEVEL Return to top level.
>
> _______________________________________________
> armedbear-devel mailing list
> armedbear-devel at common-lisp.net
> http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
>




More information about the armedbear-devel mailing list