This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-graphql-core.git


The following commit(s) were added to refs/heads/master by this push:
     new 7028ec2  SLING-12893 - NPE in DefaultQueryExecutor
7028ec2 is described below

commit 7028ec2cca60940caab798e12badeef0135fbc46
Author: Martin Schulze <[email protected]>
AuthorDate: Wed Aug 20 14:31:30 2025 +0200

    SLING-12893 - NPE in DefaultQueryExecutor
    
    * fix NPE
    * add unit test for Executor Cache
    ---------
    
    Co-authored-by: Martin Schulze <[email protected]>
---
 .../graphql/core/engine/DefaultQueryExecutor.java  |   4 +-
 .../core/engine/DefaultQueryExecutorCacheTest.java | 124 +++++++++++++++++++++
 2 files changed, 126 insertions(+), 2 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/graphql/core/engine/DefaultQueryExecutor.java 
b/src/main/java/org/apache/sling/graphql/core/engine/DefaultQueryExecutor.java
index 88d87cd..4fb73a5 100644
--- 
a/src/main/java/org/apache/sling/graphql/core/engine/DefaultQueryExecutor.java
+++ 
b/src/main/java/org/apache/sling/graphql/core/engine/DefaultQueryExecutor.java
@@ -405,12 +405,12 @@ public class DefaultQueryExecutor implements 
QueryExecutor {
          */
         String resourceToHashMapKey = getCacheKey(currentResource, selectors);
         String oldHash = resourceToHashMap.get(resourceToHashMapKey);
-        if (!newHash.equals(oldHash)) {
+        if (!newHash.equals(oldHash) || hashToSchemaMap.get(newHash) == null) {
             readLock.unlock();
             writeLock.lock();
             try {
                 oldHash = resourceToHashMap.get(resourceToHashMapKey);
-                if (!newHash.equals(oldHash)) {
+                if (!newHash.equals(oldHash) || hashToSchemaMap.get(newHash) 
== null) {
                     typeRegistry = new SchemaParser().parse(sdl);
                     typeRegistry.add(Directives.CONNECTION);
                     typeRegistry.add(Directives.FETCHER);
diff --git 
a/src/test/java/org/apache/sling/graphql/core/engine/DefaultQueryExecutorCacheTest.java
 
b/src/test/java/org/apache/sling/graphql/core/engine/DefaultQueryExecutorCacheTest.java
new file mode 100644
index 0000000..7ba4597
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/graphql/core/engine/DefaultQueryExecutorCacheTest.java
@@ -0,0 +1,124 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License.  You may obtain a copy of the License at
+ ~
+ ~   http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied.  See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+package org.apache.sling.graphql.core.engine;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.graphql.core.scalars.SlingScalarsProvider;
+import org.apache.sling.graphql.core.schema.RankedSchemaProviders;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import graphql.schema.idl.TypeDefinitionRegistry;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DefaultQueryExecutorCacheTest {
+
+    @Mock
+    private RankedSchemaProviders schemaProvider;
+
+    @Mock
+    private SlingDataFetcherSelector dataFetcherSelector;
+
+    @Mock
+    private SlingTypeResolverSelector typeResolverSelector;
+
+    @Mock
+    private SlingScalarsProvider scalarsProvider;
+
+    @Mock
+    private Resource resource;
+
+    @InjectMocks
+    private DefaultQueryExecutor executor;
+
+    @Before
+    public void setUp() {
+        // Activate the component with default config
+        DefaultQueryExecutor.Config config = 
mock(DefaultQueryExecutor.Config.class);
+        when(config.schemaCacheSize()).thenReturn(10);
+        when(config.maxQueryTokens()).thenReturn(15000);
+        when(config.maxWhitespaceTokens()).thenReturn(200000);
+        when(config.maxFieldCount()).thenReturn(100000);
+
+        executor.activate(config);
+
+        when(resource.getPath()).thenReturn("/content/test");
+    }
+
+    @Test
+    public void testGetTypeDefinitionRegistry_ValidSDL() {
+        String validSDL = "type Query { hello: String }";
+        String[] selectors = { "test" };
+
+        TypeDefinitionRegistry result = 
executor.getTypeDefinitionRegistry(validSDL, resource, selectors);
+
+        assertNotNull(result);
+        assertTrue(result.getType("Query").isPresent());
+    }
+
+    @Test
+    public void testGetTypeDefinitionRegistry_InvalidSDL() {
+        String invalidSDL = "invalid graphql syntax {";
+        String[] selectors = { "test" };
+
+        TypeDefinitionRegistry result = 
executor.getTypeDefinitionRegistry(invalidSDL, resource, selectors);
+
+        assertNull(result);
+    }
+
+    @Test
+    public void testGetTypeDefinitionRegistry_CacheDisabled() {
+        DefaultQueryExecutor.Config config = 
mock(DefaultQueryExecutor.Config.class);
+        when(config.schemaCacheSize()).thenReturn(0);
+        executor.activate(config);
+
+        String sdl = "type Query { hello: String }";
+        String[] selectors = { "test" };
+
+        TypeDefinitionRegistry result = 
executor.getTypeDefinitionRegistry(sdl, resource, selectors);
+
+        assertNotNull(result);
+    }
+
+    @Test
+    public void testGetTypeDefinitionRegistry_Extended() {
+        Resource resource2 = mock(Resource.class);
+        when(resource2.getPath()).thenReturn("/content/test2");
+
+        DefaultQueryExecutor.Config config = 
mock(DefaultQueryExecutor.Config.class);
+        when(config.schemaCacheSize()).thenReturn(2);
+        executor.activate(config);
+
+        String sdl = "type Query { hello: String }";
+        String[] selectors = { "test" };
+
+        executor.getTypeDefinitionRegistry(sdl, resource2, selectors);
+        executor.getTypeDefinitionRegistry(sdl + " ", resource, selectors);
+        executor.getTypeDefinitionRegistry(sdl + "  ", resource, selectors);
+        TypeDefinitionRegistry result = 
executor.getTypeDefinitionRegistry(sdl, resource2, selectors);
+        assertNotNull(result);
+    }
+}

Reply via email to