Skip to content

Commit 60879c5

Browse files
authored
feat(client): update jackson client generation to always annotate all fields (#1976)
### 📝 Description Update Jackson client generation logic to always annotate all fields with @get:JsonProperty. This is a workaround to Jackson limitations due to its reliance on reflections to find getters/setters following JavaBean naming conventions. Simple mutation: ``` graphql mutation CreateIssuedInvoice($input: IssuedInvoiceInput!) { CreateIssuedInvoice(IssuedInvoice: $input) { ID Stav CisloDokladu } } ``` Genarated before change: ```kotlin public const val CREATE_ISSUED_INVOICE: String = "mutation CreateIssuedInvoice(${'$'}input: IssuedInvoiceInput!) {\n CreateIssuedInvoice(IssuedInvoice: ${'$'}input) {\n ID\n Stav\n CisloDokladu\n }\n}" @generated public class CreateIssuedInvoice( override val variables: CreateIssuedInvoice.Variables, ) : GraphQLClientRequest<CreateIssuedInvoice.Result> { override val query: String = CREATE_ISSUED_INVOICE override val operationName: String = "CreateIssuedInvoice" override fun responseType(): KClass<CreateIssuedInvoice.Result> = CreateIssuedInvoice.Result::class @generated public data class Variables( @get:JsonProperty(value = "input") public val input: IssuedInvoiceInput, ) /** * Dotazy pro zápis, editaci a mazání S5 objektů */ @generated public data class Result( /** * Faktura vydaná (zápis) */ public val CreateIssuedInvoice: IssuedInvoice? = null, ) } ``` Genareted after change: ```kotlin public const val CREATE_ISSUED_INVOICE: String = "mutation CreateIssuedInvoice(${'$'}input: IssuedInvoiceInput!) {\n CreateIssuedInvoice(IssuedInvoice: ${'$'}input) {\n ID\n Stav\n CisloDokladu\n }\n}" @generated public class CreateIssuedInvoice( override val variables: CreateIssuedInvoice.Variables, ) : GraphQLClientRequest<CreateIssuedInvoice.Result> { override val query: String = CREATE_ISSUED_INVOICE override val operationName: String = "CreateIssuedInvoice" override fun responseType(): KClass<CreateIssuedInvoice.Result> = CreateIssuedInvoice.Result::class @generated public data class Variables( @get:JsonProperty(value = "input") public val input: IssuedInvoiceInput, ) /** * Dotazy pro zápis, editaci a mazání S5 objektů */ @generated public data class Result( /** * Faktura vydaná (zápis) */ @get:JsonProperty("CreateIssuedInvoice") public val CreateIssuedInvoice: IssuedInvoice? = null, ) } ``` data class IssuedInvoice **before** change: ```kotlin @generated public data class IssuedInvoice( /** * ID */ @JsonSerialize(converter = UUIDToAnyConverter::class) @JsonDeserialize(converter = AnyToUUIDConverter::class) public val ID: UUID? = null, /** * Stav */ public val Stav: Int? = null, /** * Číslo dokladu */ public val CisloDokladu: String? = null, ) ``` data class IssuedInvoice **after** change: ```kotlin @generated public data class IssuedInvoice( /** * ID */ @JsonSerialize(converter = UUIDToAnyConverter::class) @JsonDeserialize(converter = AnyToUUIDConverter::class) @get:JsonProperty("ID") public val ID: UUID? = null, /** * Stav */ @get:JsonProperty("Stav") public val Stav: Int? = null, /** * Číslo dokladu */ @get:JsonProperty("CisloDokladu") public val CisloDokladu: String? = null, ) ``` ### 🔗 Related Issues https://kotlinlang.slack.com/archives/CQLNT7B29/p1717655752084109
1 parent bce5bc4 commit 60879c5

File tree

85 files changed

+303
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+303
-0
lines changed

plugins/client/graphql-kotlin-client-generator/src/main/kotlin/com/expediagroup/graphql/plugin/client/generator/types/generatePropertySpecs.kt

+12
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
package com.expediagroup.graphql.plugin.client.generator.types
1818

1919
import com.expediagroup.graphql.plugin.client.generator.GraphQLClientGeneratorContext
20+
import com.expediagroup.graphql.plugin.client.generator.GraphQLSerializer
2021
import com.expediagroup.graphql.plugin.client.generator.ScalarConverterInfo
2122
import com.expediagroup.graphql.plugin.client.generator.exceptions.DeprecatedFieldsSelectedException
2223
import com.expediagroup.graphql.plugin.client.generator.exceptions.InvalidSelectionSetException
2324
import com.expediagroup.graphql.plugin.client.generator.exceptions.MissingArgumentException
25+
import com.fasterxml.jackson.annotation.JsonProperty
2426
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
2527
import com.fasterxml.jackson.databind.annotation.JsonSerialize
2628
import com.squareup.kotlinpoet.AnnotationSpec
@@ -96,6 +98,16 @@ internal fun generatePropertySpecs(
9698
fieldDefinition.description?.content?.let { kdoc ->
9799
propertySpecBuilder.addKdoc("%L", kdoc)
98100
}
101+
if (context.serializer == GraphQLSerializer.JACKSON) {
102+
// always add @get:JsonProperty annotation as a workaround to Jackson limitations
103+
// related to JavaBean naming conventions
104+
propertySpecBuilder.addAnnotation(
105+
AnnotationSpec.builder(JsonProperty::class)
106+
.useSiteTarget(AnnotationSpec.UseSiteTarget.GET)
107+
.addMember("value = \"$fieldName\"")
108+
.build()
109+
)
110+
}
99111
propertySpecBuilder.build()
100112
}
101113

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/alias/AliasQuery.kt

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.expediagroup.graphql.generated
22

33
import com.expediagroup.graphql.client.Generated
44
import com.expediagroup.graphql.client.types.GraphQLClientRequest
5+
import com.fasterxml.jackson.`annotation`.JsonProperty
56
import kotlin.Boolean
67
import kotlin.String
78
import kotlin.reflect.KClass
@@ -22,10 +23,12 @@ public class AliasQuery : GraphQLClientRequest<AliasQuery.Result> {
2223
/**
2324
* Query that accepts some input arguments
2425
*/
26+
@get:JsonProperty(value = "first")
2527
public val first: Boolean,
2628
/**
2729
* Query that accepts some input arguments
2830
*/
31+
@get:JsonProperty(value = "second")
2932
public val second: Boolean,
3033
)
3134
}

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/alias_nested/AliasNestedQuery.kt

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.expediagroup.graphql.client.Generated
44
import com.expediagroup.graphql.client.types.GraphQLClientRequest
55
import com.expediagroup.graphql.generated.aliasnestedquery.ComplexObject
66
import com.expediagroup.graphql.generated.aliasnestedquery.ComplexObject2
7+
import com.fasterxml.jackson.`annotation`.JsonProperty
78
import kotlin.String
89
import kotlin.reflect.KClass
910

@@ -23,10 +24,12 @@ public class AliasNestedQuery : GraphQLClientRequest<AliasNestedQuery.Result> {
2324
/**
2425
* Query returning an object that references another object
2526
*/
27+
@get:JsonProperty(value = "first")
2628
public val first: ComplexObject,
2729
/**
2830
* Query returning an object that references another object
2931
*/
32+
@get:JsonProperty(value = "second")
3033
public val second: ComplexObject2,
3134
)
3235
}

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/alias_nested/aliasnestedquery/ComplexObject.kt

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.expediagroup.graphql.generated.aliasnestedquery
22

33
import com.expediagroup.graphql.client.Generated
4+
import com.fasterxml.jackson.`annotation`.JsonProperty
45
import kotlin.String
56

67
/**
@@ -13,5 +14,6 @@ public data class ComplexObject(
1314
/**
1415
* Some object name
1516
*/
17+
@get:JsonProperty(value = "nameA")
1618
public val nameA: String,
1719
)

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/alias_nested/aliasnestedquery/ComplexObject2.kt

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.expediagroup.graphql.generated.aliasnestedquery
22

33
import com.expediagroup.graphql.client.Generated
4+
import com.fasterxml.jackson.`annotation`.JsonProperty
45
import kotlin.String
56

67
/**
@@ -13,5 +14,6 @@ public data class ComplexObject2(
1314
/**
1415
* Some object name
1516
*/
17+
@get:JsonProperty(value = "nameB")
1618
public val nameB: String,
1719
)

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/documentation/DocumentationQuery.kt

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.expediagroup.graphql.generated
33
import com.expediagroup.graphql.client.Generated
44
import com.expediagroup.graphql.client.types.GraphQLClientRequest
55
import com.expediagroup.graphql.generated.documentationquery.DocObject
6+
import com.fasterxml.jackson.`annotation`.JsonProperty
67
import kotlin.String
78
import kotlin.reflect.KClass
89

@@ -22,6 +23,7 @@ public class DocumentationQuery : GraphQLClientRequest<DocumentationQuery.Result
2223
/**
2324
* Query to test doc strings
2425
*/
26+
@get:JsonProperty(value = "docQuery")
2527
public val docQuery: DocObject,
2628
)
2729
}

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/documentation/documentationquery/DocObject.kt

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.expediagroup.graphql.generated.documentationquery
22

33
import com.expediagroup.graphql.client.Generated
4+
import com.fasterxml.jackson.`annotation`.JsonProperty
45
import kotlin.Int
56

67
/**
@@ -11,5 +12,6 @@ public data class DocObject(
1112
/**
1213
* An id with a comment containing % and $ as well
1314
*/
15+
@get:JsonProperty(value = "id")
1416
public val id: Int,
1517
)

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/include_skip_directives/IncludeSkipDirectivesQuery.kt

+2
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ public class IncludeSkipDirectivesQuery(
3636
/**
3737
* Query that returns enum value
3838
*/
39+
@get:JsonProperty(value = "enumQuery")
3940
public val enumQuery: CustomEnum? = null,
4041
/**
4142
* Query that returns wrapper object with all supported scalar types
4243
*/
44+
@get:JsonProperty(value = "scalarQuery")
4345
public val scalarQuery: ScalarWrapper? = null,
4446
)
4547
}

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/include_skip_directives/includeskipdirectivesquery/ScalarWrapper.kt

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.expediagroup.graphql.generated.includeskipdirectivesquery
22

33
import com.expediagroup.graphql.client.Generated
4+
import com.fasterxml.jackson.`annotation`.JsonProperty
45
import kotlin.Int
56

67
/**
@@ -11,5 +12,6 @@ public data class ScalarWrapper(
1112
/**
1213
* A signed 32-bit nullable integer value
1314
*/
15+
@get:JsonProperty(value = "count")
1416
public val count: Int? = null,
1517
)

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/input_hard_coded/HardCodedInputQuery.kt

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.expediagroup.graphql.generated
22

33
import com.expediagroup.graphql.client.Generated
44
import com.expediagroup.graphql.client.types.GraphQLClientRequest
5+
import com.fasterxml.jackson.`annotation`.JsonProperty
56
import kotlin.Boolean
67
import kotlin.String
78
import kotlin.reflect.KClass
@@ -23,6 +24,7 @@ public class HardCodedInputQuery : GraphQLClientRequest<HardCodedInputQuery.Resu
2324
/**
2425
* Query that accepts some input arguments
2526
*/
27+
@get:JsonProperty(value = "inputObjectQuery")
2628
public val inputObjectQuery: Boolean,
2729
)
2830
}

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/input_lists/InputListQuery.kt

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class InputListQuery(
3535
/**
3636
* Query accepting list input
3737
*/
38+
@get:JsonProperty(value = "listInputQuery")
3839
public val listInputQuery: String? = null,
3940
)
4041
}

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/input_self_reference/SelfReferencingInputQuery.kt

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class SelfReferencingInputQuery(
3333
/**
3434
* Query that accepts self referencing input object
3535
*/
36+
@get:JsonProperty(value = "complexInputObjectQuery")
3637
public val complexInputObjectQuery: Boolean,
3738
)
3839
}

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/interface_diff_selection_sets/DifferentSelectionSetQuery.kt

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.expediagroup.graphql.client.Generated
44
import com.expediagroup.graphql.client.types.GraphQLClientRequest
55
import com.expediagroup.graphql.generated.differentselectionsetquery.BasicInterface
66
import com.expediagroup.graphql.generated.differentselectionsetquery.BasicInterface2
7+
import com.fasterxml.jackson.`annotation`.JsonProperty
78
import kotlin.String
89
import kotlin.reflect.KClass
910

@@ -24,10 +25,12 @@ public class DifferentSelectionSetQuery : GraphQLClientRequest<DifferentSelectio
2425
/**
2526
* Query returning an interface
2627
*/
28+
@get:JsonProperty(value = "first")
2729
public val first: BasicInterface,
2830
/**
2931
* Query returning an interface
3032
*/
33+
@get:JsonProperty(value = "second")
3134
public val second: BasicInterface2,
3235
)
3336
}

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/interface_diff_selection_sets/differentselectionsetquery/BasicInterface.kt

+11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.expediagroup.graphql.generated.differentselectionsetquery
22

33
import com.expediagroup.graphql.client.Generated
4+
import com.fasterxml.jackson.`annotation`.JsonProperty
45
import com.fasterxml.jackson.`annotation`.JsonSubTypes
56
import com.fasterxml.jackson.`annotation`.JsonTypeInfo
67
import com.fasterxml.jackson.`annotation`.JsonTypeInfo.As.PROPERTY
@@ -27,11 +28,13 @@ public interface BasicInterface {
2728
/**
2829
* Unique identifier of an interface
2930
*/
31+
@get:JsonProperty(value = "id")
3032
public val id: Int
3133

3234
/**
3335
* Name field
3436
*/
37+
@get:JsonProperty(value = "name")
3538
public val name: String
3639
}
3740

@@ -43,14 +46,17 @@ public data class FirstInterfaceImplementation(
4346
/**
4447
* Unique identifier of the first implementation
4548
*/
49+
@get:JsonProperty(value = "id")
4650
override val id: Int,
4751
/**
4852
* Name of the first implementation
4953
*/
54+
@get:JsonProperty(value = "name")
5055
override val name: String,
5156
/**
5257
* Custom field integer value
5358
*/
59+
@get:JsonProperty(value = "intValue")
5460
public val intValue: Int,
5561
) : BasicInterface
5662

@@ -62,14 +68,17 @@ public data class SecondInterfaceImplementation(
6268
/**
6369
* Unique identifier of the second implementation
6470
*/
71+
@get:JsonProperty(value = "id")
6572
override val id: Int,
6673
/**
6774
* Name of the second implementation
6875
*/
76+
@get:JsonProperty(value = "name")
6977
override val name: String,
7078
/**
7179
* Custom field float value
7280
*/
81+
@get:JsonProperty(value = "floatValue")
7382
public val floatValue: Double,
7483
) : BasicInterface
7584

@@ -82,9 +91,11 @@ public data class DefaultBasicInterfaceImplementation(
8291
/**
8392
* Unique identifier of an interface
8493
*/
94+
@get:JsonProperty(value = "id")
8595
override val id: Int,
8696
/**
8797
* Name field
8898
*/
99+
@get:JsonProperty(value = "name")
89100
override val name: String,
90101
) : BasicInterface

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/interface_diff_selection_sets/differentselectionsetquery/BasicInterface2.kt

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.expediagroup.graphql.generated.differentselectionsetquery
22

33
import com.expediagroup.graphql.client.Generated
4+
import com.fasterxml.jackson.`annotation`.JsonProperty
45
import com.fasterxml.jackson.`annotation`.JsonSubTypes
56
import com.fasterxml.jackson.`annotation`.JsonTypeInfo
67
import com.fasterxml.jackson.`annotation`.JsonTypeInfo.As.PROPERTY
@@ -27,6 +28,7 @@ public interface BasicInterface2 {
2728
/**
2829
* Name field
2930
*/
31+
@get:JsonProperty(value = "name")
3032
public val name: String
3133
}
3234

@@ -38,10 +40,12 @@ public data class FirstInterfaceImplementation2(
3840
/**
3941
* Name of the first implementation
4042
*/
43+
@get:JsonProperty(value = "name")
4144
override val name: String,
4245
/**
4346
* Custom field integer value
4447
*/
48+
@get:JsonProperty(value = "intValue")
4549
public val intValue: Int,
4650
) : BasicInterface2
4751

@@ -53,10 +57,12 @@ public data class SecondInterfaceImplementation2(
5357
/**
5458
* Name of the second implementation
5559
*/
60+
@get:JsonProperty(value = "name")
5661
override val name: String,
5762
/**
5863
* Custom field float value
5964
*/
65+
@get:JsonProperty(value = "floatValue")
6066
public val floatValue: Double,
6167
) : BasicInterface2
6268

@@ -69,5 +75,6 @@ public data class DefaultBasicInterface2Implementation(
6975
/**
7076
* Name field
7177
*/
78+
@get:JsonProperty(value = "name")
7279
override val name: String,
7380
) : BasicInterface2

plugins/client/graphql-kotlin-client-generator/src/test/data/generator/interface_impl_diff_selection_sets/DifferentSelectionSetQuery.kt

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.expediagroup.graphql.client.Generated
44
import com.expediagroup.graphql.client.types.GraphQLClientRequest
55
import com.expediagroup.graphql.generated.differentselectionsetquery.BasicInterface
66
import com.expediagroup.graphql.generated.differentselectionsetquery.BasicInterface2
7+
import com.fasterxml.jackson.`annotation`.JsonProperty
78
import kotlin.String
89
import kotlin.reflect.KClass
910

@@ -24,10 +25,12 @@ public class DifferentSelectionSetQuery : GraphQLClientRequest<DifferentSelectio
2425
/**
2526
* Query returning an interface
2627
*/
28+
@get:JsonProperty(value = "first")
2729
public val first: BasicInterface,
2830
/**
2931
* Query returning an interface
3032
*/
33+
@get:JsonProperty(value = "second")
3134
public val second: BasicInterface2,
3235
)
3336
}

0 commit comments

Comments
 (0)