This is an automated email from the ASF dual-hosted git repository.
epugh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr-mcp.git
The following commit(s) were added to refs/heads/main by this push:
new 2809af2 fix(native): register DefaultMetaProvider reflection hint to
unbreak nativeTest (#172)
2809af2 is described below
commit 2809af25414a9e92b539a7b77295e0ac48e83dc9
Author: Aditya Parikh <[email protected]>
AuthorDate: Tue Aug 18 16:40:52 2026 -0400
fix(native): register DefaultMetaProvider reflection hint to unbreak
nativeTest (#172)
* fix(native): register reflection hint for DefaultMetaProvider
Spring AI 1.1.6 introduced a MetaUtils.getMeta() call path in the sync
resource providers that reflectively invokes the no-arg constructor on
org.springaicommunity.mcp.context.DefaultMetaProvider. AOT does not
generate this hint, so every @SpringBootTest fails in nativeTest with:
IllegalArgumentException: Required no-arg constructor not found in
org.springaicommunity.mcp.context.DefaultMetaProvider
...
Caused by: NoSuchMethodException:
org.springaicommunity.mcp.context.DefaultMetaProvider.<init>()
during ApplicationContext refresh, and the remaining tests cascade-fail
on "ApplicationContext failure threshold (1) exceeded".
Register the constructor hint in SolrNativeHints alongside the existing
SolrJ and MCP response-record hints. registerTypeIfPresent keeps it a
no-op if a future Spring AI release removes or relocates the class.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: Aditya Parikh <[email protected]>
* test(config): disable SolrConfigAuthTest in native image
The test reflects into SolrJ's private basicAuthAuthorizationStr field to
verify basic-auth wiring. That field is not registered for reflection under
GraalVM's closed-world model, so ReflectionUtils.findField returns null and
the assertion fails in nativeTest (it passes on the JVM). The basic-auth
wiring logic itself is fully covered by the JVM test run, so disable the
reflection-based assertions in native image, matching the repo convention
for tests that don't survive the closed-world assumption.
This failure is currently masked in CI: every @SpringBootTest fails first
on the DefaultMetaProvider reflection gap fixed in the previous commit.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: Aditya Parikh <[email protected]>
* test(native): pin SolrNativeHints registrations with
RuntimeHintsPredicates
Review follow-up on this PR. The hints were previously exercised only by
nativeTest -Pnative (a full GraalVM build), so an accidentally removed
registration would surface as a hard-to-diagnose native-only startup
failure. SolrNativeHintsTest pins the DefaultMetaProvider constructor
hint, a representative SolrJ type, an MCP response record, and the
logback.xml resource pattern on the plain JVM path, where a regression
fails in seconds.
Also moves the SolrConfigAuthTest disable rationale above the annotation
so spotless stops mangling the comment wrap.
Co-Authored-By: Claude Fable 5 <[email protected]>
Signed-off-by: Aditya Parikh <[email protected]>
---------
Signed-off-by: Aditya Parikh <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>
---
.../solr/mcp/server/config/SolrNativeHints.java | 7 ++
.../solr/mcp/server/config/SolrConfigAuthTest.java | 5 ++
.../mcp/server/config/SolrNativeHintsTest.java | 79 ++++++++++++++++++++++
3 files changed, 91 insertions(+)
diff --git
a/src/main/java/org/apache/solr/mcp/server/config/SolrNativeHints.java
b/src/main/java/org/apache/solr/mcp/server/config/SolrNativeHints.java
index 2390626..f8133bf 100644
--- a/src/main/java/org/apache/solr/mcp/server/config/SolrNativeHints.java
+++ b/src/main/java/org/apache/solr/mcp/server/config/SolrNativeHints.java
@@ -115,6 +115,13 @@ public class SolrNativeHints {
hints.reflection().registerTypeIfPresent(classLoader, className, categories);
}
+ // Spring AI MCP reflectively instantiates
DefaultMetaProvider via its
+ // no-arg constructor in MetaUtils.getMeta() when
building resource
+ // specifications. AOT does not generate this hint
automatically.
+ hints.reflection().registerTypeIfPresent(classLoader,
+
"org.springaicommunity.mcp.context.DefaultMetaProvider",
+
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
+
// Include logback.xml in the native image so logback's
early
// initialization (before Spring Boot) finds it and
applies the
// NopStatusListener. Without this, logback falls
through to
diff --git
a/src/test/java/org/apache/solr/mcp/server/config/SolrConfigAuthTest.java
b/src/test/java/org/apache/solr/mcp/server/config/SolrConfigAuthTest.java
index 8dd5740..7110455 100644
--- a/src/test/java/org/apache/solr/mcp/server/config/SolrConfigAuthTest.java
+++ b/src/test/java/org/apache/solr/mcp/server/config/SolrConfigAuthTest.java
@@ -28,6 +28,7 @@ import java.util.Base64;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.impl.HttpJdkSolrClient;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledInNativeImage;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.beans.factory.annotation.Autowired;
@@ -45,6 +46,10 @@ import org.springframework.util.ReflectionUtils;
* encoding.
*/
@JsonTest
+// Reflects into SolrJ's private basicAuthAuthorizationStr field, which is not
+// registered for reflection under GraalVM's closed-world model. The basic-auth
+// wiring logic itself is fully covered by the JVM test run.
+@DisabledInNativeImage
class SolrConfigAuthTest {
@Autowired
diff --git
a/src/test/java/org/apache/solr/mcp/server/config/SolrNativeHintsTest.java
b/src/test/java/org/apache/solr/mcp/server/config/SolrNativeHintsTest.java
new file mode 100644
index 0000000..3e12d09
--- /dev/null
+++ b/src/test/java/org/apache/solr/mcp/server/config/SolrNativeHintsTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.solr.mcp.server.config;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.aot.hint.MemberCategory;
+import org.springframework.aot.hint.RuntimeHints;
+import org.springframework.aot.hint.TypeReference;
+import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
+
+/**
+ * Verifies that {@link SolrNativeHints.Registrar} registers the reflection and
+ * resource hints the native image depends on.
+ *
+ * <p>
+ * The hints are otherwise only exercised by {@code nativeTest -Pnative} (a
full
+ * GraalVM build), so an accidentally removed registration would surface as a
+ * hard-to-diagnose native-only startup failure. This test pins the
+ * registrations on the plain JVM path where a regression fails in seconds.
+ */
+class SolrNativeHintsTest {
+
+ private final RuntimeHints hints = new RuntimeHints();
+
+ @BeforeEach
+ void registerHints() {
+ new SolrNativeHints.Registrar().registerHints(hints,
getClass().getClassLoader());
+ }
+
+ @Test
+ void registersDefaultMetaProviderConstructorHint() {
+ // Spring AI MCP instantiates DefaultMetaProvider reflectively
in
+ // MetaUtils.getMeta(); without this hint every Spring context
refresh
+ // fails in native image with "Required no-arg constructor not
found".
+ assertTrue(RuntimeHintsPredicates.reflection()
+
.onType(TypeReference.of("org.springaicommunity.mcp.context.DefaultMetaProvider"))
+
.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS).test(hints));
+ }
+
+ @Test
+ void registersSolrjResponseTypeHints() {
+
assertTrue(RuntimeHintsPredicates.reflection().onType(QueryResponse.class)
+
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
+
MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.DECLARED_FIELDS)
+ .test(hints));
+ }
+
+ @Test
+ void registersMcpResponseRecordHints() {
+ assertTrue(RuntimeHintsPredicates.reflection()
+
.onType(TypeReference.of("org.apache.solr.mcp.server.search.SearchResponse"))
+
.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS).test(hints));
+ }
+
+ @Test
+ void registersLogbackXmlResourceHint() {
+ // Required so logback's pre-Spring initialization finds
logback.xml and
+ // stays silent on stdout (MCP STDIO framing).
+
assertTrue(RuntimeHintsPredicates.resource().forResource("logback.xml").test(hints));
+ }
+}