Merge pull request #17988 from ktoso/wip-javadsl-handleWith-ktoso

!htp #17965 more consistent and 22-ified javadsl handleWith
This commit is contained in:
Konrad Malawski 2015-07-15 12:22:46 +02:00
commit 77d3e693c5
27 changed files with 339 additions and 272 deletions

View file

@ -1,157 +0,0 @@
/*
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.http.javadsl;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.server.*;
import akka.http.javadsl.server.values.Parameters;
import akka.http.javadsl.server.values.PathMatchers;
import akka.http.javadsl.testkit.JUnitRouteTest;
import akka.http.javadsl.testkit.TestRoute;
import org.junit.Test;
public class HandlerExampleSpec extends JUnitRouteTest {
@Test
public void testSimpleHandler() {
//#simple-handler-example-full
class TestHandler extends akka.http.javadsl.server.AllDirectives {
//#simple-handler
Handler handler = new Handler() {
@Override
public RouteResult handle(RequestContext ctx) {
return ctx.complete("This was a " + ctx.request().method().value() +
" request to "+ctx.request().getUri());
}
};
//#simple-handler
Route createRoute() {
return route(
get(
handleWith(handler)
),
post(
path("abc").route(
handleWith(handler)
)
)
);
}
}
// actual testing code
TestRoute r = testRoute(new TestHandler().createRoute());
r.run(HttpRequest.GET("/test"))
.assertStatusCode(200)
.assertEntity("This was a GET request to /test");
r.run(HttpRequest.POST("/test"))
.assertStatusCode(404);
r.run(HttpRequest.POST("/abc"))
.assertStatusCode(200)
.assertEntity("This was a POST request to /abc");
//#simple-handler-example-full
}
@Test
public void testCalculator() {
//#handler2-example-full
class TestHandler extends akka.http.javadsl.server.AllDirectives {
RequestVal<Integer> xParam = Parameters.intValue("x");
RequestVal<Integer> yParam = Parameters.intValue("y");
RequestVal<Integer> xSegment = PathMatchers.intValue();
RequestVal<Integer> ySegment = PathMatchers.intValue();
//#handler2
Handler2<Integer, Integer> multiply =
new Handler2<Integer, Integer>() {
@Override
public RouteResult handle(RequestContext ctx, Integer x, Integer y) {
int result = x * y;
return ctx.complete("x * y = " + result);
}
};
Route multiplyXAndYParam = handleWith(xParam, yParam, multiply);
//#handler2
Route createRoute() {
return route(
get(
pathPrefix("calculator").route(
path("multiply").route(
multiplyXAndYParam
),
path("path-multiply", xSegment, ySegment).route(
handleWith(xSegment, ySegment, multiply)
)
)
)
);
}
}
// actual testing code
TestRoute r = testRoute(new TestHandler().createRoute());
r.run(HttpRequest.GET("/calculator/multiply?x=12&y=42"))
.assertStatusCode(200)
.assertEntity("x * y = 504");
r.run(HttpRequest.GET("/calculator/path-multiply/23/5"))
.assertStatusCode(200)
.assertEntity("x * y = 115");
//#handler2-example-full
}
@Test
public void testCalculatorReflective() {
//#reflective-example-full
class TestHandler extends akka.http.javadsl.server.AllDirectives {
RequestVal<Integer> xParam = Parameters.intValue("x");
RequestVal<Integer> yParam = Parameters.intValue("y");
RequestVal<Integer> xSegment = PathMatchers.intValue();
RequestVal<Integer> ySegment = PathMatchers.intValue();
//#reflective
public RouteResult multiply(RequestContext ctx, Integer x, Integer y) {
int result = x * y;
return ctx.complete("x * y = " + result);
}
Route multiplyXAndYParam = handleWith(this, "multiply", xParam, yParam);
//#reflective
Route createRoute() {
return route(
get(
pathPrefix("calculator").route(
path("multiply").route(
multiplyXAndYParam
),
path("path-multiply", xSegment, ySegment).route(
handleWith(this, "multiply", xSegment, ySegment)
)
)
)
);
}
}
// actual testing code
TestRoute r = testRoute(new TestHandler().createRoute());
r.run(HttpRequest.GET("/calculator/multiply?x=12&y=42"))
.assertStatusCode(200)
.assertEntity("x * y = 504");
r.run(HttpRequest.GET("/calculator/path-multiply/23/5"))
.assertStatusCode(200)
.assertEntity("x * y = 115");
//#reflective-example-full
}
}

View file

@ -32,12 +32,12 @@ public class HighLevelServerExample extends HttpApp {
public Route createRoute() {
// This handler generates responses to `/hello?name=XXX` requests
Route helloRoute =
handleWith(name,
handleWith1(name,
// in Java 8 the following becomes simply
// (ctx, name) -> ctx.complete("Hello " + name + "!")
new Handler1<String>() {
@Override
public RouteResult handle(RequestContext ctx, String name) {
public RouteResult apply(RequestContext ctx, String name) {
return ctx.complete("Hello " + name + "!");
}
});

View file

@ -28,7 +28,7 @@ import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;
public class HttpServerExampleSpec {
public class HttpServerExampleDocTest {
public static void bindingExample() {
//#binding-example
ActorSystem system = ActorSystem.create();

View file

@ -44,7 +44,7 @@ public class PathDirectiveExampleTest extends JUnitRouteTest {
Handler1<Integer> completeWithUserId =
new Handler1<Integer>() {
@Override
public RouteResult handle(RequestContext ctx, Integer userId) {
public RouteResult apply(RequestContext ctx, Integer userId) {
return ctx.complete("Hello user " + userId);
}
};

View file

@ -7,10 +7,10 @@ Handlers implement the actual application-defined logic for a certain trace in t
the routing tree will be routes created from handlers. Creating a ``Route`` from a handler is achieved using the
``BasicDirectives.handleWith`` overloads. They come in several forms:
* with a single ``Handler`` argument
* with a number ``n`` of ``RequestVal<T1>`` arguments and a ``HandlerN<T1, .., TN>`` argument
* with a ``Class<?>`` and/or instance and a method name String argument and a variable number of ``RequestVal<?>``
arguments
* with a single ``Handler`` argument and a variable number of ``RequestVal<?>`` (may be 0)
* with a number ``n`` of ``RequestVal<T1>`` arguments and a ``HandlerN<T1, .., TN>`` argument
* with a ``Class<?>`` and/or instance and a method name String argument and a variable number of ``RequestVal<?>`` (may be 0)
arguments
Simple Handler
--------------
@ -24,7 +24,7 @@ by inspecting the ``RequestContext`` and returning a ``RouteResult``:
Such a handler inspects the ``RequestContext`` it receives and uses the ``RequestContext``'s methods to
create a response:
.. includecode:: ../../code/docs/http/javadsl/HandlerExampleSpec.java
.. includecode:: /../../akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: simple-handler
The handler can include any kind of logic but must return a ``RouteResult`` in the end which can only
@ -32,7 +32,7 @@ be created by using one of the ``RequestContext`` methods.
A handler instance can be used once or several times as shown in the full example:
.. includecode:: ../../code/docs/http/javadsl/HandlerExampleSpec.java
.. includecode:: /../../akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: simple-handler-example-full
Handlers and Request Values
@ -42,14 +42,14 @@ In many cases, instead of manually inspecting the request, a handler will make u
to extract details from the request. This is possible using one of the other ``handleWith`` overloads that bind
the values of one or more request values with a ``HandlerN`` instance to produce a ``Route``:
.. includecode:: ../../code/docs/http/javadsl/HandlerExampleSpec.java
.. includecode:: /../../akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: handler2
The handler here implements multiplication of two integers. However, it doesn't need to specify where these
parameters come from. In ``handleWith``, as many request values of the matching type have to be specified as the
handler needs. This can be seen in the full example:
.. includecode:: ../../code/docs/http/javadsl/HandlerExampleSpec.java
.. includecode:: /../../akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: handler2-example-full
Here, the handler is again being reused. First, in creating a route that expects URI parameters ``x`` and ``y``. This
@ -59,27 +59,44 @@ route structure, this time representing segments from the URI path.
Handlers in Java 8
------------------
In Java 8 handlers can be provided as function literals. The previous example can then be written like this:
Handlers are in fact simply classes which extend ``akka.japi.function.FunctionN`` in order to make reasoning
about the number of handled arguments easier. For example, a :class:`Handler1[String]` is simply a
``Function2[RequestContext, String, RouteResult]``. You can think of handlers as hot-dogs, where each ``T``
type represents a sausage, put between the "buns" which are ``RequestContext`` and ``RouteResult``.
In Java 8 handlers can be provided as function literals or method references. The example from before then looks like this:
.. includecode:: /../../akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: handler2-java8-example-full
.. note::
The reason the ``handleWith##`` methods include the number of handled values is because otherwise (if overloading would
be used, for all 22 methods) error messages generated by ``javac`` end up being very long and not readable, i.e.
if one type of a handler does not match the given values, *all* possible candidates would be printed in the error message
(22 of them), instead of just the one arity-matching method, pointing out that the type does not match.
We opted for better error messages as we feel this is more helpful when developing applications,
instead of having one overloaded method which looks nice when everything works, but procudes hard to read error
messages if something does not match up.
.. includecode:: /../../akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleSpec.java
:include: handler2-example-full
Providing Handlers by Reflection
--------------------------------
Using Java before Java 8, writing out handlers as (anonymous) classes can be unwieldy. Therefore, ``handleWith``
Using Java before Java 8, writing out handlers as (anonymous) classes can be unwieldy. Therefore, ``handleReflectively``
overloads are provided that allow writing handler as simple methods and specifying them by name:
.. includecode:: ../../code/docs/http/javadsl/HandlerExampleSpec.java
.. includecode:: /../../akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: reflective
The complete calculator example can then be written like this:
.. includecode:: ../../code/docs/http/javadsl/HandlerExampleSpec.java
.. includecode:: /../../akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
:include: reflective-example-full
There are alternative overloads for ``handleWith`` that take a ``Class`` instead of an object instance to refer to
There are alternative overloads for ``handleReflectively`` that take a ``Class`` instead of an object instance to refer to
static methods. The referenced method must be publicly accessible.
Deferring Result Creation

View file

@ -7,7 +7,7 @@ The Akka HTTP :ref:`http-low-level-server-side-api-java` provides a ``Flow``- or
an application to respond to incoming HTTP requests by simply mapping requests to responses
(excerpt from :ref:`Low-level server side example <http-low-level-server-side-example-java>`):
.. includecode:: ../../code/docs/http/javadsl/HttpServerExampleSpec.java
.. includecode:: ../../code/docs/http/javadsl/HttpServerExampleDocTest.java
:include: request-handler
While it'd be perfectly possible to define a complete REST API service purely by inspecting the incoming

View file

@ -62,7 +62,7 @@ Starting and Stopping
On the most basic level an Akka HTTP server is bound by invoking the ``bind`` method of the `akka.http.javadsl.Http`_
extension:
.. includecode:: ../../code/docs/http/javadsl/HttpServerExampleSpec.java
.. includecode:: ../../code/docs/http/javadsl/HttpServerExampleDocTest.java
:include: binding-example
Arguments to the ``Http().bind`` method specify the interface and port to bind to and register interest in handling
@ -99,7 +99,7 @@ Requests are handled by calling one of the ``handleWithXXX`` methods with a hand
Here is a complete example:
.. includecode:: ../../code/docs/http/javadsl/HttpServerExampleSpec.java
.. includecode:: ../../code/docs/http/javadsl/HttpServerExampleDocTest.java
:include: full-server-example
In this example, a request is handled by transforming the request stream with a function ``Function<HttpRequest, HttpResponse>``