Verified Owner
Top Description Inners Fields Constructors Methods
org.jabref.logic.ai.chatting.migrations

public final Class ChatHistoryMigrationV1

extends Object
Class Inheritance
Imports
java.io.IOException, .InputStream, .ObjectInputStream, .ObjectStreamClass, java.nio.ByteBuffer, java.nio.file.Path, java.time.Instant, java.util.ArrayList, .Comparator, .List, .Map, .UUID, org.jabref.logic.ai.chatting.repositories.ChatHistoryRepository, org.jabref.logic.l10n.Localization, org.jabref.logic.util.Directories, .NotificationService, org.jabref.model.ai.chatting.ChatHistoryRecord, .ChatIdentifier, .ChatMessage, .ChatType, .ErrorMessage, org.jabref.model.database.BibDatabaseContext, dev.langchain4j.data.message.AiMessage, dev.langchain4j.data.message.UserMessage, org.h2.mvstore.MVMap, .MVStore, .WriteBuffer, org.h2.mvstore.type.BasicDataType, org.slf4j.Logger, .LoggerFactory

Migrates chat history from the old v1 MVStore file to the new v2 repository.

Old format (v1): Stored in "chat-history.mv" file. Map keys like "bibDatabasePath-entry-citationKey" or "bibDatabasePath-group-groupName" containing Map<Integer, ChatHistoryRecord> where ChatHistoryRecord was a private inner class of MVStoreChatHistoryStorage (full name: org.jabref.logic.ai.chatting.chathistory.storages.MVStoreChatHistoryStorage$ChatHistoryRecord).

New format (v2): Stored via repository using ChatIdentifier(libraryId, chatType, chatName).

Problem: The old inner class no longer exists, so MVStore's ObjectDataType fails with ClassNotFoundException before our code can intercept.

Solution: Open the map with a custom RawBytesDataType that returns the raw Java-serialized bytes for each value without invoking standard Java deserialization. Then a ClassRemappingObjectInputStream deserializes those bytes while remapping the deleted inner class name to the current ChatHistoryRecord.

Nested and Inner Type Summary

Modifier and TypeClass and Description
private static class
ChatHistoryMigrationV1.ClassRemappingObjectInputStream

Custom ObjectInputStream that remaps the deleted old inner class name to the current ChatHistoryRecord class.

private static class
ChatHistoryMigrationV1.RawBytesDataType

Reads raw Java-serialized bytes from MVStore's binary page format without invoking Java deserialization.

Field Summary

Modifier and TypeField and Description
private static final String
private static final String
private static final Logger
private static final String
private static final String
OLD_CHAT_HISTORY_RECORD_CLASS

Old inner class full name that is no longer in the classpath.

Constructor Summary

AccessConstructor and Description
private

Method Summary

Modifier and TypeMethod and Description
private static ChatMessage
private static ChatHistoryRecord
deserializeOldRecord(byte[] data)

Deserializes old ChatHistoryRecord bytes using a remapping ObjectInputStream.

private static boolean
public static void
migrate(BibDatabaseContext
The database context containing the AI library ID
bibDatabaseContext
,
ChatHistoryRepository
The new v2 chat history repository to migrate to
repository
,
NotificationService
Service for notifying user of errors
notificationService
)

Migrates old chat history data from v1 file to v2 repository.

public static void
migrate(Path oldFilePath, String libraryId, BibDatabaseContext bibDatabaseContext, ChatHistoryRepository repository, NotificationService notificationService)

private static boolean
migrateOldMap(String oldMapName, String libraryId, BibDatabaseContext bibDatabaseContext, ChatHistoryRepository repository, MVStore oldMvStore)

private static boolean
pathMatchesCurrentLibrary(String pathPrefix, BibDatabaseContext bibDatabaseContext)

Returns true if pathPrefix (extracted from an old map name) refers to the same file as the current library.

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

ENTRY_CHAT_HISTORY_INFIXback to summary
private static final String ENTRY_CHAT_HISTORY_INFIX
GROUP_CHAT_HISTORY_INFIXback to summary
private static final String GROUP_CHAT_HISTORY_INFIX
LOGGERback to summary
private static final Logger LOGGER
OLD_CHAT_HISTORY_FILE_NAMEback to summary
private static final String OLD_CHAT_HISTORY_FILE_NAME
OLD_CHAT_HISTORY_RECORD_CLASSback to summary
private static final String OLD_CHAT_HISTORY_RECORD_CLASS

Old inner class full name that is no longer in the classpath. Was: private record ChatHistoryRecord inside MVStoreChatHistoryStorage.

Constructor Detail

ChatHistoryMigrationV1back to summary
private ChatHistoryMigrationV1()

Method Detail

convertToNewChatMessageback to summary
private static ChatMessage convertToNewChatMessage(ChatHistoryRecord oldRecord, Instant timestamp)
deserializeOldRecordback to summary
private static ChatHistoryRecord deserializeOldRecord(byte[] data)

Deserializes old ChatHistoryRecord bytes using a remapping ObjectInputStream. Remaps the deleted inner class name to the current ChatHistoryRecord.

isOldChatHistoryMapback to summary
private static boolean isOldChatHistoryMap(String mapName)
migrateback to summary
public static void migrate(BibDatabaseContext bibDatabaseContext, ChatHistoryRepository repository, NotificationService notificationService)

Migrates old chat history data from v1 file to v2 repository.

Parameters
bibDatabaseContext:BibDatabaseContext

The database context containing the AI library ID

repository:ChatHistoryRepository

The new v2 chat history repository to migrate to

notificationService:NotificationService

Service for notifying user of errors

migrateback to summary
public static void migrate(Path oldFilePath, String libraryId, BibDatabaseContext bibDatabaseContext, ChatHistoryRepository repository, NotificationService notificationService)
migrateOldMapback to summary
private static boolean migrateOldMap(String oldMapName, String libraryId, BibDatabaseContext bibDatabaseContext, ChatHistoryRepository repository, MVStore oldMvStore)
pathMatchesCurrentLibraryback to summary
private static boolean pathMatchesCurrentLibrary(String pathPrefix, BibDatabaseContext bibDatabaseContext)

Returns true if pathPrefix (extracted from an old map name) refers to the same file as the current library.

  • If the prefix is an absolute path, it is compared after normalization.
  • If the prefix is a relative path, the current library's absolute path is checked with Path#endsWith(Path), so a/lib1.bib matches D:/my/a/lib1.bib.
org.jabref.logic.ai.chatting.migrations back to summary

private Class ChatHistoryMigrationV1.ClassRemappingObjectInputStream

extends ObjectInputStream
Class Inheritance

Custom ObjectInputStream that remaps the deleted old inner class name to the current ChatHistoryRecord class.

The old and new records have identical components (className: String, content: String), so Java record deserialization will call the canonical constructor successfully.

Constructor Summary

AccessConstructor and Description
public

Method Summary

Modifier and TypeMethod and Description
protected ObjectStreamClass
readClassDescriptor()

Overrides java.io.ObjectInputStream.readClassDescriptor.

Read a class descriptor from the serialization stream.

Inherited from java.io.ObjectInputStream:
availableclosedefaultReadObjectenableResolveObjectgetObjectInputFilterreadreadreadBooleanreadBytereadCharreadDoublereadFieldsreadFloatreadFullyreadFullyreadIntreadLinereadLongreadObjectreadObjectOverridereadShortreadStreamHeaderreadUnsharedreadUnsignedBytereadUnsignedShortreadUTFregisterValidationresolveClassresolveObjectresolveProxyClasssetObjectInputFilterskipBytes

Constructor Detail

ClassRemappingObjectInputStreamback to summary
public ClassRemappingObjectInputStream(InputStream in) throws IOException

Method Detail

readClassDescriptorback to summary
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException

Overrides java.io.ObjectInputStream.readClassDescriptor.

Doc from java.io.ObjectInputStream.readClassDescriptor.

Read a class descriptor from the serialization stream. This method is called when the ObjectInputStream expects a class descriptor as the next item in the serialization stream. Subclasses of ObjectInputStream may override this method to read in class descriptors that have been written in non-standard formats (by subclasses of ObjectOutputStream which have overridden the writeClassDescriptor method). By default, this method reads class descriptors according to the format defined in the Object Serialization specification.

Annotations
@Override
Exceptions
IOException:
If an I/O error has occurred.
ClassNotFoundException:
If the Class of a serialized object used in the class descriptor representation cannot be found
org.jabref.logic.ai.chatting.migrations back to summary

private Class ChatHistoryMigrationV1.RawBytesDataType

extends BasicDataType<byte[]>
Class Inheritance

Reads raw Java-serialized bytes from MVStore's binary page format without invoking Java deserialization. MVStore's ObjectDataType stores each serializable value as:
  1. 1 byte: type identifier — 19 (TYPE_SERIALIZED_OBJECT in H2 2.3.232)
  2. VarInt: byte length of the serialized payload
  3. N bytes: the raw Java-serialized payload

Field Summary

Modifier and TypeField and Description
private static final int

Constructor Summary

AccessConstructor and Description
private

Method Summary

Modifier and TypeMethod and Description
public byte[][]
createStorage(int size)

Implements org.h2.mvstore.type.DataType.createStorage.

Create storage object of array type to hold values

public int
getMemory(byte[] obj)

Implements abstract org.h2.mvstore.type.BasicDataType.getMemory.

Implements org.h2.mvstore.type.DataType.getMemory.

Calculates the amount of used memory in bytes.

public byte[]
read(ByteBuffer buff)

Implements abstract org.h2.mvstore.type.BasicDataType.read.

Implements org.h2.mvstore.type.DataType.read.

Read an object.

private static int
public void
write(WriteBuffer buff, byte[] obj)

Implements abstract org.h2.mvstore.type.BasicDataType.write.

Implements org.h2.mvstore.type.DataType.write.

Write an object.

Inherited from org.h2.mvstore.type.BasicDataType:
binarySearchcastcompareequalshashCodeisMemoryEstimationAllowedreadwrite

Field Detail

TYPE_SERIALIZED_OBJECTback to summary
private static final int TYPE_SERIALIZED_OBJECT

Constructor Detail

RawBytesDataTypeback to summary
private RawBytesDataType()

Method Detail

createStorageback to summary
public byte[][] createStorage(int size)

Implements org.h2.mvstore.type.DataType.createStorage.

Doc from org.h2.mvstore.type.DataType.createStorage.

Create storage object of array type to hold values

Annotations
@Override
getMemoryback to summary
public int getMemory(byte[] obj)

Implements abstract org.h2.mvstore.type.BasicDataType.getMemory.

Implements org.h2.mvstore.type.DataType.getMemory.

Doc from org.h2.mvstore.type.DataType.getMemory.

Calculates the amount of used memory in bytes.

Annotations
@Override
readback to summary
public byte[] read(ByteBuffer buff)

Implements abstract org.h2.mvstore.type.BasicDataType.read.

Implements org.h2.mvstore.type.DataType.read.

Doc from org.h2.mvstore.type.DataType.read.

Read an object.

Annotations
@Override
readVarIntback to summary
private static int readVarInt(ByteBuffer buff)
writeback to summary
public void write(WriteBuffer buff, byte[] obj)

Implements abstract org.h2.mvstore.type.BasicDataType.write.

Implements org.h2.mvstore.type.DataType.write.

Doc from org.h2.mvstore.type.DataType.write.

Write an object.

Annotations
@Override