Skip to content

Commit 0391a0f

Browse files
committed
Add dynamic method binding
1 parent 072ead4 commit 0391a0f

File tree

4 files changed

+172
-2
lines changed

4 files changed

+172
-2
lines changed

README.md

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ app.get("/", (req, res) -> {
4141

4242
# Docs:
4343
* [Routing](#routing)
44+
* [DynExpress](#dynexpress)
4445
* [Direct](#direct)
4546
* [With Router](#with-router)
4647
* [URL Basics](#url-basics)
@@ -49,7 +50,7 @@ app.get("/", (req, res) -> {
4950
* [URL Querys](#url-querys)
5051
* [Cookies](#cookies)
5152
* [Form Data](#form-data)
52-
* [HTTP - Main Classes](#http---main-classes)
53+
* [HTTP Relevant classes](#http-relevant-classes)
5354
* [Response Object](#response-object)
5455
* [Request Object](#request-object)
5556
* [Middleware](#middleware)
@@ -59,6 +60,52 @@ app.get("/", (req, res) -> {
5960
* [Examples](#examples)
6061

6162
# Routing
63+
## DynExpress
64+
Express allows the attaching of request-handler to instance methods via the DynExpress annotation:
65+
```java
66+
67+
// Your main class
68+
import express.Express;
69+
public class Main {
70+
public static void main(String[] args) {
71+
Express app = new Express();
72+
app.bind(new Bindings()); // See class below
73+
app.listen();
74+
}
75+
}
76+
77+
// Your class with request handlers
78+
import express.DynExpress;
79+
import express.http.RequestMethod;
80+
import express.http.request.Request;
81+
import express.http.response.Response;
82+
public class Bindings {
83+
84+
@DynExpress() // Default is context="/" and method=RequestMethod.GET
85+
public void getIndex(Request req, Response res) {
86+
res.send("Hello World!");
87+
}
88+
89+
@DynExpress(context = "/about") // Only context is defined, method=RequestMethod.GET is used as method
90+
public void getAbout(Request req, Response res) {
91+
res.send("About page");
92+
}
93+
94+
@DynExpress(context = "/impressum", method = RequestMethod.PATCH) // Both defined
95+
public void getImpressum(Request req, Response res) {
96+
res.send("Impressum page was patched");
97+
}
98+
99+
@DynExpress(method = RequestMethod.POST) // Only the method is defined, "/" is used as context
100+
public void postIndex(Request req, Response res) {
101+
res.send("POST to index");
102+
}
103+
}
104+
105+
106+
```
107+
108+
62109
## Direct
63110
You can add routes (And middlewares) directly to the Express object to handle requests:
64111
```java
@@ -216,7 +263,7 @@ app.post("/register", (req, res) -> {
216263
});
217264
```
218265

219-
# HTTP - Main Classes
266+
# HTTP Relevant classes
220267
## Express
221268
This class represents the entire HTTP-Server, the available methods are:
222269
```java
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package express;
2+
3+
import express.http.RequestMethod;
4+
5+
import java.lang.annotation.ElementType;
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.RetentionPolicy;
8+
import java.lang.annotation.Target;
9+
10+
/**
11+
* @author Simon Reinisch
12+
* Annotation to use object methods as request handler.
13+
*/
14+
@Retention(RetentionPolicy.RUNTIME)
15+
@Target(ElementType.METHOD)
16+
public @interface DynExpress {
17+
RequestMethod method() default RequestMethod.GET;
18+
19+
String context() default "/";
20+
}

src/main/java/express/Express.java

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import express.filter.FilterTask;
99
import express.filter.FilterWorker;
1010
import express.http.HttpRequestHandler;
11+
import express.http.request.Request;
12+
import express.http.response.Response;
1113

1214
import java.io.IOException;
1315
import java.lang.reflect.InvocationTargetException;
@@ -236,6 +238,75 @@ public Express patch(String context, HttpRequestHandler request) {
236238
return this;
237239
}
238240

241+
/**
242+
* Binds a or multiple objects with request-handler methods on this express instance.
243+
* With the use of the DynExpress Annotation handler can be declared with a annotation
244+
* on a compatible method which has as parameter a Request and Response object.
245+
*
246+
* @param objects Object with proper request handler methods.
247+
* @return This express instance.
248+
*/
249+
public Express bind(Object... objects) {
250+
for (Object o : objects) {
251+
252+
// Skip null objects
253+
if (o == null) {
254+
continue;
255+
}
256+
257+
// Find methods wich has the DynExpress annotation
258+
Method[] methods = o.getClass().getDeclaredMethods();
259+
for (Method method : methods) {
260+
261+
// Validate parameter types
262+
Class<?>[] params = method.getParameterTypes();
263+
if (params.length < 1 || params[0] != Request.class || params[1] != Response.class) {
264+
StringBuilder sb = new StringBuilder();
265+
for (Class<?> c : params) {
266+
sb.append(c.getSimpleName());
267+
sb.append(", ");
268+
}
269+
270+
String paramString = sb.toString();
271+
if (paramString.length() > 2) {
272+
paramString = paramString.substring(0, paramString.length() - 2);
273+
}
274+
275+
System.err.println("Skipped method with invalid parameter types found in " +
276+
method.getName() + "(" + paramString + ") in " + o.getClass().getName() +
277+
". Expected Request and Response.");
278+
continue;
279+
}
280+
281+
// Make private method accessible
282+
if (!method.isAccessible()) {
283+
method.setAccessible(true);
284+
}
285+
286+
// Check if dyn-annotation is present
287+
if (method.isAnnotationPresent(DynExpress.class)) {
288+
DynExpress[] annotations = method.getAnnotationsByType(DynExpress.class);
289+
290+
for (DynExpress dex : annotations) {
291+
String context = dex.context();
292+
String requestMethod = dex.method().getMethod();
293+
294+
// Bind to instance
295+
handler.add(1, new FilterImpl(requestMethod, context, (req, res) -> {
296+
try {
297+
method.invoke(o, req, res);
298+
} catch (IllegalAccessException | InvocationTargetException e) {
299+
e.printStackTrace();
300+
}
301+
}));
302+
}
303+
}
304+
}
305+
}
306+
307+
return this;
308+
}
309+
239310
/**
240311
* Start the HTTP-Server on port 80.
241312
* This method is asynchronous so be sure to add an listener or keep it in mind!
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package express.http;
2+
3+
/**
4+
* @author Simon Reinisch
5+
* Enum with basic requestmethods.
6+
*/
7+
public enum RequestMethod {
8+
9+
// Real request methods
10+
GET("GET"),
11+
POST("POST"),
12+
PUT("PUT"),
13+
PATCH("PATCH"),
14+
DELETE("DELETE"),
15+
CONNECT("CONNECT"),
16+
OPTIONS("OPTIONS"),
17+
TRACE("TRACE"),
18+
HEAD("HEAD"),
19+
20+
// Express specific method which will catch every method
21+
ALL("*");
22+
23+
private String method;
24+
25+
RequestMethod(String method) {
26+
this.method = method;
27+
}
28+
29+
public String getMethod() {
30+
return method;
31+
}
32+
}

0 commit comments

Comments
 (0)