Companion code for the ankurm.com guide. Verified on Spring AI 2.0.0, Spring Boot 4.1.0,
JDK 25.0.3. run.txt is unedited mvn test output: 5 tests, 0 failures.
Runs with NO API key, no network and no provider account. A canned ChatModel returns fixed
responses; ChatClient, advisors and chat memory all sit above the model, so everything that
changed is still exercised faithfully. TestChatModel records each Prompt it receives, which
lets the tests assert what Spring AI SENT rather than what a model replied.
docs/01 complete breaking-change reference: platform (Boot 4 mandatory, Jackson 2 to 3),
artifact renames (spring-ai-advisors-vector-store -> spring-ai-vector-store-advisor,
spring-ai-core split, OCI and Minimax removals, MCP transports moved into Spring AI),
options builders replacing setters, the dropped .options property prefix, tool
calling (internalToolExecutionEnabled and toolNames removed outright, not renamed),
chat memory, structured output schema changes, and a migration order that works.
Tested here
- Chat memory becomes stricter: 2.0 removes the remaining default-ID and builder-based
configuration paths (ChatMemory.DEFAULT_CONVERSATION_ID and .conversationId() are both
gone). Explicit per-request conversation ids - introduced during the 1.x line and already
the recommended approach - become the only migration target.
- CONVERSATION_ID survives as the metadata KEY. It and the removed DEFAULT_CONVERSATION_ID
look interchangeable and are opposites; swapping them to clear a compile error restores
exactly the shared-conversation behaviour that removing it was meant to take away.
- PromptChatMemoryAdvisor is gone; MessageChatMemoryAdvisor replaces it, and the difference
is not cosmetic (system-prompt text vs real Message objects, so token counts change).
- A test asserts two conversation ids cannot see each other.
121 lines
13 KiB
Plaintext
121 lines
13 KiB
Plaintext
mvn.cmd : WARNING: A restricted method in java.lang.System has been called
|
|
At line:5 char:1
|
|
+ & $mvn -B test *> run.txt
|
|
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
+ CategoryInfo : NotSpecified: (WARNING: A rest...has been called:String) [], RemoteException
|
|
+ FullyQualifiedErrorId : NativeCommandError
|
|
|
|
WARNING: java.lang.System::load has been called by org.fusesource.jansi.internal.JansiLoader in an unnamed module
|
|
(file:/C:/Users/Ankur/ankurm-blog-tools/apache-maven-3.9.9/lib/jansi-2.4.1.jar)
|
|
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
|
|
WARNING: Restricted methods will be blocked in a future release unless native access is enabled
|
|
|
|
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
|
WARNING: sun.misc.Unsafe::objectFieldOffset has been called by
|
|
com.google.common.util.concurrent.AbstractFuture$UnsafeAtomicHelper
|
|
(file:/C:/Users/Ankur/ankurm-blog-tools/apache-maven-3.9.9/lib/guava-33.2.1-jre.jar)
|
|
WARNING: Please consider reporting this to the maintainers of class
|
|
com.google.common.util.concurrent.AbstractFuture$UnsafeAtomicHelper
|
|
WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release
|
|
[INFO] Scanning for projects...
|
|
[INFO]
|
|
[INFO] ----------------< com.ankurm.ai:spring-ai-2-migration >-----------------
|
|
[INFO] Building Spring AI 1.x to 2.0 migration 1.0.0
|
|
[INFO] from pom.xml
|
|
[INFO] --------------------------------[ jar ]---------------------------------
|
|
[INFO]
|
|
[INFO] --- resources:3.5.0:resources (default-resources) @ spring-ai-2-migration ---
|
|
[INFO] skip non existing resourceDirectory C:\Users\Ankur\ankurm-blog-tools\projects\spring-ai-2-migration\src\main\resources
|
|
[INFO] skip non existing resourceDirectory C:\Users\Ankur\ankurm-blog-tools\projects\spring-ai-2-migration\src\main\resources
|
|
[INFO]
|
|
[INFO] --- compiler:3.15.0:compile (default-compile) @ spring-ai-2-migration ---
|
|
[INFO] Nothing to compile - all classes are up to date.
|
|
[INFO]
|
|
[INFO] --- resources:3.5.0:testResources (default-testResources) @ spring-ai-2-migration ---
|
|
[INFO] skip non existing resourceDirectory C:\Users\Ankur\ankurm-blog-tools\projects\spring-ai-2-migration\src\test\resources
|
|
[INFO]
|
|
[INFO] --- compiler:3.15.0:testCompile (default-testCompile) @ spring-ai-2-migration ---
|
|
[INFO] Recompiling the module because of changed source code.
|
|
[INFO] Compiling 1 source file with javac [debug parameters release 25] to target\test-classes
|
|
[INFO]
|
|
[INFO] --- surefire:3.5.6:test (default-test) @ spring-ai-2-migration ---
|
|
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
|
|
[INFO]
|
|
[INFO] -------------------------------------------------------
|
|
[INFO] T E S T S
|
|
[INFO] -------------------------------------------------------
|
|
[INFO] Running com.ankurm.ai.ChatMemoryMigrationTest
|
|
|
|
==============================================================================
|
|
4. Proving isolation, now that explicit ids are the only path
|
|
==============================================================================
|
|
bob's prompt: USER what did you hear?
|
|
|
|
>> Passing distinct ids keeps the conversations separate -- and in 2.0
|
|
>> there is no longer a way NOT to pass one. Under 1.x the same code
|
|
>> with the ids omitted would have compiled, put alice and bob in the
|
|
>> shared 'default' conversation, and failed this assertion silently.
|
|
|
|
==============================================================================
|
|
1. ChatMemory.DEFAULT_CONVERSATION_ID has been removed
|
|
==============================================================================
|
|
public constants on ChatMemory : [CONVERSATION_ID]
|
|
|
|
Note the survivor is CONVERSATION_ID, the metadata key you use to PASS an id.
|
|
The removed one was DEFAULT_CONVERSATION_ID, the value 'default' used when you
|
|
passed nothing. Same prefix, opposite meaning -- so 'fixing' the compile error by
|
|
swapping one for the other restores exactly the shared-conversation behaviour
|
|
that removing it was meant to take away.
|
|
|
|
==============================================================================
|
|
2. PromptChatMemoryAdvisor has been removed
|
|
==============================================================================
|
|
PromptChatMemoryAdvisor : ClassNotFoundException (as expected in 2.0)
|
|
MessageChatMemoryAdvisor: org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor
|
|
|
|
Replacement is MessageChatMemoryAdvisor. The difference is not cosmetic: the
|
|
removed one injected history into the SYSTEM PROMPT as text, the replacement
|
|
adds it as real Message objects. Providers treat those differently, so expect
|
|
your prompts -- and your token counts -- to change on migration.
|
|
|
|
==============================================================================
|
|
5. Direct ChatMemory use, for the storage-layer migration
|
|
==============================================================================
|
|
stored: first
|
|
stored: second
|
|
after clear: 0 messages
|
|
|
|
>> If you use a JDBC/Cassandra/Mongo/Neo4j ChatMemoryRepository, note a
|
|
>> separate 2.0 change: retrieved messages now carry a creation
|
|
>> timestamp in metadata, so a message read back is NOT equals() to an
|
|
>> identical one built in code. Any test or cache keyed on Message
|
|
>> equality, or storing Messages in a Set, will change behaviour.
|
|
|
|
==============================================================================
|
|
3. The conversation ID is now required, per request
|
|
==============================================================================
|
|
turn 1 -- conversation 'user-42'
|
|
turn 2 -- same conversation
|
|
messages the model received on turn 2 : 3
|
|
USER my name is Ankur
|
|
ASSISTANT hello back
|
|
USER what is my name?
|
|
|
|
>> The id travels as an advisor PARAM per request, not as builder state.
|
|
>> This form already existed in 1.x; 2.0 removes the alternatives, so it
|
|
>> is now the only option. That suits how the id is actually scoped: in a
|
|
>> web app it is per user or per session, and therefore cannot sensibly
|
|
>> be baked into a singleton ChatClient.
|
|
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.336 s -- in com.ankurm.ai.ChatMemoryMigrationTest
|
|
[INFO]
|
|
[INFO] Results:
|
|
[INFO]
|
|
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
|
|
[INFO]
|
|
[INFO] ------------------------------------------------------------------------
|
|
[INFO] BUILD SUCCESS
|
|
[INFO] ------------------------------------------------------------------------
|
|
[INFO] Total time: 3.939 s
|
|
[INFO] Finished at: 2026-08-01T10:50:45+05:30
|
|
[INFO] ------------------------------------------------------------------------
|