Unmarshalling
“Unmarshalling” is the process of converting some kind of a lower-level representation, often a “wire format”, into a higher-level (object) structure. Other popular names for it are “Deserialization” or “Unpickling”.
In Akka HTTP “Unmarshalling” means the conversion of a lower-level source object, e.g. a MessageEntity
(which forms the “entity body” of an HTTP request or response) or a full HttpRequest
or HttpResponse
, into an instance of type T
.
Basic Design
Unmarshalling of instances of type A
into instances of type B
is performed by an Unmarshaller<A, B>
.
At its core an Unmarshaller<A, B>
is very similar to a Function<A, CompletionStage<B>>
and as such quite a bit simpler than its marshalling counterpart. The process of unmarshalling does not have to support content negotiation which saves two additional layers of indirection that are required on the marshalling side.
Using unmarshallers
For an example on how to use an unmarshaller on the server side, see for example the Dynamic Routing Example. For the client side, see Processing Responses
Predefined Unmarshallers
Akka HTTP already predefines a number of unmarshallers for the most common types. Specifically these are:
StringUnmarshallers
Byte
Short
Integer
Long
Float
Double
Boolean
Unmarshaller
byte[]
ByteString
char[]
String
akka.http.javadsl.model.FormData
Additional unmarshallers are available in separate modules for specific content types, such as JSON .
Custom Unmarshallers
Akka HTTP gives you a few convenience tools for constructing unmarshallers for your own types. Usually you won’t have to “manually” implement the Unmarshaller
class directly. Rather, it should be possible to use one of the convenience construction helpers defined on Unmarshaller
:
- Scala
- Java
-
source
<A, B> Unmarshaller<A, B> async(java.util.function.Function<A, java.util.concurrent.CompletionStage<B>> f); <A, B> Unmarshaller<A, B> sync(java.util.function.Function<A, B> f); <A, B> Unmarshaller<A, B> firstOf(Unmarshaller<A, B> u1, Unmarshaller<A, B> u2); <A, B> Unmarshaller<A, B> firstOf(Unmarshaller<A, B> u1, Unmarshaller<A, B> u2, Unmarshaller<A, B> u3); <A, B> Unmarshaller<A, B> firstOf(Unmarshaller<A, B> u1, Unmarshaller<A, B> u2, Unmarshaller<A, B> u3, Unmarshaller<A, B> u4); <A, B> Unmarshaller<A, B> firstOf(Unmarshaller<A, B> u1, Unmarshaller<A, B> u2, Unmarshaller<A, B> u3, Unmarshaller<A, B> u4, Unmarshaller<A, B> u5);
To avoid unnecessary memory pressure, unmarshallers should make sure to either fully consume the incoming entity data stream, or make sure it is properly cancelled on error. Failure to do so might keep the remaining part of the stream in memory for longer than necessary.
Deriving Unmarshallers
Sometimes you can save yourself some work by reusing existing unmarshallers for your custom ones. The idea is to “wrap” an existing unmarshaller with some logic to “re-target” it to your type.
Usually what you want to do is to transform the output of some existing unmarshaller and convert it to your type. For this type of unmarshaller transformation Akka HTTP defines these methods:
baseMarshaller.thenApply
baseMarshaller.flatMap
Unmarshaller.forMediaType
(to derive from aHttpEntity
unmarshaller)Unmarshaller.forMediaTypes
(to derive from aHttpEntity
unmarshaller)
The method signatures should make their semantics relatively clear.
Using Unmarshallers
In many places throughout Akka HTTP unmarshallers are used implicitly, e.g. when you want to access the entity of a request using the Routing DSL.
However, you can also use the unmarshalling infrastructure directly if you wish, which can be useful for example in tests. The best entry point for this is the akka.http.javadsl.unmarshalling.StringUnmarshallers
class, which you can use like this:
- Scala
- Java
-
source
import akka.http.javadsl.model.*; import akka.http.javadsl.unmarshalling.StringUnmarshallers; import akka.http.javadsl.unmarshalling.Unmarshaller; import java.util.concurrent.CompletionStage; import java.util.concurrent.TimeUnit; CompletionStage<Integer> integerStage = StringUnmarshallers.INTEGER.unmarshal("42", system().dispatcher(), materializer()); int integer = integerStage.toCompletableFuture().get(1, TimeUnit.SECONDS); // don't block in non-test code! assertEquals(integer, 42); CompletionStage<Boolean> boolStage = StringUnmarshallers.BOOLEAN.unmarshal("off", system().dispatcher(), materializer()); boolean bool = boolStage.toCompletableFuture().get(1, TimeUnit.SECONDS); // don't block in non-test code! assertEquals(bool, false);