diff --git a/elide-async/src/main/java/com/yahoo/elide/async/resources/ExportApiEndpoint.java b/elide-async/src/main/java/com/yahoo/elide/async/resources/ExportApiEndpoint.java index 9dec51471..2a8e1a2fc 100644 --- a/elide-async/src/main/java/com/yahoo/elide/async/resources/ExportApiEndpoint.java +++ b/elide-async/src/main/java/com/yahoo/elide/async/resources/ExportApiEndpoint.java @@ -6,13 +6,14 @@ package com.yahoo.elide.async.resources; import com.yahoo.elide.async.service.storageengine.ResultStorageEngine; -import com.yahoo.elide.core.exceptions.HttpStatus; import jakarta.inject.Inject; import jakarta.inject.Named; import jakarta.inject.Singleton; import jakarta.servlet.http.HttpServletResponse; import jakarta.ws.rs.GET; +import jakarta.ws.rs.InternalServerErrorException; +import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.container.AsyncResponse; @@ -83,9 +84,13 @@ public void get(@PathParam("asyncQueryId") String asyncQueryId, @Context HttpSer try { log.debug(message); if (message != null && message.equals(ResultStorageEngine.RETRIEVE_ERROR)) { - httpServletResponse.sendError(HttpStatus.SC_NOT_FOUND, asyncQueryId + " Not Found"); + String errorMessage = asyncQueryId + " Not Found"; + throw new NotFoundException(errorMessage, + Response.status(Response.Status.NOT_FOUND).entity(errorMessage).build()); } else { - httpServletResponse.sendError(HttpStatus.SC_INTERNAL_SERVER_ERROR); + throw new InternalServerErrorException( + Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Internal Server Error").build()); } } catch (IllegalStateException ise) { // If stream was flushed, Attachment download has already started. diff --git a/elide-core/src/main/java/com/yahoo/elide/core/exceptions/ExceptionMapper.java b/elide-core/src/main/java/com/yahoo/elide/core/exceptions/ExceptionMapper.java index 329573e4f..4f05e0191 100644 --- a/elide-core/src/main/java/com/yahoo/elide/core/exceptions/ExceptionMapper.java +++ b/elide-core/src/main/java/com/yahoo/elide/core/exceptions/ExceptionMapper.java @@ -7,8 +7,6 @@ import com.yahoo.elide.ElideErrorResponse; -import javax.annotation.Nullable; - /** * Maps an exception to an {@link ElideErrorResponse}. * @@ -24,6 +22,5 @@ public interface ExceptionMapper { * @param errorContext the error context * @return the mapped ElideErrorResponse or null if you do not want to map this error */ - @Nullable ElideErrorResponse toErrorResponse(E exception, ErrorContext errorContext); } diff --git a/elide-core/src/main/java/com/yahoo/elide/core/graal/ElideFeature.java b/elide-core/src/main/java/com/yahoo/elide/core/graal/ElideFeature.java index b88544170..df601bebc 100644 --- a/elide-core/src/main/java/com/yahoo/elide/core/graal/ElideFeature.java +++ b/elide-core/src/main/java/com/yahoo/elide/core/graal/ElideFeature.java @@ -5,15 +5,25 @@ */ package com.yahoo.elide.core.graal; +import com.yahoo.elide.annotation.LifeCycleHookBinding; import com.yahoo.elide.core.utils.ClassScannerCache; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.RuntimeReflection; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ScanResult; + import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; /** * Native Image Feature for Elide. @@ -21,38 +31,77 @@ public class ElideFeature implements Feature { @Override public void beforeAnalysis(BeforeAnalysisAccess access) { - ClassScannerCache.getInstance().values().stream().forEach(set -> set.stream().forEach(this::register)); - } - - void register(Class... classes) { - Arrays.stream(classes).forEach(clazz -> { - System.out.println("Elide registering class " + clazz + " for reflection"); - - RuntimeReflection.register(clazz); - + Map>> classes = ClassScannerCache.getInstance(); + // In GraalVM 21+ java.class.path is not set so need to use + // access.getApplicationClassPath otherwise no classes are found + try (ScanResult scanResult = new ClassGraph().overrideClasspath(access.getApplicationClassPath()) + .enableClassInfo().enableAnnotationInfo().scan()) { + for (String annotationName : ClassScannerCache.getCachedAnnotations()) { + Set> value = scanResult.getClassesWithAnnotation(annotationName).stream() + .map(ClassInfo::loadClass).collect(Collectors.toCollection(LinkedHashSet::new)); + if (!value.isEmpty()) { + classes.put(annotationName, value); + } + } + } + Set> results = new LinkedHashSet<>(); + classes.values().stream().forEach(set -> set.stream().forEach(clazz -> { + results.add(clazz); + LifeCycleHookBinding lifeCycleHookBinding = clazz.getAnnotation(LifeCycleHookBinding.class); + if (lifeCycleHookBinding != null) { + results.add(lifeCycleHookBinding.hook()); + } + })); + Set> hooks = new LinkedHashSet<>(); + results.forEach(clazz -> { for (Field field : clazz.getFields()) { - RuntimeReflection.register(field); + LifeCycleHookBinding lifeCycleHookBinding = field.getAnnotation(LifeCycleHookBinding.class); + if (lifeCycleHookBinding != null) { + hooks.add(lifeCycleHookBinding.hook()); + } } - for (Method method : clazz.getMethods()) { - RuntimeReflection.register(method); + LifeCycleHookBinding lifeCycleHookBinding = method.getAnnotation(LifeCycleHookBinding.class); + if (lifeCycleHookBinding != null) { + hooks.add(lifeCycleHookBinding.hook()); + } } + }); + results.addAll(hooks); + // Sort + List> ordered = new ArrayList<>(results); + ordered.sort((left, right) -> { + return left.getName().compareTo(right.getName()); + }); + ordered.forEach(this::register); + } - for (Constructor constructor : clazz.getConstructors()) { - RuntimeReflection.register(constructor); - } + void register(Class clazz) { + System.out.println("Elide registering " + clazz + " for reflection"); - for (Field field : clazz.getDeclaredFields()) { - RuntimeReflection.register(field); - } + RuntimeReflection.register(clazz); + for (Field field : clazz.getFields()) { + RuntimeReflection.register(field); + } - for (Method method : clazz.getDeclaredMethods()) { - RuntimeReflection.register(method); - } + for (Method method : clazz.getMethods()) { + RuntimeReflection.register(method); + } - for (Constructor constructor : clazz.getDeclaredConstructors()) { - RuntimeReflection.register(constructor); - } - }); + for (Constructor constructor : clazz.getConstructors()) { + RuntimeReflection.register(constructor); + } + + for (Field field : clazz.getDeclaredFields()) { + RuntimeReflection.register(field); + } + + for (Method method : clazz.getDeclaredMethods()) { + RuntimeReflection.register(method); + } + + for (Constructor constructor : clazz.getDeclaredConstructors()) { + RuntimeReflection.register(constructor); + } } } diff --git a/elide-core/src/main/java/com/yahoo/elide/core/utils/ClassScannerCache.java b/elide-core/src/main/java/com/yahoo/elide/core/utils/ClassScannerCache.java index 62c067738..ca7cd727d 100644 --- a/elide-core/src/main/java/com/yahoo/elide/core/utils/ClassScannerCache.java +++ b/elide-core/src/main/java/com/yahoo/elide/core/utils/ClassScannerCache.java @@ -66,4 +66,8 @@ private ClassScannerCache() { public static Map>> getInstance() { return INSTANCE; } + + public static String[] getCachedAnnotations() { + return CACHE_ANNOTATIONS; + } } diff --git a/elide-graphql/src/test/java/com/yahoo/elide/graphql/FetcherFetchTest.java b/elide-graphql/src/test/java/com/yahoo/elide/graphql/FetcherFetchTest.java index 325ef84e3..7daf43bac 100644 --- a/elide-graphql/src/test/java/com/yahoo/elide/graphql/FetcherFetchTest.java +++ b/elide-graphql/src/test/java/com/yahoo/elide/graphql/FetcherFetchTest.java @@ -54,7 +54,7 @@ public void testSubscriptionThrowsError() throws Exception { + " }\n" + "}"; - assertQueryFailsWith(query, "Schema is not configured for subscriptions."); + assertQueryFailsWith(query, "Validation error (UnknownOperation): The 'Subscription' operation is not supported by the schema"); } @Test diff --git a/pom.xml b/pom.xml index 444b024f4..396bbbb6b 100644 --- a/pom.xml +++ b/pom.xml @@ -80,63 +80,64 @@ ${project.basedir}/target/lombok - 4.13.1 - 2.33.0 + 4.13.2 + 2.40.0 6.0.0 - 1.37.0 - 3.2.0 - 4.8.172 + 1.41.0 + 3.2.3 + 4.8.184 1.11.0 - 1.9.0 - 4.4 - 1.26.2 - 3.14.0 + 1.11.0 + 4.5.0 + 1.28.0 + 3.20.0 0.11.0 - 1.2.3 - 5.1.0 - 22.0 - 24.0.1 - 33.4.0-jre - 4.4.0 - 6.6.12.Final - 8.0.2.Final + 1.4.0 + 5.4.0 + 24.3 + 24.0 + 25.0.1 + 33.5.0-jre + 4.5.0 + 6.6.36.Final + 8.0.3.Final 6.2.4.Final 3.1.0 - 5.4.3 - 2.11.0 + 5.5.1 + 2.13.2 2.3.232 - 5.1.0 - 2.17.1 - 2.0.1.MR + 6.3.3 + 2.19.4 + 2.0.1 3.1.0 3.1.0 2.0.1 2.2.0 4.0.0 3.1.0 - 2.4.1 - 3.1.8 - 12.0.15 - 5.1.5 + 2.4.2 + 3.1.11 + 12.0.30 + 6.0.0 1.5.3 - 2.9.0 - 1.5.6 + 2.10.0 + 1.5.9 5.10.2 - 1.5.18 + 1.5.21 1.18.36 - 5.4.0 - 5.5.1 - 2023.0.6 + 5.5.1 + 5.5.6 + 2024.0.12 2.1.0 2.0.17 - 3.4.1 - 6.1.10 - 4.1.4 - 2.8.5 - 2.2.29 + 3.5.8 + 6.2.14 + 4.3.0 + 2.8.14 + 2.2.41 1.2.1 - 11.0.6 - 5.12.0 + 11.0.14 + 5.20.0 3.6.0 4.3.0 10.21.4 @@ -271,7 +272,7 @@ com.graphql-java graphql-java-extended-scalars - ${graphql-java.version} + ${graphql-java-extended-scalars.version} com.google.code.gson