aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/foo/zaaarf/routecompass
diff options
context:
space:
mode:
author zaaarf <me@zaaarf.foo>2024-01-23 10:57:46 +0100
committer zaaarf <me@zaaarf.foo>2024-01-23 10:57:46 +0100
commit47b45e2e42241c59011276572181c6efd016a378 (patch)
treed0c7336eed3918d0ab3f97687f87ba8b3fe1226e /src/main/java/foo/zaaarf/routecompass
parent729bf6f2a752bf16724401eed5f470276fd38a39 (diff)
feat: request/response dto support0.1.1
Diffstat (limited to 'src/main/java/foo/zaaarf/routecompass')
-rw-r--r--src/main/java/foo/zaaarf/routecompass/Route.java44
-rw-r--r--src/main/java/foo/zaaarf/routecompass/RouteCompass.java64
2 files changed, 98 insertions, 10 deletions
diff --git a/src/main/java/foo/zaaarf/routecompass/Route.java b/src/main/java/foo/zaaarf/routecompass/Route.java
index db1492a..7c7c091 100644
--- a/src/main/java/foo/zaaarf/routecompass/Route.java
+++ b/src/main/java/foo/zaaarf/routecompass/Route.java
@@ -35,6 +35,16 @@ public class Route {
public final boolean deprecated;
/**
+ * A {@link DTO} representing the response body.
+ */
+ public final DTO returnType;
+
+ /**
+ * A {@link DTO} representing the request body.
+ */
+ public final DTO inputType;
+
+ /**
* An array of {@link Param}s, representing parameters accepted by the endpoint.
*/
public final Param[] params;
@@ -48,8 +58,8 @@ public class Route {
* @param deprecated whether the endpoint is deprecated
* @param params {@link Param}s of the endpoint, may be null
*/
- public Route(String path, RequestMethod[] methods, MediaType consumes, MediaType produces, boolean deprecated,
- Param... params) {
+ public Route(String path, RequestMethod[] methods, MediaType consumes, MediaType produces,
+ boolean deprecated, DTO returnType, DTO inputType, Param... params) {
this.path = path;
StringBuilder methodStringBuilder = new StringBuilder("[");
@@ -70,6 +80,9 @@ public class Route {
this.deprecated = deprecated;
+ this.returnType = returnType;
+ this.inputType = inputType;
+
if(params != null) this.params = params;
else this.params = new Param[0]; //just in case
}
@@ -106,4 +119,31 @@ public class Route {
this.defaultValue = defaultValue;
}
}
+
+ /**
+ * Representation of a DTO type.
+ */
+ public static class DTO {
+
+ /**
+ * Fully-qualified name of the type.
+ */
+ public final String FQN;
+
+ /**
+ * An array of {@link Param} representing the type's fields.
+ */
+ public final Route.Param[] fields;
+
+ /**
+ * The one and only constructor.
+ * @param FQN the fully-qualified name
+ * @param fields the {@link Param}s representing the fields
+ */
+ public DTO(String FQN, Route.Param ... fields) {
+ this.FQN = FQN;
+ if(fields == null) this.fields = new Route.Param[0];
+ else this.fields = fields;
+ }
+ }
}
diff --git a/src/main/java/foo/zaaarf/routecompass/RouteCompass.java b/src/main/java/foo/zaaarf/routecompass/RouteCompass.java
index 0847002..58c0d89 100644
--- a/src/main/java/foo/zaaarf/routecompass/RouteCompass.java
+++ b/src/main/java/foo/zaaarf/routecompass/RouteCompass.java
@@ -11,6 +11,8 @@ import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
@@ -18,6 +20,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.util.*;
+import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
@@ -58,6 +61,7 @@ public class RouteCompass extends AbstractProcessor {
* @return false, letting other processor process the annotations again
*/
@Override
+ @SuppressWarnings("OptionalGetWithoutIsPresent")
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
for(TypeElement annotationType : annotations) {
env.getElementsAnnotatedWith(annotationType)
@@ -73,7 +77,11 @@ public class RouteCompass extends AbstractProcessor {
this.getConsumedType(annotationType, elem),
this.getProducedType(annotationType, elem),
this.isDeprecated(elem),
- this.getParams(elem.getParameters())
+ this.getDTO(this.processingEnv.getTypeUtils().asElement(elem.getReturnType())),
+ this.getDTO(elem.getParameters().stream()
+ .filter(e -> e.getAnnotation(RequestBody.class) != null)
+ .findFirst().get()),
+ this.getQueryParams(elem.getParameters())
));
});
}
@@ -96,12 +104,24 @@ public class RouteCompass extends AbstractProcessor {
if(r.produces != null) out.print("(returns: " + r.produces + ")");
out.println();
- for(Route.Param p : r.params) {
- out.print("\t\t- " + p.typeFQN + " " + p.name);
- if(p.defaultValue != null)
- out.print(" " + "(default: " + p.defaultValue + ")");
- out.println();
- }
+ BiConsumer<String, Route.Param[]> printParam = (name, params) -> {
+ if(name != null) out.println("\t\t" + name);
+ for(Route.Param p : params) {
+ out.print(name != null ? "\t\t\t" : "\t\t");
+ out.print("- " + p.typeFQN + " " + p.name);
+ if(p.defaultValue != null)
+ out.print(" " + "(default: " + p.defaultValue + ")");
+ out.println();
+ }
+ };
+
+ printParam.accept(null, r.params);
+
+ if(r.inputType != null)
+ printParam.accept("input: " + r.inputType.FQN, r.inputType.fields);
+
+ if(r.returnType != null)
+ printParam.accept("output: " + r.returnType.FQN, r.returnType.fields);
}
}
@@ -198,7 +218,7 @@ public class RouteCompass extends AbstractProcessor {
* @param params the {@link VariableElement}s representing the parameters of a request
* @return an array of {@link Route.Param} representing the parameters of the request.
*/
- private Route.Param[] getParams(List<? extends VariableElement> params) {
+ private Route.Param[] getQueryParams(List<? extends VariableElement> params) {
return params.stream()
.map(p -> {
RequestParam ann = p.getAnnotation(RequestParam.class);
@@ -221,6 +241,34 @@ public class RouteCompass extends AbstractProcessor {
}
/**
+ * Gets a representation of a DTO type.
+ * @param type the {@link TypeElement} to examine
+ * @return a {@link Route.DTO} representing the given type
+ */
+ private Route.DTO getDTO(Element type) {
+ if(!(type instanceof TypeElement)) //doubles as null check
+ return null;
+
+ List<VariableElement> fieldElements = new ArrayList<>();
+ TypeElement typeElement = (TypeElement) type;
+ do {
+ fieldElements.addAll(typeElement
+ .getEnclosedElements()
+ .stream().filter(e -> e instanceof VariableElement)
+ .map(e -> (VariableElement) e)
+ .collect(Collectors.toList()));
+ TypeMirror superclass = typeElement.getSuperclass();
+ if(superclass.getKind() == TypeKind.DECLARED)
+ typeElement = (TypeElement) this.processingEnv.getTypeUtils().asElement(superclass);
+ else typeElement = null;
+ } while(typeElement != null);
+
+ return new Route.DTO(type.asType().toString(), fieldElements.stream() //TODO @JsonIgnore
+ .map(e -> new Route.Param(e.asType().toString(), e.getSimpleName().toString(), null))
+ .toArray(Route.Param[]::new));
+ }
+
+ /**
* An annotation value.
* @param annotationType the {@link TypeElement} with the annotation we are processing
* @param element the {@link Element} currently being examined