Initial Commit

This commit is contained in:
CodingPhoenix
2026-05-08 11:04:40 +02:00
commit 392658d54e
25 changed files with 1055 additions and 0 deletions
@@ -0,0 +1,103 @@
package dev.coph.nextusweb.server.annotation;
import dev.coph.nextusweb.server.router.Request;
import dev.coph.nextusweb.server.router.Response;
import dev.coph.nextusweb.server.router.Router;
import io.netty.handler.codec.http.HttpMethod;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
public final class AnnotationScanner {
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
private static final MethodType HANDLER_TYPE =
MethodType.methodType(void.class, Request.class, Response.class);
private AnnotationScanner() {
}
public static void register(Router router, Object controller) {
Class<?> clazz = controller.getClass();
Controller ctrlAnno = clazz.getAnnotation(Controller.class);
if (ctrlAnno == null) {
throw new IllegalArgumentException(
clazz.getName() + " ist nicht mit @Controller annotiert");
}
String prefix = normalizePrefix(ctrlAnno.value());
for (Method method : clazz.getDeclaredMethods()) {
RouteInfo info = extractRoute(method);
if (info == null) continue;
validateSignature(method);
try {
method.setAccessible(true);
MethodHandle mh = LOOKUP.unreflect(method).bindTo(controller);
Router.Handler handler = (req, res) -> {
try {
mh.invokeExact(req, res);
} catch (Throwable t) {
if (t instanceof Exception e) throw e;
throw new RuntimeException(t);
}
};
String fullPath = prefix + normalizePath(info.path());
router.register(HttpMethod.valueOf(info.method()), fullPath, handler);
System.out.printf("Registered: %-6s %-30s -> %s.%s%n",
info.method(), fullPath, clazz.getSimpleName(), method.getName());
} catch (IllegalAccessException e) {
throw new RuntimeException("Konnte Methode nicht registrieren: " + method, e);
}
}
}
private static String normalizePrefix(String p) {
if (p == null || p.isEmpty()) return "";
return p.startsWith("/") ? p : "/" + p;
}
private static RouteInfo extractRoute(Method m) {
Route r = m.getAnnotation(Route.class);
if (r != null) return new RouteInfo(r.method(), r.path());
GET get = m.getAnnotation(GET.class);
if (get != null) return new RouteInfo("GET", get.value());
POST post = m.getAnnotation(POST.class);
if (post != null) return new RouteInfo("POST", post.value());
PUT put = m.getAnnotation(PUT.class);
if (put != null) return new RouteInfo("PUT", put.value());
DELETE del = m.getAnnotation(DELETE.class);
if (del != null) return new RouteInfo("DELETE", del.value());
return null;
}
private static void validateSignature(Method m) {
Class<?>[] params = m.getParameterTypes();
if (params.length != 2 || params[0] != Request.class || params[1] != Response.class) {
throw new IllegalArgumentException(
"Handler-Methode " + m + " muss Signatur (Request, Response) haben");
}
if (m.getReturnType() != void.class) {
throw new IllegalArgumentException(
"Handler-Methode " + m + " muss void zurückgeben");
}
}
private static String normalizePath(String p) {
if (p == null || p.isEmpty()) return "";
return p.startsWith("/") ? p : "/" + p;
}
private record RouteInfo(String method, String path) {
}
}
@@ -0,0 +1,12 @@
package dev.coph.nextusweb.server.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Controller {
String value() default "";
}
@@ -0,0 +1,12 @@
package dev.coph.nextusweb.server.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DELETE {
String value();
}
@@ -0,0 +1,12 @@
package dev.coph.nextusweb.server.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface GET {
String value();
}
@@ -0,0 +1,12 @@
package dev.coph.nextusweb.server.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface POST {
String value();
}
@@ -0,0 +1,12 @@
package dev.coph.nextusweb.server.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PUT {
String value();
}
@@ -0,0 +1,14 @@
package dev.coph.nextusweb.server.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Route {
String method();
String path();
}