Skip to content

Commit 6728a8f

Browse files
author
Samuel Vazquez
committed
feat: integrate fastjson2
1 parent c20b8c6 commit 6728a8f

File tree

18 files changed

+297
-127
lines changed

18 files changed

+297
-127
lines changed

gradle/libs.versions.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ kotlinx-coroutines = "1.8.1"
1313
# TODO kotlin 1.9 upgrade: fix GraphQLTestUtils and GenerateKotlinxClientIT
1414
kotlinx-serialization = "1.6.3"
1515
ktor = "2.3.12"
16+
fastjson2 = "2.0.53"
1617
maven-plugin-annotation = "3.13.1"
1718
maven-plugin-api = "3.9.8"
1819
maven-project = "2.2.1"
@@ -86,6 +87,8 @@ spring-boot-netty = { group = "org.springframework.boot", name = "spring-boot-st
8687
spring-boot-webflux = { group = "org.springframework.boot", name = "spring-boot-starter-webflux", version.ref = "spring-boot" }
8788
spring-webflux = { group = "org.springframework", name = "spring-webflux", version.ref = "spring" }
8889
spring-context = { group = "org.springframework", name = "spring-context", version.ref = "spring" }
90+
fastjson2 = { group = "com.alibaba.fastjson2", name = "fastjson2-kotlin", version.ref = "fastjson2" }
91+
fastjson2-spring = { group = "com.alibaba.fastjson2", name = "fastjson2-extension-spring6", version.ref = "fastjson2" }
8992

9093
# security vulnerabilities overrides
9194
commons-codec = { group = "commons-codec", name = "commons-codec", version.ref = "commons-codec" }

plugins/server/graphql-kotlin-graalvm-metadata-generator/src/main/resources/default-reflect-config.json

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -120,22 +120,6 @@
120120
"allDeclaredFields": true,
121121
"queryAllDeclaredMethods": true
122122
},
123-
{
124-
"name":"com.expediagroup.graphql.server.types.GraphQLRequest",
125-
"fields":[{"name":"Companion"}]
126-
},
127-
{
128-
"name":"com.expediagroup.graphql.server.types.GraphQLRequest$Companion",
129-
"methods":[{"name":"serializer","parameterTypes":[] }]
130-
},
131-
{
132-
"name":"com.expediagroup.graphql.server.types.GraphQLBatchRequest",
133-
"fields":[{"name":"Companion"}]
134-
},
135-
{
136-
"name":"com.expediagroup.graphql.server.types.GraphQLBatchRequest$Companion",
137-
"methods":[{"name":"serializer","parameterTypes":[] }]
138-
},
139123
{
140124
"name": "com.expediagroup.graphql.server.types.GraphQLServerRequestDeserializer",
141125
"methods": [

servers/graphql-kotlin-server/build.gradle.kts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@ description = "Common code for running a GraphQL server in any HTTP server frame
55
plugins {
66
id("com.expediagroup.graphql.conventions")
77
alias(libs.plugins.benchmark)
8-
alias(libs.plugins.kotlin.serialization)
98
}
109

1110
dependencies {
1211
api(projects.graphqlKotlinSchemaGenerator)
1312
api(projects.graphqlKotlinDataloaderInstrumentation)
1413
api(projects.graphqlKotlinAutomaticPersistedQueries)
1514
api(libs.jackson)
16-
api(libs.kotlinx.serialization.json)
15+
api(libs.fastjson2)
1716
testImplementation(libs.kotlinx.coroutines.test)
1817
testImplementation(libs.logback)
1918
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2024 Expedia, Inc
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.expediagroup.graphql.server
18+
19+
import com.alibaba.fastjson2.JSON
20+
import com.alibaba.fastjson2.JSONWriter
21+
import com.alibaba.fastjson2.to
22+
import com.expediagroup.graphql.server.types.GraphQLServerRequest
23+
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
24+
import com.fasterxml.jackson.module.kotlin.readValue
25+
import org.openjdk.jmh.annotations.Benchmark
26+
import org.openjdk.jmh.annotations.Fork
27+
import org.openjdk.jmh.annotations.Measurement
28+
import org.openjdk.jmh.annotations.Scope
29+
import org.openjdk.jmh.annotations.Setup
30+
import org.openjdk.jmh.annotations.State
31+
import org.openjdk.jmh.annotations.Warmup
32+
import java.util.concurrent.TimeUnit
33+
34+
@State(Scope.Benchmark)
35+
@Fork(value = 5, jvmArgsAppend = ["--add-modules=jdk.incubator.vector", "-Dfastjson2.readerVector=true"])
36+
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
37+
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
38+
open class GraphQLServerBatchRequestDeserializationBenchmark {
39+
private val mapper = jacksonObjectMapper()
40+
private lateinit var request: String
41+
private lateinit var batchRequest: String
42+
43+
@Setup
44+
fun setUp() {
45+
JSON.config(JSONWriter.Feature.WriteNulls)
46+
val loader = this::class.java.classLoader
47+
val operation = loader.getResource("StarWarsDetails.graphql")!!.readText().replace("\n", "\\n")
48+
val variables = loader.getResource("StarWarsDetailsVariables.json")!!.readText()
49+
batchRequest = """
50+
[
51+
{ "operationName": "StarWarsDetails", "query": "$operation", "variables": $variables },
52+
{ "operationName": "StarWarsDetails", "query": "$operation", "variables": $variables },
53+
{ "operationName": "StarWarsDetails", "query": "$operation", "variables": $variables },
54+
{ "operationName": "StarWarsDetails", "query": "$operation", "variables": $variables }
55+
]
56+
""".trimIndent()
57+
}
58+
59+
@Benchmark
60+
fun JacksonDeserializeGraphQLBatchRequest(): GraphQLServerRequest = mapper.readValue(batchRequest)
61+
62+
@Benchmark
63+
fun FastJsonDeserializeGraphQLBatchRequest(): GraphQLServerRequest = batchRequest.to<GraphQLServerRequest>()
64+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2024 Expedia, Inc
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.expediagroup.graphql.server
18+
19+
import com.alibaba.fastjson2.JSON
20+
import com.alibaba.fastjson2.JSONWriter
21+
import com.expediagroup.graphql.server.types.GraphQLBatchResponse
22+
import com.expediagroup.graphql.server.types.GraphQLResponse
23+
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
24+
import com.fasterxml.jackson.module.kotlin.readValue
25+
import org.openjdk.jmh.annotations.Benchmark
26+
import org.openjdk.jmh.annotations.Fork
27+
import org.openjdk.jmh.annotations.Measurement
28+
import org.openjdk.jmh.annotations.Scope
29+
import org.openjdk.jmh.annotations.Setup
30+
import org.openjdk.jmh.annotations.State
31+
import org.openjdk.jmh.annotations.Warmup
32+
import java.util.concurrent.TimeUnit
33+
34+
@State(Scope.Benchmark)
35+
@Fork(value = 5, jvmArgsAppend = ["--add-modules=jdk.incubator.vector", "-Dfastjson2.readerVector=true"])
36+
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
37+
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
38+
open class GraphQLServerBatchResponseSerializationBenchmark {
39+
private val mapper = jacksonObjectMapper()
40+
private lateinit var batchResponse: GraphQLBatchResponse
41+
42+
@Setup
43+
fun setUp() {
44+
JSON.config(JSONWriter.Feature.WriteNulls)
45+
val data = mapper.readValue<Map<String, Any?>>(
46+
this::class.java.classLoader.getResourceAsStream("StarWarsDetailsResponse.json")!!
47+
)
48+
batchResponse = GraphQLBatchResponse(
49+
listOf(
50+
GraphQLResponse(data),
51+
GraphQLResponse(data),
52+
GraphQLResponse(data),
53+
GraphQLResponse(data)
54+
)
55+
)
56+
}
57+
58+
@Benchmark
59+
fun JacksonSerializeGraphQLBatchResponse(): String = mapper.writeValueAsString(batchResponse)
60+
61+
@Benchmark
62+
fun FastJsonSerializeGraphQLBatchResponse(): String = JSON.toJSONString(batchResponse)
63+
}

servers/graphql-kotlin-server/src/benchmarks/kotlin/GraphQLServerRequestDeserializationBenchmark.kt

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616

1717
package com.expediagroup.graphql.server
1818

19-
import com.expediagroup.graphql.server.testtypes.GraphQLServerRequest
19+
import com.alibaba.fastjson2.JSON
20+
import com.alibaba.fastjson2.JSONWriter
21+
import com.alibaba.fastjson2.to
22+
import com.expediagroup.graphql.server.types.GraphQLServerRequest
2023
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
2124
import com.fasterxml.jackson.module.kotlin.readValue
22-
import kotlinx.serialization.json.Json
2325
import org.openjdk.jmh.annotations.Benchmark
2426
import org.openjdk.jmh.annotations.Fork
2527
import org.openjdk.jmh.annotations.Measurement
@@ -30,16 +32,16 @@ import org.openjdk.jmh.annotations.Warmup
3032
import java.util.concurrent.TimeUnit
3133

3234
@State(Scope.Benchmark)
33-
@Fork(5)
34-
@Warmup(iterations = 1, time = 5, timeUnit = TimeUnit.SECONDS)
35-
@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
35+
@Fork(value = 5, jvmArgsAppend = ["--add-modules=jdk.incubator.vector", "-Dfastjson2.readerVector=true"])
36+
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
37+
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
3638
open class GraphQLServerRequestDeserializationBenchmark {
3739
private val mapper = jacksonObjectMapper()
3840
private lateinit var request: String
39-
private lateinit var batchRequest: String
4041

4142
@Setup
4243
fun setUp() {
44+
JSON.config(JSONWriter.Feature.WriteNulls)
4345
val loader = this::class.java.classLoader
4446
val operation = loader.getResource("StarWarsDetails.graphql")!!.readText().replace("\n", "\\n")
4547
val variables = loader.getResource("StarWarsDetailsVariables.json")!!.readText()
@@ -50,25 +52,11 @@ open class GraphQLServerRequestDeserializationBenchmark {
5052
"variables": $variables
5153
}
5254
""".trimIndent()
53-
batchRequest = """
54-
[
55-
{ "operationName": "StarWarsDetails", "query": "$operation", "variables": $variables },
56-
{ "operationName": "StarWarsDetails", "query": "$operation", "variables": $variables },
57-
{ "operationName": "StarWarsDetails", "query": "$operation", "variables": $variables },
58-
{ "operationName": "StarWarsDetails", "query": "$operation", "variables": $variables }
59-
]
60-
""".trimIndent()
6155
}
6256

6357
@Benchmark
6458
fun JacksonDeserializeGraphQLRequest(): GraphQLServerRequest = mapper.readValue(request)
6559

6660
@Benchmark
67-
fun JacksonDeserializeGraphQLBatchRequest(): GraphQLServerRequest = mapper.readValue(batchRequest)
68-
69-
@Benchmark
70-
fun KSerializationDeserializeGraphQLRequest(): GraphQLServerRequest = Json.decodeFromString(request)
71-
72-
@Benchmark
73-
fun KSerializationDeserializeGraphQLBatchRequest(): GraphQLServerRequest = Json.decodeFromString(batchRequest)
61+
fun FastJsonDeserializeGraphQLRequest(): GraphQLServerRequest = request.to()
7462
}

servers/graphql-kotlin-server/src/benchmarks/kotlin/GraphQLServerResponseSerializationBenchmark.kt

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@
1616

1717
package com.expediagroup.graphql.server
1818

19-
import com.expediagroup.graphql.server.testtypes.GraphQLBatchResponse
19+
import com.alibaba.fastjson2.JSON
20+
import com.alibaba.fastjson2.JSONWriter
2021
import com.expediagroup.graphql.server.testtypes.GraphQLResponse
2122
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
2223
import com.fasterxml.jackson.module.kotlin.readValue
23-
import kotlinx.serialization.encodeToString
24-
import kotlinx.serialization.json.Json
2524
import org.openjdk.jmh.annotations.Benchmark
2625
import org.openjdk.jmh.annotations.Fork
2726
import org.openjdk.jmh.annotations.Measurement
@@ -32,16 +31,16 @@ import org.openjdk.jmh.annotations.Warmup
3231
import java.util.concurrent.TimeUnit
3332

3433
@State(Scope.Benchmark)
35-
@Fork(5)
36-
@Warmup(iterations = 1, time = 5, timeUnit = TimeUnit.SECONDS)
37-
@Measurement(iterations = 5, time = 10, timeUnit = TimeUnit.SECONDS)
34+
@Fork(value = 5, jvmArgsAppend = ["--add-modules=jdk.incubator.vector", "-Dfastjson2.readerVector=true"])
35+
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
36+
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
3837
open class GraphQLServerResponseSerializationBenchmark {
3938
private val mapper = jacksonObjectMapper()
4039
private lateinit var response: GraphQLResponse
41-
private lateinit var batchResponse: GraphQLBatchResponse
4240

4341
@Setup
4442
fun setUp() {
43+
JSON.config(JSONWriter.Feature.WriteNulls)
4544
val data = mapper.readValue<Map<String, Any?>>(
4645
this::class.java.classLoader.getResourceAsStream("StarWarsDetailsResponse.json")!!
4746
)
@@ -50,23 +49,11 @@ open class GraphQLServerResponseSerializationBenchmark {
5049
this::class.java.classLoader.getResourceAsStream("StarWarsDetailsResponse.json")!!
5150
)
5251
)
53-
batchResponse = GraphQLBatchResponse(
54-
GraphQLResponse(data),
55-
GraphQLResponse(data),
56-
GraphQLResponse(data),
57-
GraphQLResponse(data)
58-
)
5952
}
6053

6154
@Benchmark
6255
fun JacksonSerializeGraphQLResponse(): String = mapper.writeValueAsString(response)
6356

6457
@Benchmark
65-
fun JacksonSerializeGraphQLBatchResponse(): String = mapper.writeValueAsString(batchResponse)
66-
67-
@Benchmark
68-
fun KSerializationSerializeGraphQLResponse(): String = Json.encodeToString(response)
69-
70-
@Benchmark
71-
fun KSerializationSerializeGraphQLBatchResponse(): String = Json.encodeToString(batchResponse)
58+
fun FastJsonSerializeGraphQLResponse(): String = JSON.toJSONString(response)
7259
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.expediagroup.graphql.server.extensions
2+
3+
import com.alibaba.fastjson2.JSONReader
4+
5+
inline fun <reified T> JSONReader.readAsArray(): List<T> {
6+
val collector = mutableListOf<T>()
7+
readArray(collector, T::class.java)
8+
return collector
9+
}
10+
11+
inline fun <reified T> JSONReader.readAs(): T = read(T::class.java)

servers/graphql-kotlin-server/src/main/kotlin/com/expediagroup/graphql/server/types/GraphQLServerError.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.expediagroup.graphql.server.types
1818

19+
import com.alibaba.fastjson2.annotation.JSONType
20+
import com.expediagroup.graphql.server.types.serializers.FastJsonIncludeNonNullProperty
1921
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
2022
import com.fasterxml.jackson.annotation.JsonInclude
2123

@@ -26,6 +28,7 @@ import com.fasterxml.jackson.annotation.JsonInclude
2628
*/
2729
@JsonIgnoreProperties(ignoreUnknown = true)
2830
@JsonInclude(JsonInclude.Include.NON_NULL)
31+
@JSONType(serializeFilters = [FastJsonIncludeNonNullProperty::class])
2932
data class GraphQLServerError(
3033
val message: String,
3134
val locations: List<GraphQLSourceLocation>? = null,

0 commit comments

Comments
 (0)