diff --git a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/aot/VertexAiGeminiRuntimeHintsTests.java b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/aot/VertexAiGeminiRuntimeHintsTests.java index aa6d7bbc854..c8b863fb4c8 100644 --- a/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/aot/VertexAiGeminiRuntimeHintsTests.java +++ b/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/aot/VertexAiGeminiRuntimeHintsTests.java @@ -53,4 +53,72 @@ void registerHints() { assertThat(registeredTypes.contains(TypeReference.of(VertexAiGeminiChatOptions.class))).isTrue(); } + @Test + void registerHintsWithNullClassLoader() { + RuntimeHints runtimeHints = new RuntimeHints(); + VertexAiGeminiRuntimeHints vertexAiGeminiRuntimeHints = new VertexAiGeminiRuntimeHints(); + + // Should not throw exception with null ClassLoader + org.assertj.core.api.Assertions + .assertThatCode(() -> vertexAiGeminiRuntimeHints.registerHints(runtimeHints, null)) + .doesNotThrowAnyException(); + } + + @Test + void ensureReflectionHintsAreRegistered() { + RuntimeHints runtimeHints = new RuntimeHints(); + VertexAiGeminiRuntimeHints vertexAiGeminiRuntimeHints = new VertexAiGeminiRuntimeHints(); + vertexAiGeminiRuntimeHints.registerHints(runtimeHints, null); + + // Ensure reflection hints are properly registered + assertThat(runtimeHints.reflection().typeHints().spliterator().estimateSize()).isGreaterThan(0); + } + + @Test + void verifyMultipleRegistrationCallsAreIdempotent() { + RuntimeHints runtimeHints = new RuntimeHints(); + VertexAiGeminiRuntimeHints vertexAiGeminiRuntimeHints = new VertexAiGeminiRuntimeHints(); + + // Register hints multiple times + vertexAiGeminiRuntimeHints.registerHints(runtimeHints, null); + long firstCount = runtimeHints.reflection().typeHints().spliterator().estimateSize(); + + vertexAiGeminiRuntimeHints.registerHints(runtimeHints, null); + long secondCount = runtimeHints.reflection().typeHints().spliterator().estimateSize(); + + // Should not register duplicate hints + assertThat(firstCount).isEqualTo(secondCount); + } + + @Test + void verifyJsonAnnotatedClassesFromCorrectPackage() { + Set jsonAnnotatedClasses = findJsonAnnotatedClassesInPackage( + "org.springframework.ai.vertexai.gemini"); + + // Ensure we found some JSON annotated classes in the expected package + assertThat(jsonAnnotatedClasses.spliterator().estimateSize()).isGreaterThan(0); + + // Verify all found classes are from the expected package + for (TypeReference classRef : jsonAnnotatedClasses) { + assertThat(classRef.getName()).startsWith("org.springframework.ai.vertexai.gemini"); + } + } + + @Test + void verifyNoUnnecessaryHintsRegistered() { + RuntimeHints runtimeHints = new RuntimeHints(); + VertexAiGeminiRuntimeHints vertexAiGeminiRuntimeHints = new VertexAiGeminiRuntimeHints(); + vertexAiGeminiRuntimeHints.registerHints(runtimeHints, null); + + Set jsonAnnotatedClasses = findJsonAnnotatedClassesInPackage( + "org.springframework.ai.vertexai.gemini"); + + Set registeredTypes = new HashSet<>(); + runtimeHints.reflection().typeHints().forEach(typeHint -> registeredTypes.add(typeHint.getType())); + + // Ensure we don't register significantly more types than needed + // Allow for some additional utility types but prevent hint bloat + assertThat(registeredTypes.size()).isLessThanOrEqualTo(jsonAnnotatedClasses.size() + 10); + } + }