diff --git a/spring-ai-model/src/main/java/org/springframework/ai/converter/BeanOutputConverter.java b/spring-ai-model/src/main/java/org/springframework/ai/converter/BeanOutputConverter.java index 977aa5a20f..321d57b097 100644 --- a/spring-ai-model/src/main/java/org/springframework/ai/converter/BeanOutputConverter.java +++ b/spring-ai-model/src/main/java/org/springframework/ai/converter/BeanOutputConverter.java @@ -21,16 +21,18 @@ import java.util.Objects; import com.github.victools.jsonschema.generator.Option; +import com.github.victools.jsonschema.generator.OptionPreset; import com.github.victools.jsonschema.generator.SchemaGenerator; import com.github.victools.jsonschema.generator.SchemaGeneratorConfig; import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; import com.github.victools.jsonschema.module.jackson.JacksonOption; import com.github.victools.jsonschema.module.jackson.JacksonSchemaModule; -import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import tools.jackson.core.JacksonException; +import tools.jackson.core.type.TypeReference; import tools.jackson.core.util.DefaultIndenter; import tools.jackson.core.util.DefaultPrettyPrinter; import tools.jackson.databind.DeserializationFeature; @@ -64,7 +66,9 @@ */ public class BeanOutputConverter implements StructuredOutputConverter { - private final Logger logger = LoggerFactory.getLogger(BeanOutputConverter.class); + private static final Logger logger = LoggerFactory.getLogger(BeanOutputConverter.class); + + private static final MapTypeReference MAP_TYPE_REFERENCE = new MapTypeReference(); /** * The target class type reference to which the output will be converted. @@ -189,9 +193,8 @@ private static ResponseTextCleaner createDefaultTextCleaner() { private void generateSchema() { JacksonSchemaModule jacksonModule = new JacksonSchemaModule(JacksonOption.RESPECT_JSONPROPERTY_REQUIRED, JacksonOption.RESPECT_JSONPROPERTY_ORDER); - SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder( - com.github.victools.jsonschema.generator.SchemaVersion.DRAFT_2020_12, - com.github.victools.jsonschema.generator.OptionPreset.PLAIN_JSON) + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, + OptionPreset.PLAIN_JSON) .with(jacksonModule) .with(Option.FORBIDDEN_ADDITIONAL_PROPERTIES_BY_DEFAULT); @@ -222,7 +225,8 @@ private void generateSchema() { * subclasses. * @param jsonNode the JSON schema, in the form of a JSON node */ - protected void postProcessSchema(@NonNull JsonNode jsonNode) { + @SuppressWarnings("unused") + protected void postProcessSchema(JsonNode jsonNode) { } /** @@ -230,14 +234,13 @@ protected void postProcessSchema(@NonNull JsonNode jsonNode) { * @param text The LLM output in string format. * @return The parsed output in the desired target type. */ - @SuppressWarnings("unchecked") @Override public T convert(String text) { try { // Clean the text using the configured text cleaner text = this.textCleaner.clean(text); - return (T) this.jsonMapper.readValue(text, this.jsonMapper.constructType(this.type)); + return this.jsonMapper.readValue(text, this.jsonMapper.constructType(this.type)); } catch (JacksonException e) { logger.error(SENSITIVE_DATA_MARKER, @@ -285,7 +288,7 @@ public String getJsonSchema() { public Map getJsonSchemaMap() { try { - return this.jsonMapper.readValue(this.jsonSchema, Map.class); + return this.jsonMapper.readValue(this.jsonSchema, MAP_TYPE_REFERENCE); } catch (JacksonException ex) { logger.error("Could not parse the JSON Schema to a Map object", ex); @@ -293,4 +296,8 @@ public Map getJsonSchemaMap() { } } + private static final class MapTypeReference extends TypeReference> { + + } + } diff --git a/spring-ai-model/src/test/java/org/springframework/ai/converter/BeanOutputConverterTest.java b/spring-ai-model/src/test/java/org/springframework/ai/converter/BeanOutputConverterTest.java index ce6fa22ce6..618fc7fc2a 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/converter/BeanOutputConverterTest.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/converter/BeanOutputConverterTest.java @@ -29,9 +29,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; import org.slf4j.LoggerFactory; import tools.jackson.databind.DeserializationFeature; import tools.jackson.databind.JsonNode; @@ -51,17 +48,12 @@ * @author Soby Chacko * @author Konstantin Pavlov */ -@ExtendWith(MockitoExtension.class) class BeanOutputConverterTest { private ListAppender logAppender; - @Mock - private JsonMapper jsonMapperMock; - @BeforeEach void beforeEach() { - var logger = (Logger) LoggerFactory.getLogger(BeanOutputConverter.class); this.logAppender = new ListAppender<>(); @@ -82,19 +74,15 @@ static class TestClass { private String someString; - @SuppressWarnings("unused") TestClass() { } - TestClass(String someString) { - this.someString = someString; - } - String getSomeString() { return this.someString; } - public void setSomeString(String someString) { + @SuppressWarnings("unused") + void setSomeString(String someString) { this.someString = someString; } @@ -104,19 +92,15 @@ static class TestClassWithDateProperty { private LocalDate someString; - @SuppressWarnings("unused") TestClassWithDateProperty() { } - TestClassWithDateProperty(LocalDate someString) { - this.someString = someString; - } - LocalDate getSomeString() { return this.someString; } - public void setSomeString(LocalDate someString) { + @SuppressWarnings("unused") + void setSomeString(LocalDate someString) { this.someString = someString; } diff --git a/spring-ai-model/src/test/java/org/springframework/ai/converter/CompositeResponseTextCleanerTest.java b/spring-ai-model/src/test/java/org/springframework/ai/converter/CompositeResponseTextCleanerTest.java index 22f3e608d8..f84e12ab1c 100644 --- a/spring-ai-model/src/test/java/org/springframework/ai/converter/CompositeResponseTextCleanerTest.java +++ b/spring-ai-model/src/test/java/org/springframework/ai/converter/CompositeResponseTextCleanerTest.java @@ -41,7 +41,7 @@ void shouldApplyCleanersInOrder() { @Test void shouldWorkWithSingleCleaner() { - var cleaner = new CompositeResponseTextCleaner(text -> text.trim()); + var cleaner = new CompositeResponseTextCleaner(String::trim); String result = cleaner.clean(" content "); assertThat(result).isEqualTo("content"); }