From 09d8aac77f68bd8052933052c7cdd39f0ce6af0b Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Fri, 23 May 2025 15:38:04 -0500 Subject: [PATCH] provide default implementation in handleOutput; update newObjectFromTypeArgument to support class hierarchies of depth > 1 add AbstractMiddlewareVersion as argument to some methods add pre-execute method add getRequestBodyAsJsonObject --- .../javalin/specs/AbstractEndpointSpec.java | 92 ++++++++++++++----- 1 file changed, 69 insertions(+), 23 deletions(-) diff --git a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/AbstractEndpointSpec.java b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/AbstractEndpointSpec.java index e27c5e43..d56332b8 100644 --- a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/AbstractEndpointSpec.java +++ b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/middleware/javalin/specs/AbstractEndpointSpec.java @@ -36,6 +36,7 @@ import com.kingsrook.qqq.backend.core.exceptions.QRuntimeException; import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.utils.CollectionUtils; +import com.kingsrook.qqq.backend.core.utils.JsonUtils; import com.kingsrook.qqq.backend.core.utils.ValueUtils; import com.kingsrook.qqq.backend.javalin.QJavalinUtils; import com.kingsrook.qqq.middleware.javalin.executors.AbstractMiddlewareExecutor; @@ -81,11 +82,15 @@ public abstract class AbstractEndpointSpec< public abstract INPUT buildInput(Context context) throws Exception; + /*************************************************************************** ** build the endpoint's http response (written to the javalin context) from ** an execution output object ***************************************************************************/ - public abstract void handleOutput(Context context, OUTPUT output) throws Exception; + public void handleOutput(Context context, OUTPUT output) throws Exception + { + context.result(JsonUtils.toJson(output)); + } @@ -120,7 +125,16 @@ public abstract class AbstractEndpointSpec< { try { - Type superClass = getClass().getGenericSuperclass(); + ///////////////////////////////////////////////// + // moving up type hierarchy to find this class // + ///////////////////////////////////////////////// + Class s = getClass(); + while(!s.getSuperclass().equals(AbstractEndpointSpec.class)) + { + s = s.getSuperclass(); + } + + Type superClass = s.getGenericSuperclass(); Type actualTypeArgument = ((ParameterizedType) superClass).getActualTypeArguments()[argumentIndex]; String className = actualTypeArgument.getTypeName().replaceAll("<.*", ""); Class aClass = Class.forName(className); @@ -137,14 +151,14 @@ public abstract class AbstractEndpointSpec< /*************************************************************************** ** define a javalin route for the spec ***************************************************************************/ - public void defineRoute(String versionBasePath) + public void defineRoute(AbstractMiddlewareVersion abstractMiddlewareVersion, String versionBasePath) { CompleteOperation completeOperation = defineCompleteOperation(); String fullPath = "/qqq/" + versionBasePath + completeOperation.getPath(); fullPath = fullPath.replaceAll("/+", "/"); - final Handler handler = context -> serveRequest(context); + final Handler handler = context -> serveRequest(abstractMiddlewareVersion, context); switch(completeOperation.getHttpMethod()) { @@ -162,7 +176,7 @@ public abstract class AbstractEndpointSpec< /*************************************************************************** ** ***************************************************************************/ - public OUTPUT serveRequest(Context context) throws Exception + public OUTPUT serveRequest(AbstractMiddlewareVersion abstractMiddlewareVersion, Context context) throws Exception { try { @@ -175,6 +189,8 @@ public abstract class AbstractEndpointSpec< QContext.setQInstance(qInstance); } + abstractMiddlewareVersion.preExecute(context); + INPUT input = buildInput(context); EXECUTOR executor = newExecutor(); OUTPUT output = newOutput(); @@ -360,6 +376,53 @@ public abstract class AbstractEndpointSpec< + /*************************************************************************** + ** + ***************************************************************************/ + protected JSONObject getRequestBodyAsJsonObject(Context context) + { + RequestBody requestBody = getMemoizedRequestBody(); + if(requestBody != null) + { + String requestContentType = context.contentType(); + if(requestContentType != null) + { + requestContentType = requestContentType.toLowerCase().replaceAll(" *;.*", ""); + } + + Content contentSpec = requestContentType == null ? null : requestBody.getContent().get(requestContentType); + if(contentSpec != null && "object".equals(contentSpec.getSchema().getType())) + { + if(ContentType.APPLICATION_JSON.getMimeType().equals(requestContentType)) + { + ///////////////////////////////////////////////////////////////////////////// + // avoid re-parsing the JSON object if getting multiple attributes from it // + // by stashing it in a (request) attribute. // + ///////////////////////////////////////////////////////////////////////////// + Object jsonBodyAttribute = context.attribute("jsonBody"); + JSONObject jsonObject = null; + + if(jsonBodyAttribute instanceof JSONObject jo) + { + jsonObject = jo; + } + + if(jsonObject == null) + { + jsonObject = new JSONObject(context.body()); + context.attribute("jsonBody", jsonObject); + } + + return (jsonObject); + } + } + } + + return (null); + } + + + /*************************************************************************** ** ***************************************************************************/ @@ -404,24 +467,7 @@ public abstract class AbstractEndpointSpec< } else if(ContentType.APPLICATION_JSON.getMimeType().equals(requestContentType)) { - ///////////////////////////////////////////////////////////////////////////// - // avoid re-parsing the JSON object if getting multiple attributes from it // - // by stashing it in a (request) attribute. // - ///////////////////////////////////////////////////////////////////////////// - Object jsonBodyAttribute = context.attribute("jsonBody"); - JSONObject jsonObject = null; - - if(jsonBodyAttribute instanceof JSONObject jo) - { - jsonObject = jo; - } - - if(jsonObject == null) - { - jsonObject = new JSONObject(context.body()); - context.attribute("jsonBody", jsonObject); - } - + JSONObject jsonObject = getRequestBodyAsJsonObject(context); if(jsonObject.has(name)) { value = jsonObject.getString(name);