diff --git a/ezyhttp-client/pom.xml b/ezyhttp-client/pom.xml index 8b369df8..2a5ce9f2 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 8dadc95c..d94e7177 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 f480f965..624382b5 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 9e967d8a..237c92b2 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 08e6f7d0..db4c4aee 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-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 1797a35e..346a471c 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/exception/GraphQLObjectMapperException.java b/ezyhttp-server-graphql/src/main/java/com/tvd12/ezyhttp/server/graphql/exception/GraphQLObjectMapperException.java index b7764574..40ebf668 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 1f6ecd91..99324372 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,12 +47,15 @@ public GraphQLSchema parseQuery( nameLength = 0; } GraphQLField.Builder childBuilder = GraphQLField.builder(); - stack.add(childBuilder); + stack.push(childBuilder); continue; } if (ch == '(') { - GraphQLField.Builder childBuilder = stack.peek(); + GraphQLField.Builder childBuilder = peekFieldStackItemOrThrow( + stack, + "there is no child" + ); StringBuilder argumentsBuilder = new StringBuilder(); i = extractQueryArguments( argumentsBuilder, @@ -106,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) { @@ -119,7 +126,7 @@ public GraphQLSchema parseQuery( if (stack.isEmpty()) { GraphQLQueryDefinition.Builder queryBuilder = GraphQLQueryDefinition.builder(); - stack.add(queryBuilder); + stack.push(queryBuilder); nameLength = 0; continue; } @@ -134,7 +141,7 @@ public GraphQLSchema parseQuery( GraphQLQueryDefinition.Builder queryBuilder = GraphQLQueryDefinition.builder(); - stack.add(queryBuilder); + stack.push(queryBuilder); continue; } @@ -146,11 +153,14 @@ 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(); - stack.add(newChildBuilder); + stack.push(newChildBuilder); } else { nameBuffer[nameLength++] = ch; } @@ -282,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/data/GraphQLRequestTest.java b/ezyhttp-server-graphql/src/test/java/com/tvd12/ezyhttp/server/graphql/test/data/GraphQLRequestTest.java new file mode 100644 index 00000000..aa153e8c --- /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"); + } +} 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 1d54cf01..0f9ac568 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 + ); + } } diff --git a/ezyhttp-server-jetty/pom.xml b/ezyhttp-server-jetty/pom.xml index ca0365f0..9ee950b8 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 e6f95f12..6512e95f 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 5fb8dc56..5dd22003 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 e9b006a6..34af3739 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 eec80bff..ae1cf855 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 1.0.7 ezyhttp - 1.4.7 + 1.4.8 pom ezyhttp