package com.ankurm.structuredoutput; import java.util.Map; import com.ankurm.structuredoutput.support.ScriptedChatModel; import com.ankurm.structuredoutput.support.Transcript; import org.junit.jupiter.api.Test; import org.springframework.ai.chat.client.ChatClient; import org.springframework.core.ParameterizedTypeReference; import static org.assertj.core.api.Assertions.assertThat; /** * Sometimes there's no record worth declaring -- a one-off extraction, a shape that varies call * to call. {@code entity()} maps straight to a {@code Map} for that case, the * same converter machinery as the record and list cases, just with a looser target type. */ class EntityBindingMapTest { @Test void mapsAJsonObjectToAMapWhenNoRecordIsWorthDeclaring() { ScriptedChatModel model = ScriptedChatModel.builder() .thenRespond(""" {"darkModeEnabled":true,"maxUploadSizeMb":25,"betaFeatures":["new-dashboard","ai-search"]} """) .build(); ChatClient client = ChatClient.builder(model).build(); Map flags = client.prompt() .user("Extract the feature flags mentioned here: dark mode is on, max upload size is 25MB, " + "and the beta features enabled are new-dashboard and ai-search.") .call() .entity(new ParameterizedTypeReference>() { }); assertThat(flags).containsEntry("darkModeEnabled", true).containsEntry("maxUploadSizeMb", 25); assertThat(model.callCount()).isEqualTo(1); Transcript.write("04-entity-map", "model call count: " + model.callCount() + "\n\n" + "mapped map: " + flags); } }