From 5c35cee2da5bf443cd9a1a74230ed3c1a5b8795f Mon Sep 17 00:00:00 2001 From: Dung Ta Van Date: Thu, 29 Jan 2026 14:11:57 +0700 Subject: [PATCH 1/4] version 1.4.8 --- ezyhttp-client/pom.xml | 2 +- ezyhttp-core/pom.xml | 2 +- ezyhttp-server-boot/pom.xml | 2 +- ezyhttp-server-core/pom.xml | 2 +- ezyhttp-server-graphql/pom.xml | 2 +- ezyhttp-server-jetty/pom.xml | 2 +- ezyhttp-server-management/pom.xml | 2 +- ezyhttp-server-thymeleaf/pom.xml | 2 +- ezyhttp-server-tomcat/pom.xml | 2 +- pom.xml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ezyhttp-client/pom.xml b/ezyhttp-client/pom.xml index 8b369df..2a5ce9f 100644 --- a/ezyhttp-client/pom.xml +++ b/ezyhttp-client/pom.xml @@ -5,7 +5,7 @@ com.tvd12 ezyhttp - 1.4.7 + 1.4.8 ezyhttp-client diff --git a/ezyhttp-core/pom.xml b/ezyhttp-core/pom.xml index 8dadc95..d94e717 100644 --- a/ezyhttp-core/pom.xml +++ b/ezyhttp-core/pom.xml @@ -5,7 +5,7 @@ com.tvd12 ezyhttp - 1.4.7 + 1.4.8 ezyhttp-core diff --git a/ezyhttp-server-boot/pom.xml b/ezyhttp-server-boot/pom.xml index f480f96..624382b 100644 --- a/ezyhttp-server-boot/pom.xml +++ b/ezyhttp-server-boot/pom.xml @@ -5,7 +5,7 @@ com.tvd12 ezyhttp - 1.4.7 + 1.4.8 ezyhttp-server-boot diff --git a/ezyhttp-server-core/pom.xml b/ezyhttp-server-core/pom.xml index 9e967d8..237c92b 100644 --- a/ezyhttp-server-core/pom.xml +++ b/ezyhttp-server-core/pom.xml @@ -5,7 +5,7 @@ com.tvd12 ezyhttp - 1.4.7 + 1.4.8 ezyhttp-server-core diff --git a/ezyhttp-server-graphql/pom.xml b/ezyhttp-server-graphql/pom.xml index 08e6f7d..db4c4ae 100644 --- a/ezyhttp-server-graphql/pom.xml +++ b/ezyhttp-server-graphql/pom.xml @@ -6,7 +6,7 @@ com.tvd12 ezyhttp - 1.4.7 + 1.4.8 ezyhttp-server-graphql ezyhttp-server-graphql diff --git a/ezyhttp-server-jetty/pom.xml b/ezyhttp-server-jetty/pom.xml index ca0365f..9ee950b 100644 --- a/ezyhttp-server-jetty/pom.xml +++ b/ezyhttp-server-jetty/pom.xml @@ -5,7 +5,7 @@ com.tvd12 ezyhttp - 1.4.7 + 1.4.8 ezyhttp-server-jetty diff --git a/ezyhttp-server-management/pom.xml b/ezyhttp-server-management/pom.xml index e6f95f1..6512e95 100644 --- a/ezyhttp-server-management/pom.xml +++ b/ezyhttp-server-management/pom.xml @@ -6,7 +6,7 @@ com.tvd12 ezyhttp - 1.4.7 + 1.4.8 ezyhttp-server-management ezyhttp-server-management diff --git a/ezyhttp-server-thymeleaf/pom.xml b/ezyhttp-server-thymeleaf/pom.xml index 5fb8dc5..5dd2200 100644 --- a/ezyhttp-server-thymeleaf/pom.xml +++ b/ezyhttp-server-thymeleaf/pom.xml @@ -6,7 +6,7 @@ com.tvd12 ezyhttp - 1.4.7 + 1.4.8 ezyhttp-server-thymeleaf ezyhttp-server-thymeleaf diff --git a/ezyhttp-server-tomcat/pom.xml b/ezyhttp-server-tomcat/pom.xml index e9b006a..34af373 100644 --- a/ezyhttp-server-tomcat/pom.xml +++ b/ezyhttp-server-tomcat/pom.xml @@ -5,7 +5,7 @@ com.tvd12 ezyhttp - 1.4.7 + 1.4.8 ezyhttp-server-tomcat diff --git a/pom.xml b/pom.xml index eec80bf..ae1cf85 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 1.0.7 ezyhttp - 1.4.7 + 1.4.8 pom ezyhttp From a0170d5b5dc3461b7964252b1e0a00e34eb7b7db Mon Sep 17 00:00:00 2001 From: Dung Ta Van Date: Thu, 29 Jan 2026 14:33:44 +0700 Subject: [PATCH 2/4] use dequeue instead stack --- .../server/graphql/data/GraphQLDataFilter.java | 4 ++-- .../graphql/scheme/GraphQLSchemaParser.java | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/data/GraphQLDataFilter.java b/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/data/GraphQLDataFilter.java index 1797a35..346a471 100644 --- a/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/data/GraphQLDataFilter.java +++ b/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/data/GraphQLDataFilter.java @@ -17,8 +17,8 @@ public Map filter( ) { Map answer = new HashMap<>(); Map parentMap = null; - Stack stack = new Stack<>(); - stack.add(new StackEntry(queryDefinition, data)); + Deque stack = new ArrayDeque<>(); + stack.push(new StackEntry(queryDefinition, data)); while (!stack.isEmpty()) { StackEntry entry = stack.pop(); String parentName = entry.field.getName(); diff --git a/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/scheme/GraphQLSchemaParser.java b/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/scheme/GraphQLSchemaParser.java index 1f6ecd9..5221a75 100644 --- a/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/scheme/GraphQLSchemaParser.java +++ b/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/scheme/GraphQLSchemaParser.java @@ -7,8 +7,9 @@ import com.tvd12.ezyhttp.server.graphql.query.GraphQLQueryDefinition; import lombok.AllArgsConstructor; +import java.util.ArrayDeque; +import java.util.Deque; import java.util.Map; -import java.util.Stack; import static com.tvd12.ezyfox.io.EzyStrings.EMPTY_STRING; @@ -24,7 +25,7 @@ public GraphQLSchema parseQuery( ) { String query = standardize(queryToParse); - Stack stack = new Stack<>(); + Deque stack = new ArrayDeque<>(); GraphQLSchema.Builder schemaBuilder = GraphQLSchema.builder(); int queryLength = query.length(); @@ -36,7 +37,7 @@ public GraphQLSchema parseQuery( if (stack.isEmpty()) { GraphQLQueryDefinition.Builder queryBuilder = GraphQLQueryDefinition.builder(); - stack.add(queryBuilder); + stack.push(queryBuilder); continue; } @@ -46,7 +47,7 @@ public GraphQLSchema parseQuery( nameLength = 0; } GraphQLField.Builder childBuilder = GraphQLField.builder(); - stack.add(childBuilder); + stack.push(childBuilder); continue; } @@ -119,7 +120,7 @@ public GraphQLSchema parseQuery( if (stack.isEmpty()) { GraphQLQueryDefinition.Builder queryBuilder = GraphQLQueryDefinition.builder(); - stack.add(queryBuilder); + stack.push(queryBuilder); nameLength = 0; continue; } @@ -134,7 +135,7 @@ public GraphQLSchema parseQuery( GraphQLQueryDefinition.Builder queryBuilder = GraphQLQueryDefinition.builder(); - stack.add(queryBuilder); + stack.push(queryBuilder); continue; } @@ -150,7 +151,7 @@ public GraphQLSchema parseQuery( parentBuilder.addField(childBuilder.build()); GraphQLField.Builder newChildBuilder = GraphQLField.builder(); - stack.add(newChildBuilder); + stack.push(newChildBuilder); } else { nameBuffer[nameLength++] = ch; } From c3d77f5a9abb453d4e982a65acd175e6b32150b1 Mon Sep 17 00:00:00 2001 From: Dung Ta Van Date: Thu, 29 Jan 2026 14:54:15 +0700 Subject: [PATCH 3/4] use dequeue instead stack --- .../GraphQLObjectMapperException.java | 7 ++ .../graphql/scheme/GraphQLSchemaParser.java | 31 ++++++- .../test/scheme/GraphQLSchemaParserTest.java | 81 +++++++++++++++++++ 3 files changed, 116 insertions(+), 3 deletions(-) diff --git a/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/exception/GraphQLObjectMapperException.java b/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/exception/GraphQLObjectMapperException.java index b776457..40ebf66 100644 --- a/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/exception/GraphQLObjectMapperException.java +++ b/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/exception/GraphQLObjectMapperException.java @@ -8,6 +8,13 @@ public class GraphQLObjectMapperException extends IllegalArgumentException { private final Object errors; + public GraphQLObjectMapperException( + Object errors + ) { + super(errors.toString()); + this.errors = errors; + } + public GraphQLObjectMapperException( Object errors, Throwable cause diff --git a/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/scheme/GraphQLSchemaParser.java b/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/scheme/GraphQLSchemaParser.java index 5221a75..9932437 100644 --- a/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/scheme/GraphQLSchemaParser.java +++ b/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/scheme/GraphQLSchemaParser.java @@ -52,7 +52,10 @@ public GraphQLSchema parseQuery( } if (ch == '(') { - GraphQLField.Builder childBuilder = stack.peek(); + GraphQLField.Builder childBuilder = peekFieldStackItemOrThrow( + stack, + "there is no child" + ); StringBuilder argumentsBuilder = new StringBuilder(); i = extractQueryArguments( argumentsBuilder, @@ -107,7 +110,10 @@ public GraphQLSchema parseQuery( nameLength = 0; } - GraphQLField.Builder parentBuilder = stack.peek(); + GraphQLField.Builder parentBuilder = peekFieldStackItemOrThrow( + stack, + "there is no parent case curly brace close" + ); parentBuilder.addField(childBuilder.build()); if (stack.size() == 1) { @@ -147,7 +153,10 @@ public GraphQLSchema parseQuery( nameLength = 0; } - GraphQLField.Builder parentBuilder = stack.peek(); + GraphQLField.Builder parentBuilder = peekFieldStackItemOrThrow( + stack, + "there is no parent case space" + ); parentBuilder.addField(childBuilder.build()); GraphQLField.Builder newChildBuilder = GraphQLField.builder(); @@ -283,4 +292,20 @@ private int extractQueryArguments( } return i; } + + private GraphQLField.Builder peekFieldStackItemOrThrow( + Deque stack, + String message + ) { + GraphQLField.Builder parentBuilder = stack.peek(); + if (parentBuilder == null) { + throw new GraphQLObjectMapperException( + EzyMapBuilder.mapBuilder() + .put("arguments", "invalid") + .put("message", message) + .toMap() + ); + } + return parentBuilder; + } } diff --git a/ezyhttp-server-graphql/src/test/java/com/tvd12/ezyhttp/server/graphql/test/scheme/GraphQLSchemaParserTest.java b/ezyhttp-server-graphql/src/test/java/com/tvd12/ezyhttp/server/graphql/test/scheme/GraphQLSchemaParserTest.java index 1d54cf0..0f9ac56 100644 --- a/ezyhttp-server-graphql/src/test/java/com/tvd12/ezyhttp/server/graphql/test/scheme/GraphQLSchemaParserTest.java +++ b/ezyhttp-server-graphql/src/test/java/com/tvd12/ezyhttp/server/graphql/test/scheme/GraphQLSchemaParserTest.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.ObjectMapper; import com.tvd12.ezyfox.util.EzyMapBuilder; +import com.tvd12.ezyhttp.server.graphql.data.GraphQLField; import com.tvd12.ezyhttp.server.graphql.exception.GraphQLObjectMapperException; import com.tvd12.ezyhttp.server.graphql.json.GraphQLObjectMapperFactory; import com.tvd12.ezyhttp.server.graphql.scheme.GraphQLSchema; @@ -12,8 +13,12 @@ import com.tvd12.test.util.RandomUtil; import org.testng.annotations.Test; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayDeque; import java.util.Arrays; import java.util.Collections; +import java.util.Deque; import java.util.Map; public class GraphQLSchemaParserTest { @@ -501,4 +506,80 @@ public void parseQueryInvalidArgument6Test() { // then Asserts.assertEqualsType(e, GraphQLObjectMapperException.class); } + + @Test + public void parseQueryNoChildBeforeArgumentsTest() { + // given + GraphQLSchemaParser instance = new GraphQLSchemaParser( + new ObjectMapper() + ); + + // when + Throwable e = Asserts.assertThrows(() -> + instance.parseQuery( + "(id: 1)", + Collections.emptyMap() + ) + ); + + // then + Asserts.assertEqualsType(e, GraphQLObjectMapperException.class); + GraphQLObjectMapperException exception = (GraphQLObjectMapperException) e; + Asserts.assertEquals( + exception.getErrors(), + EzyMapBuilder.mapBuilder() + .put("arguments", "invalid") + .put("message", "there is no child") + .toMap(), + false + ); + } + + @Test + public void requireParentBuilderWithEmptyStackTest() { + // given + GraphQLSchemaParser instance = new GraphQLSchemaParser( + new ObjectMapper() + ); + Deque stack = new ArrayDeque<>(); + + // when + final Method method; + try { + method = GraphQLSchemaParser.class.getDeclaredMethod( + "peekFieldStackItemOrThrow", + Deque.class, + String.class + ); + } catch (NoSuchMethodException ex) { + throw new IllegalStateException( + "method requireParentBuilder should exist", + ex + ); + } + method.setAccessible(true); + Throwable e = Asserts.assertThrows(() -> { + try { + method.invoke( + instance, + stack, + "there is no parent case curly brace close" + ); + } catch (InvocationTargetException ex) { + throw ex.getCause(); + } + }); + + // then + Asserts.assertEqualsType(e, GraphQLObjectMapperException.class); + GraphQLObjectMapperException exception = (GraphQLObjectMapperException) e; + Asserts.assertEquals( + exception.getErrors(), + EzyMapBuilder.mapBuilder() + .put("arguments", "invalid") + .put("message", "there is no parent case curly brace close") + .toMap(), + false + ); + } } From 4581b53bc9b014873b3dc0ec300c083e5b79473b Mon Sep 17 00:00:00 2001 From: Dung Ta Van Date: Thu, 29 Jan 2026 14:56:18 +0700 Subject: [PATCH 4/4] add unit test --- .../graphql/test/data/GraphQLRequestTest.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 ezyhttp-server-graphql/src/test/java/com/tvd12/ezyhttp/server/graphql/test/data/GraphQLRequestTest.java diff --git a/ezyhttp-server-graphql/src/test/java/com/tvd12/ezyhttp/server/graphql/test/data/GraphQLRequestTest.java b/ezyhttp-server-graphql/src/test/java/com/tvd12/ezyhttp/server/graphql/test/data/GraphQLRequestTest.java new file mode 100644 index 0000000..aa153e8 --- /dev/null +++ b/ezyhttp-server-graphql/src/test/java/com/tvd12/ezyhttp/server/graphql/test/data/GraphQLRequestTest.java @@ -0,0 +1,41 @@ +package com.tvd12.ezyhttp.server.graphql.test.data; + +import com.tvd12.ezyhttp.server.graphql.data.GraphQLRequest; +import com.tvd12.test.assertion.Asserts; +import org.testng.annotations.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class GraphQLRequestTest { + + @Test + public void getVariablesReturnsEmptyMapWhenUnset() { + // given + GraphQLRequest request = new GraphQLRequest(); + + // when + Map variables = request.getVariables(); + + // then + Asserts.assertEquals(variables, Collections.emptyMap(), false); + Asserts.assertTrue(variables.isEmpty()); + } + + @Test + public void getVariablesReturnsProvidedMap() { + // given + GraphQLRequest request = new GraphQLRequest(); + Map provided = new HashMap<>(); + provided.put("hello", "world"); + request.setVariables(provided); + + // when + Map variables = request.getVariables(); + + // then + Asserts.assertEquals(variables, provided, false); + Asserts.assertEquals(variables.get("hello"), "world"); + } +}