From 622cb69b5c24518451bf651f15182ff38a728ba8 Mon Sep 17 00:00:00 2001 From: Carolyn Russell Date: Mon, 14 Nov 2022 23:11:47 -0700 Subject: [PATCH] Upgrade Kotlin * Plus many more versions -> see CHANGELOG.md for full list closes: #342 --- CHANGELOG.md | 17 ++++++++++ build.gradle.kts | 4 +-- buildSrc/src/main/kotlin/Dependencies.kt | 29 ++++++++-------- docker/Dockerfile-service | 2 +- gradle.properties | 1 - gradle/wrapper/gradle-wrapper.properties | 2 +- service/build.gradle.kts | 1 + .../io/provenance/explorer/Application.kt | 14 ++++---- .../explorer/config/SwaggerConfig.kt | 34 +++++++++++++++++++ .../explorer/domain/entities/Blocks.kt | 2 +- .../explorer/service/ExplorerService.kt | 9 +++-- .../explorer/service/PricingService.kt | 5 +-- .../explorer/service/TokenService.kt | 5 +-- .../explorer/service/ValidatorService.kt | 9 +++-- .../explorer/service/async/AsyncService.kt | 4 +-- .../src/main/resources/application.properties | 3 ++ 16 files changed, 99 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b9aecca..1979e854 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,23 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## Unreleased +### Improvements +* Updated Kotlin version `1.5.31` -> `1.6.21` #342 + * Gradle `7.3.3` -> `7.4.2` + * SpringBoot `2.5.6` -> `2.6.6` + * Kotlin Coroutines `1.5.2` -> `1.6.4` + * Apache commons-text `1.9` -> `1.10` + * Apache HttClient `4.5.12` -> `5.2` + * BouncyCastle `1.69` -> `1.70` + * Exposed `0.34.1` -> `0.38.2` + * Jackson `2.12.5` -> `2.13.2` + * Jackson Protobuf `0.9.12` -> `0.9.13` + * Ktor `1.5.7` -> `2.1.3` + * Grpc `1.40.1` -> `1.50.2` + * Protobuf `3.19.1` -> `3.21.9` + * NOTE: These updates had minimal impact, but the Springfox 3.0.0 and Springboot 2.6.x do not play nicely. Had + to add a hacky fix; will probably set some time aside to switch to SpringDoc. + ## [v5.3.2](https://github.com/provenance-io/explorer-service/releases/tag/v5.3.2) - 2022-11-14 ### Release Name: Afonso Gonçalves Baldaia diff --git a/build.gradle.kts b/build.gradle.kts index 104fbe37..097da5f9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -52,8 +52,8 @@ subprojects { "-Xopt-in=kotlin.contracts.ExperimentalContracts" ) jvmTarget = "11" - languageVersion = "1.5" - apiVersion = "1.5" + languageVersion = "1.6" + apiVersion = "1.6" } } diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 4fe7f98c..e25c1be8 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -21,7 +21,7 @@ object PluginIds { // please keep this sorted in sections object PluginVersions { // please keep this sorted in sections // Kotlin - const val Kotlin = "1.5.31" + const val Kotlin = "1.6.21" // 3rd Party const val Flyway = "7.15.0" @@ -31,32 +31,32 @@ object PluginVersions { // please keep this sorted in sections const val GoryLenkoGitProps = "1.5.2" const val SpringDependency = "1.0.11.RELEASE" - const val SpringBoot = "2.5.6" + const val SpringBoot = "2.6.6" } object Versions { // kotlin const val Kotlin = PluginVersions.Kotlin - const val KotlinXCoroutines = "1.5.2" + const val KotlinXCoroutines = "1.6.4" // 3rd Party - const val ApacheCommonsText = "1.9" + const val ApacheCommonsText = "1.10.0" const val ApacheCommonsCsv = "1.9.0" - const val ApacheHttpClient = "4.5.12" - const val BouncyCastle = "1.69" - const val Exposed = "0.34.1" + const val ApacheHttpClient = "5.2" + const val BouncyCastle = "1.70" + const val Exposed = "0.38.2" const val Flyway = PluginVersions.Flyway - const val Jackson = "2.12.5" - const val JacksonProtobuf = "0.9.12" + const val Jackson = "2.13.2" + const val JacksonProtobuf = "0.9.13" const val Json = "20211205" const val KaseChange = "1.3.0" - const val Ktor = "1.6.7" + const val Ktor = "2.1.3" const val SpringBoot = PluginVersions.SpringBoot const val Swagger = "3.0.0" - const val Grpc = "1.40.1" + const val Grpc = "1.50.2" const val ProvProto = "1.12.0" const val Postgres = "42.2.23" - const val Protobuf = "3.19.1" + const val Protobuf = "3.21.9" // Testing const val Jupiter = "5.7.1" @@ -85,10 +85,11 @@ object Libraries { const val BouncyCastle = "org.bouncycastle:bcprov-jdk15on:${Versions.BouncyCastle}" const val ApacheCommonsText = "org.apache.commons:commons-text:${Versions.ApacheCommonsText}" const val ApacheCommonsCsv = "org.apache.commons:commons-csv:${Versions.ApacheCommonsCsv}" - const val ApacheHttpClient = "org.apache.httpcomponents:httpclient:${Versions.ApacheHttpClient}" + const val ApacheHttpClient = "org.apache.httpcomponents.client5:httpclient5:${Versions.ApacheHttpClient}" const val KtorClientCore = "io.ktor:ktor-client-core:${Versions.Ktor}" const val KtorClientEngineJava = "io.ktor:ktor-client-java:${Versions.Ktor}" - const val KtorClientSerialization = "io.ktor:ktor-client-jackson:${Versions.Ktor}" + const val KtorClientSerialization = "io.ktor:ktor-serialization-jackson:${Versions.Ktor}" + const val KtorClientContentNeg = "io.ktor:ktor-client-content-negotiation:${Versions.Ktor}" const val KaseChange = "net.pearx.kasechange:kasechange:${Versions.KaseChange}" const val Json = "org.json:json:${Versions.Json}" diff --git a/docker/Dockerfile-service b/docker/Dockerfile-service index 4db291f0..7847d902 100644 --- a/docker/Dockerfile-service +++ b/docker/Dockerfile-service @@ -1,4 +1,4 @@ -FROM gradle:7.3.3-jdk11 AS build +FROM gradle:7.4.2-jdk11 AS build RUN gradle --version && java -version WORKDIR /app diff --git a/gradle.properties b/gradle.properties index fdf9bf8b..780b115b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,3 @@ kotlin.code.style=official -kapt.use.worker.api=false kapt.incremental.apt=false org.gradle.jvmargs=-Xmx4096M diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2e6e5897..aa991fce 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/service/build.gradle.kts b/service/build.gradle.kts index 7e18255c..61865909 100644 --- a/service/build.gradle.kts +++ b/service/build.gradle.kts @@ -43,6 +43,7 @@ dependencies { implementation(Libraries.KtorClientCore) implementation(Libraries.KtorClientEngineJava) implementation(Libraries.KtorClientSerialization) + implementation(Libraries.KtorClientContentNeg) implementation(Libraries.Json) implementation(Libraries.GrpcNetty) diff --git a/service/src/main/kotlin/io/provenance/explorer/Application.kt b/service/src/main/kotlin/io/provenance/explorer/Application.kt index 2731457c..b607d2d5 100644 --- a/service/src/main/kotlin/io/provenance/explorer/Application.kt +++ b/service/src/main/kotlin/io/provenance/explorer/Application.kt @@ -1,12 +1,12 @@ package io.provenance.explorer import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.PropertyNamingStrategy +import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.node.JsonNodeFactory import io.ktor.client.HttpClient import io.ktor.client.engine.java.Java -import io.ktor.client.features.json.JacksonSerializer -import io.ktor.client.features.json.JsonFeature +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.serialization.jackson.jackson import io.provenance.explorer.config.ExplorerProperties import io.provenance.explorer.domain.extensions.configureProvenance import org.springframework.boot.autoconfigure.EnableAutoConfiguration @@ -35,7 +35,7 @@ fun main(args: Array) { } val OBJECT_MAPPER = ObjectMapper() - .setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE) + .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE) .configureProvenance() val VANILLA_MAPPER = ObjectMapper().configureProvenance() @@ -44,7 +44,9 @@ val VANILLA_MAPPER = ObjectMapper().configureProvenance() val JSON_NODE_FACTORY: JsonNodeFactory = JsonNodeFactory.instance val KTOR_CLIENT_JAVA = HttpClient(Java) { - install(JsonFeature) { - serializer = JacksonSerializer(VANILLA_MAPPER) + install(ContentNegotiation) { + jackson { + this.configureProvenance() + } } } diff --git a/service/src/main/kotlin/io/provenance/explorer/config/SwaggerConfig.kt b/service/src/main/kotlin/io/provenance/explorer/config/SwaggerConfig.kt index 31bad5e8..9a866c4d 100644 --- a/service/src/main/kotlin/io/provenance/explorer/config/SwaggerConfig.kt +++ b/service/src/main/kotlin/io/provenance/explorer/config/SwaggerConfig.kt @@ -1,11 +1,15 @@ package io.provenance.explorer.config import io.provenance.explorer.domain.annotation.HiddenApi +import org.springframework.beans.BeansException +import org.springframework.beans.factory.config.BeanPostProcessor import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.HttpHeaders.AUTHORIZATION import org.springframework.http.MediaType +import org.springframework.util.ReflectionUtils +import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping import springfox.documentation.builders.RequestHandlerSelectors import springfox.documentation.service.ApiInfo import springfox.documentation.service.ApiKey @@ -14,6 +18,8 @@ import springfox.documentation.service.SecurityReference import springfox.documentation.spi.DocumentationType import springfox.documentation.spi.service.contexts.SecurityContext import springfox.documentation.spring.web.plugins.Docket +import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider +import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider import java.util.function.Predicate @EnableConfigurationProperties( @@ -61,4 +67,32 @@ class SwaggerConfig(val props: ExplorerProperties) { return docket.build() } + + @Suppress("UNCHECKED_CAST") + @Bean + fun springfoxHandlerProviderBeanPostProcessor(): BeanPostProcessor? { + return object : BeanPostProcessor { + @Throws(BeansException::class) + override fun postProcessAfterInitialization(bean: Any, beanName: String): Any { + if (bean is WebMvcRequestHandlerProvider || bean is WebFluxRequestHandlerProvider) { + customizeSpringfoxHandlerMappings(getHandlerMappings(bean)) + } + return bean + } + + private fun customizeSpringfoxHandlerMappings(mappings: MutableList) { + mappings.removeIf { mapping -> mapping?.patternParser != null } + } + + private fun getHandlerMappings(bean: Any): MutableList { + return try { + val field = ReflectionUtils.findField(bean.javaClass, "handlerMappings") + field?.isAccessible = true + field?.get(bean) as MutableList + } catch (e: Exception) { + throw IllegalStateException(e) + } + } + } + } } diff --git a/service/src/main/kotlin/io/provenance/explorer/domain/entities/Blocks.kt b/service/src/main/kotlin/io/provenance/explorer/domain/entities/Blocks.kt index 6bf5ae64..690a84dd 100644 --- a/service/src/main/kotlin/io/provenance/explorer/domain/entities/Blocks.kt +++ b/service/src/main/kotlin/io/provenance/explorer/domain/entities/Blocks.kt @@ -433,7 +433,7 @@ class BlockCacheHourlyTxCountsRecord(id: EntityID) : Entity( var txCount by BlockCacheHourlyTxCountsTable.txCount } -object BlockTxCountsCacheTable : IntIdTable(name = "block_tx_count_cache") { +object BlockTxCountsCacheTable : IdTable(name = "block_tx_count_cache") { val blockHeight = integer("block_height") val blockTimestamp = datetime("block_timestamp") val txCount = integer("tx_count").default(0) diff --git a/service/src/main/kotlin/io/provenance/explorer/service/ExplorerService.kt b/service/src/main/kotlin/io/provenance/explorer/service/ExplorerService.kt index 255cf663..fafe9636 100644 --- a/service/src/main/kotlin/io/provenance/explorer/service/ExplorerService.kt +++ b/service/src/main/kotlin/io/provenance/explorer/service/ExplorerService.kt @@ -5,10 +5,9 @@ import com.google.protobuf.util.JsonFormat import cosmos.bank.v1beta1.params import cosmos.base.tendermint.v1beta1.Query import cosmos.gov.v1beta1.Gov -import io.ktor.client.call.receive -import io.ktor.client.features.ResponseException +import io.ktor.client.call.body +import io.ktor.client.plugins.ResponseException import io.ktor.client.request.get -import io.ktor.client.statement.HttpResponse import io.provenance.explorer.KTOR_CLIENT_JAVA import io.provenance.explorer.VANILLA_MAPPER import io.provenance.explorer.config.ExplorerProperties @@ -260,14 +259,14 @@ class ExplorerService( fun getChainReleases(page: Int, count: Int): MutableList = runBlocking { val url = "https://api.github.com/repos/${props.upgradeGithubRepo}/releases?per_page=$count&page=$page" val res = try { - KTOR_CLIENT_JAVA.get(url) + KTOR_CLIENT_JAVA.get(url) } catch (e: ResponseException) { return@runBlocking mutableListOf().also { logger.error("Error: ${e.response}") } } if (res.status.value == 200) { try { - JSONArray(res.receive()).mapNotNull { ele -> + JSONArray(res.body()).mapNotNull { ele -> if (ele is JSONObject) { GithubReleaseData( ele.getString("tag_name"), diff --git a/service/src/main/kotlin/io/provenance/explorer/service/PricingService.kt b/service/src/main/kotlin/io/provenance/explorer/service/PricingService.kt index a50a7ced..32ae40c0 100644 --- a/service/src/main/kotlin/io/provenance/explorer/service/PricingService.kt +++ b/service/src/main/kotlin/io/provenance/explorer/service/PricingService.kt @@ -1,6 +1,7 @@ package io.provenance.explorer.service -import io.ktor.client.features.ResponseException +import io.ktor.client.call.body +import io.ktor.client.plugins.ResponseException import io.ktor.client.request.get import io.ktor.client.request.parameter import io.provenance.explorer.KTOR_CLIENT_JAVA @@ -63,7 +64,7 @@ class PricingService( try { KTOR_CLIENT_JAVA.get("${props.pricingUrl}/api/v1/pricing/marker/new") { parameter("time", time) - } + }.body() } catch (e: ResponseException) { return@runBlocking listOf() .also { logger.error("Error coming from $comingFrom: ${e.response}") } diff --git a/service/src/main/kotlin/io/provenance/explorer/service/TokenService.kt b/service/src/main/kotlin/io/provenance/explorer/service/TokenService.kt index 93c0cdd9..5350bf49 100644 --- a/service/src/main/kotlin/io/provenance/explorer/service/TokenService.kt +++ b/service/src/main/kotlin/io/provenance/explorer/service/TokenService.kt @@ -2,7 +2,8 @@ package io.provenance.explorer.service import com.fasterxml.jackson.module.kotlin.readValue import cosmos.auth.v1beta1.Auth -import io.ktor.client.features.ResponseException +import io.ktor.client.call.body +import io.ktor.client.plugins.ResponseException import io.ktor.client.request.accept import io.ktor.client.request.get import io.ktor.client.request.parameter @@ -226,7 +227,7 @@ class TokenService( parameter("type", "buy") parameter("start_time", DateTimeFormat.forPattern("dd-MM-yyyy").print(startTime)) accept(ContentType.Application.Json) - } + }.body() } catch (e: ResponseException) { return@runBlocking null.also { logger.error("Error fetching from Dlob: ${e.response}") } } catch (e: Exception) { diff --git a/service/src/main/kotlin/io/provenance/explorer/service/ValidatorService.kt b/service/src/main/kotlin/io/provenance/explorer/service/ValidatorService.kt index 4b806bcd..36e37b66 100644 --- a/service/src/main/kotlin/io/provenance/explorer/service/ValidatorService.kt +++ b/service/src/main/kotlin/io/provenance/explorer/service/ValidatorService.kt @@ -2,11 +2,10 @@ package io.provenance.explorer.service import cosmos.base.tendermint.v1beta1.Query import cosmos.staking.v1beta1.Staking -import io.ktor.client.call.receive -import io.ktor.client.features.ResponseException +import io.ktor.client.call.body +import io.ktor.client.plugins.ResponseException import io.ktor.client.request.get import io.ktor.client.request.parameter -import io.ktor.client.statement.HttpResponse import io.provenance.explorer.KTOR_CLIENT_JAVA import io.provenance.explorer.config.ExplorerProperties.Companion.PROV_ACC_PREFIX import io.provenance.explorer.config.ExplorerProperties.Companion.PROV_VAL_CONS_PREFIX @@ -476,7 +475,7 @@ class ValidatorService( fun getImgUrl(identityStr: String) = runBlocking { if (identityStr.isNotBlank()) { val res = try { - KTOR_CLIENT_JAVA.get("https://keybase.io/_/api/1.0/user/lookup.json") { + KTOR_CLIENT_JAVA.get("https://keybase.io/_/api/1.0/user/lookup.json") { parameter("key_suffix", identityStr) parameter("fields", "pictures") } @@ -486,7 +485,7 @@ class ValidatorService( if (res.status.value in 200..299) { try { - JSONObject(res.receive()).getJSONArray("them").let { + JSONObject(res.body()).getJSONArray("them").let { if (it.length() > 0) { val them = it.getJSONObject(0) if (them.has("pictures")) diff --git a/service/src/main/kotlin/io/provenance/explorer/service/async/AsyncService.kt b/service/src/main/kotlin/io/provenance/explorer/service/async/AsyncService.kt index 45b2112e..0c1dc06a 100644 --- a/service/src/main/kotlin/io/provenance/explorer/service/async/AsyncService.kt +++ b/service/src/main/kotlin/io/provenance/explorer/service/async/AsyncService.kt @@ -55,7 +55,7 @@ import org.jetbrains.exposed.sql.SortOrder import org.jetbrains.exposed.sql.andWhere import org.jetbrains.exposed.sql.deleteWhere import org.jetbrains.exposed.sql.innerJoin -import org.jetbrains.exposed.sql.insert +import org.jetbrains.exposed.sql.insertIgnore import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.transactions.transaction import org.joda.time.DateTime @@ -378,7 +378,7 @@ class AsyncService( TxMsgTypeSubtypeTable.deleteWhere { TxMsgTypeSubtypeTable.id inList it } } secondaries.forEach { secId -> - TxMsgTypeSubtypeTable.insert { + TxMsgTypeSubtypeTable.insertIgnore { it[this.txMsgId] = msgId.txMsgId it[this.primaryType] = primId it[this.secondaryType] = secId diff --git a/service/src/main/resources/application.properties b/service/src/main/resources/application.properties index 8e0cff00..0c42a327 100644 --- a/service/src/main/resources/application.properties +++ b/service/src/main/resources/application.properties @@ -12,3 +12,6 @@ logging.level.io.provenance.timed=warn logging.level.Exposed=ERROR spring.task.scheduling.pool.size=20 + +spring.mvc.pathmatch.matching-strategy=ant_path_matcher +spring.main.allow-bean-definition-overriding=true