Add comprehensive Javadoc documentation to server components, including annotations, request/response handling, routing, and WebSocket support.
This commit is contained in:
@@ -9,15 +9,63 @@ import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Reflective registrar that wires the routing annotations on a controller object into a
|
||||
* {@link Router}.
|
||||
*
|
||||
* <p>Given a controller instance, the scanner reads the optional {@link Controller} annotation
|
||||
* to determine a path prefix, then walks every declared method looking for one of the
|
||||
* supported route annotations ({@link Route}, {@link GET}, {@link POST}, {@link PUT},
|
||||
* {@link DELETE}, {@link PATCH} or {@link CUSTOM}). For each matching method it:</p>
|
||||
* <ol>
|
||||
* <li>validates that the method has the required {@code (Request, Response)} signature and
|
||||
* a {@code void} return type;</li>
|
||||
* <li>creates a {@link MethodHandle} bound to the controller instance for fast,
|
||||
* reflection-free invocation;</li>
|
||||
* <li>registers a {@link Router.Handler} that delegates to that handle under the resolved
|
||||
* HTTP method and full path.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>This class is a stateless utility and cannot be instantiated.</p>
|
||||
*
|
||||
* @see Controller
|
||||
* @see Router
|
||||
*/
|
||||
public final class AnnotationScanner {
|
||||
|
||||
/**
|
||||
* Shared lookup used to unreflect controller methods into {@link MethodHandle}s. A single
|
||||
* lookup is sufficient because the scanner forces accessibility on each method before
|
||||
* unreflecting it.
|
||||
*/
|
||||
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
|
||||
|
||||
/**
|
||||
* The exact method type every handler must conform to: {@code void (Request, Response)}.
|
||||
* Used as documentation of the contract enforced by {@link #validateSignature(Method)}.
|
||||
*/
|
||||
private static final MethodType HANDLER_TYPE =
|
||||
MethodType.methodType(void.class, Request.class, Response.class);
|
||||
|
||||
/**
|
||||
* Private constructor preventing instantiation of this stateless utility class.
|
||||
*/
|
||||
private AnnotationScanner() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given controller for route annotations and registers every discovered handler
|
||||
* with the supplied router.
|
||||
*
|
||||
* <p>If the controller class is annotated with {@link Controller}, its value is used as a
|
||||
* path prefix for all routes. Methods without a recognised route annotation are ignored.
|
||||
* A line describing each registered route is printed to standard output.</p>
|
||||
*
|
||||
* @param router the router to register the discovered handlers with
|
||||
* @param controller the controller instance whose annotated methods should be registered
|
||||
* @throws IllegalArgumentException if an annotated method has an invalid signature
|
||||
* @throws RuntimeException if a method cannot be made accessible or unreflected
|
||||
*/
|
||||
public static void register(Router router, Object controller) {
|
||||
Class<?> clazz = controller.getClass();
|
||||
Controller ctrlAnno = clazz.getAnnotation(Controller.class);
|
||||
@@ -55,11 +103,27 @@ public final class AnnotationScanner {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a controller-level path prefix by ensuring it starts with a single leading
|
||||
* slash.
|
||||
*
|
||||
* @param p the raw prefix from the {@link Controller} annotation, may be {@code null} or empty
|
||||
* @return the normalized prefix, or an empty string if {@code p} is {@code null} or empty
|
||||
*/
|
||||
private static String normalizePrefix(String p) {
|
||||
if (p == null || p.isEmpty()) return "";
|
||||
return p.startsWith("/") ? p : "/" + p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts route metadata (HTTP method and path) from a method by inspecting the supported
|
||||
* route annotations in priority order. {@link Route} is checked first, followed by the
|
||||
* verb-specific annotations and finally {@link CUSTOM}.
|
||||
*
|
||||
* @param m the method to inspect
|
||||
* @return a {@link RouteInfo} describing the route, or {@code null} if the method carries
|
||||
* no recognised route annotation
|
||||
*/
|
||||
private static RouteInfo extractRoute(Method m) {
|
||||
Route r = m.getAnnotation(Route.class);
|
||||
if (r != null) return new RouteInfo(r.method(), r.path());
|
||||
@@ -75,16 +139,24 @@ public final class AnnotationScanner {
|
||||
|
||||
DELETE del = m.getAnnotation(DELETE.class);
|
||||
if (del != null) return new RouteInfo("DELETE", del.value());
|
||||
|
||||
|
||||
PATCH patch = m.getAnnotation(PATCH.class);
|
||||
if (patch != null) return new RouteInfo("PATCH", patch.value());
|
||||
|
||||
|
||||
CUSTOM custom = m.getAnnotation(CUSTOM.class);
|
||||
if (custom != null) return new RouteInfo(custom.method(), custom.value());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a handler method conforms to the required {@code void (Request, Response)}
|
||||
* contract.
|
||||
*
|
||||
* @param m the method to validate
|
||||
* @throws IllegalArgumentException if the method does not take exactly a {@link Request}
|
||||
* and a {@link Response}, or does not return {@code void}
|
||||
*/
|
||||
private static void validateSignature(Method m) {
|
||||
Class<?>[] params = m.getParameterTypes();
|
||||
if (params.length != 2 || params[0] != Request.class || params[1] != Response.class) {
|
||||
@@ -95,11 +167,23 @@ public final class AnnotationScanner {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a route-level path by ensuring it starts with a single leading slash.
|
||||
*
|
||||
* @param p the raw path from a route annotation, may be {@code null} or empty
|
||||
* @return the normalized path, or an empty string if {@code p} is {@code null} or empty
|
||||
*/
|
||||
private static String normalizePath(String p) {
|
||||
if (p == null || p.isEmpty()) return "";
|
||||
return p.startsWith("/") ? p : "/" + p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Immutable carrier for the HTTP method and path extracted from a route annotation.
|
||||
*
|
||||
* @param method the HTTP method name (e.g. {@code "GET"})
|
||||
* @param path the route path relative to the controller prefix
|
||||
*/
|
||||
private record RouteInfo(String method, String path) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user