目次

Version 2, last updated by pbernet at Nov 27 20:17 UTC

This wiki entry was originally written by Timothy Perrett and was lifted with permission from his blog which can be found at blog.getintheloop.eu

I was just looking at the Lift’s StreamingResponse and was a bit bemused by the structural type being used for the first parameter. After some fiddling around I realized that:

data: {def read(buf: Array[Byte]): Int}

This will actually make the method more flexible and not tied to a particular hierarchy of classes (and super classes). So, if your looking at Lift’s StreamingResponse and thinking “what the hell”, all you need to remember is that you can pass any thing into the first parameter as long as it implements the read method with the above signature. This, IMO, is major cool. The default thing that implements this signature is java.io.InputStream, but you could of course pass anything – even your own custom classes!

A sample implementation might look like:

var data: Array[Byte] = // get your data here
val headers = 
    ("Content-type" -> "application/pdf") :: 
    ("Content-length" -> data.length.toString) :: 
    ("Content-disposition" -> "attachment; filname=download.pdf") 
    :: Nil
Full(StreamingResponse(
  new java.io.ByteArrayInputStream(data),
  () => {},
  data.length, 
  headers, Nil, 200)
)

So, to recap, structural types are awesome!

Context
If you want to get familiar with the concepts around LiftResponse and DispatchPF, make sure you have read
the up-to-date version of of Exploring Lift

  • Chapter Kap. 3.8 Custom Dispatch Functions
  • Chapter Kap. 9.4 LiftResponse in Detail