diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt index 50a579fedd1..5754471d290 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt @@ -55,7 +55,7 @@ import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererCon import software.aws.toolkits.jetbrains.services.amazonq.SUPPLEMENTAL_CONTEXT_TIMEOUT import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.GetConfigurationFromServerParams -import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.LspServerConfigurations +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.Workspaces import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererModelConfigurator @@ -706,12 +706,12 @@ class CodeWhispererService(private val cs: CoroutineScope) : Disposable { ) } - private fun getWorkspaceIds(project: Project): CompletableFuture { + private fun getWorkspaceIds(project: Project): CompletableFuture { val payload = GetConfigurationFromServerParams( section = "aws.q.workspaceContext" ) return AmazonQLspService.executeIfRunning(project) { server -> - server.getConfigurationFromServer(payload) + server.getConfigurationFromServer(payload) as CompletableFuture } ?: (CompletableFuture.failedFuture(IllegalStateException("LSP Server not running"))) } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageServer.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageServer.kt index 18cf95d3973..23e62fcbfeb 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageServer.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageServer.kt @@ -8,7 +8,7 @@ import org.eclipse.lsp4j.jsonrpc.services.JsonNotification import org.eclipse.lsp4j.jsonrpc.services.JsonRequest import org.eclipse.lsp4j.services.LanguageServer import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.GetConfigurationFromServerParams -import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.LspServerConfigurations +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.GetConfigurationFromServerResponse import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.credentials.UpdateCredentialsPayload import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.dependencies.DidChangeDependencyPathsParams import java.util.concurrent.CompletableFuture @@ -28,5 +28,5 @@ interface AmazonQLanguageServer : LanguageServer { fun deleteTokenCredentials(): CompletableFuture @JsonRequest("aws/getConfigurationFromServer") - fun getConfigurationFromServer(params: GetConfigurationFromServerParams): CompletableFuture + fun getConfigurationFromServer(params: GetConfigurationFromServerParams): CompletableFuture } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt index 59658c3a878..6e855a6f387 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLspService.kt @@ -50,6 +50,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.artifacts.ArtifactMa import software.aws.toolkits.jetbrains.services.amazonq.lsp.auth.DefaultAuthCredentialsService import software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.DefaultModuleDependenciesService import software.aws.toolkits.jetbrains.services.amazonq.lsp.encryption.JwtEncryptionManager +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.adapter.GetConfigurationFromServerResponseTypeAdapterFactory import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.createExtendedClientMetadata import software.aws.toolkits.jetbrains.services.amazonq.lsp.textdocument.TextDocumentServiceHandler import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.WorkspaceFolderUtil.createWorkspaceFolders @@ -272,6 +273,9 @@ private class AmazonQServerInstance(private val project: Project, private val cs // otherwise Gson treats all numbers as double which causes deser issues it.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE) + + // type adapter factory for polymorphic deserialization + it.registerTypeAdapterFactory(GetConfigurationFromServerResponseTypeAdapterFactory()) }.traceMessages( PrintWriter( object : StringWriter() { diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/adapter/GetConfigurationFromServerResponseTypeAdapterFactory.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/adapter/GetConfigurationFromServerResponseTypeAdapterFactory.kt new file mode 100644 index 00000000000..6e7aec548d9 --- /dev/null +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/adapter/GetConfigurationFromServerResponseTypeAdapterFactory.kt @@ -0,0 +1,52 @@ +// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package software.aws.toolkits.jetbrains.services.amazonq.lsp.model.adapter + +import com.google.gson.Gson +import com.google.gson.JsonElement +import com.google.gson.TypeAdapter +import com.google.gson.TypeAdapterFactory +import com.google.gson.reflect.TypeToken +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.Customizations +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.GetConfigurationFromServerResponse +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.Workspaces + +class GetConfigurationFromServerResponseTypeAdapterFactory : TypeAdapterFactory { + override fun create(gson: Gson, type: TypeToken): TypeAdapter? { + // Only handle GetConfigurationFromServerResponse + if (GetConfigurationFromServerResponse::class.java != type.rawType) { + return null + } + + val delegateAdapter = gson.getDelegateAdapter(this, type) + val elementAdapter = gson.getAdapter(JsonElement::class.java) + + @Suppress("UNCHECKED_CAST") + return object : TypeAdapter() { + override fun write(out: JsonWriter, value: T) { + delegateAdapter.write(out, value) + } + + override fun read(reader: JsonReader): T? { + val jsonElement = elementAdapter.read(reader) + if (!jsonElement.isJsonObject) { + return null + } + + val jsonObject = jsonElement.asJsonObject + + val ret = when { + jsonObject.has("workspaces") -> gson.fromJson(jsonElement, Workspaces::class.java) + jsonObject.has("customizations") -> gson.fromJson(jsonElement, Customizations::class.java) + else -> delegateAdapter.fromJsonTree(jsonElement) + } as T + + return ret + } + } + } +} + diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/LspServerConfigurations.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/LspServerConfigurations.kt index e762b938d28..b30cbc425f6 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/LspServerConfigurations.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/LspServerConfigurations.kt @@ -3,8 +3,11 @@ package software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws -// This represents each item in the array -data class WorkspaceInfo(val workspaceRoot: String, val workspaceId: String) +interface GetConfigurationFromServerResponse // This represents the entire array -data class LspServerConfigurations(val workspaces: List) +data class Workspaces(val workspaces: List): GetConfigurationFromServerResponse +data class Customizations(val customizations: List): GetConfigurationFromServerResponse + +data class WorkspaceInfo(val workspaceRoot: String, val workspaceId: String) +data class Customization(val arn: String, val name: String, val description: String)