Parsing of PageInfo fails (using generated types)
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 217
- Forks
- 116
- PR merge metrics
- No merged PRs in 30d
Description
Using the schema found here (also attached as txt)
schema.txt
I've generated a query API.
I make the following query (generated by the query API):
query {
site {
settings {
url {
vanityUrl
}
}
products(first: 10) {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
entityId
name
plainTextDescription(characterLimit: 1024)
brand {
name
}
availabilityV2 {
status
}
inventory {
hasVariantInventory
aggregated {
availableToSell
}
}
path
categories(first: 10) {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
name
}
}
}
images(first: 50) {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
urlOriginal
altText
}
}
}
prices {
price {
value
currencyCode
}
basePrice {
value
currencyCode
}
salePrice {
value
currencyCode
}
}
productOptions(first: 3) {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
displayName
... on MultipleChoiceOption {
__typename
values {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
label
}
}
}
}
}
}
}
variants(first: 200) {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
inventory {
aggregated {
availableToSell
}
}
entityId
productOptions(first: 3) {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
entityId
displayName
... on MultipleChoiceOption {
__typename
values {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
label
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
I get this response back:
{
"data" : {
"site" : {
"settings" : {
"url" : {
"vanityUrl" : "https://shop.soapboxus.com"
}
},
"products" : {
"pageInfo" : {
"hasNextPage" : false,
"endCursor" : "YXJyYXljb25uZWN0aW9uOjA="
},
"edges" : [ {
"node" : {
"entityId" : 175,
"name" : "Tide ReLoad Compatible Detergent",
"plainTextDescription" : "\n\nThis Box Contains\nOne Tide ReLoad™ tray and Detergent\nTide ReLoad™ tray works with multiple types of detergent, shipped directly from us with free shipping. Just choose the type of Tide you like best – Tide PODS Original, Tide PODS Spring Meadow, or Tide Eco-Box Original. Please note that Tide ReLoad™ tray will not work with Tide products purchased elsewhere.\n",
"brand" : null,
"availabilityV2" : {
"status" : "Available"
},
"inventory" : {
"hasVariantInventory" : false,
"aggregated" : null
},
"path" : "/tide-smart-tray-detergent/",
"categories" : {
"pageInfo" : {
"hasNextPage" : false,
"endCursor" : null
},
"edges" : [ ]
},
"images" : {
"pageInfo" : {
"hasNextPage" : false,
"endCursor" : "YXJyYXljb25uZWN0aW9uOjY="
},
"edges" : [ {
"node" : {
"urlOriginal" : "https://cdn11.bigcommerce.com/s-v1a6036467/images/stencil/original/products/175/800/Image_1_-_Delivered__03950.1633532989.jpg",
"altText" : ""
}
}, {
"node" : {
"urlOriginal" : "https://cdn11.bigcommerce.com/s-v1a6036467/images/stencil/original/products/175/802/Image_2_-_Free_Shipping__53500.1633532989.jpg",
"altText" : ""
}
}, {
"node" : {
"urlOriginal" : "https://cdn11.bigcommerce.com/s-v1a6036467/images/stencil/original/products/175/815/Image_3_-_Never_run_out_copy__63238.1633532989.jpg",
"altText" : ""
}
}, {
"node" : {
"urlOriginal" : "https://cdn11.bigcommerce.com/s-v1a6036467/images/stencil/original/products/175/799/Image_4_-_Cancel_Anytime__26398.1633532989.jpg",
"altText" : ""
}
}, {
"node" : {
"urlOriginal" : "https://cdn11.bigcommerce.com/s-v1a6036467/images/stencil/original/products/175/798/Image_5_-_Set_up__06965.1633532989.jpg",
"altText" : ""
}
}, {
"node" : {
"urlOriginal" : "https://cdn11.bigcommerce.com/s-v1a6036467/images/stencil/original/products/175/803/Image_6_-_Skip_the_trip_to_the_store__76617.1633532989.jpg",
"altText" : ""
}
}, {
"node" : {
"urlOriginal" : "https://cdn11.bigcommerce.com/s-v1a6036467/images/stencil/original/products/175/801/Image_7_-_Comes_with__54036.1633532989.jpg",
"altText" : ""
}
} ]
},
"prices" : {
"price" : {
"value" : 19.99,
"currencyCode" : "USD"
},
"basePrice" : {
"value" : 19.99,
"currencyCode" : "USD"
},
"salePrice" : null
},
"productOptions" : {
"pageInfo" : {
"hasNextPage" : false,
"endCursor" : "YXJyYXljb25uZWN0aW9uOjA="
},
"edges" : [ {
"node" : {
"displayName" : "Your detergent selection",
"__typename" : "MultipleChoiceOption",
"values" : {
"pageInfo" : {
"hasNextPage" : false,
"endCursor" : "YXJyYXljb25uZWN0aW9uOjI="
},
"edges" : [ {
"node" : {
"label" : "Original"
}
}, {
"node" : {
"label" : "Spring Meadow"
}
}, {
"node" : {
"label" : "Tide Eco Box"
}
} ]
}
}
} ]
},
"variants" : {
"pageInfo" : {
"hasNextPage" : false,
"endCursor" : "YXJyYXljb25uZWN0aW9uOjI="
},
"edges" : [ {
"node" : {
"inventory" : {
"aggregated" : null
},
"entityId" : 170,
"productOptions" : {
"pageInfo" : {
"hasNextPage" : false,
"endCursor" : "YXJyYXljb25uZWN0aW9uOjA="
},
"edges" : [ {
"node" : {
"entityId" : 21,
"displayName" : "Your detergent selection",
"__typename" : "MultipleChoiceOption",
"values" : {
"pageInfo" : {
"hasNextPage" : false,
"endCursor" : "YXJyYXljb25uZWN0aW9uOjA="
},
"edges" : [ {
"node" : {
"label" : "Original"
}
} ]
}
}
} ]
}
}
}, {
"node" : {
"inventory" : {
"aggregated" : null
},
"entityId" : 171,
"productOptions" : {
"pageInfo" : {
"hasNextPage" : false,
"endCursor" : "YXJyYXljb25uZWN0aW9uOjA="
},
"edges" : [ {
"node" : {
"entityId" : 21,
"displayName" : "Your detergent selection",
"__typename" : "MultipleChoiceOption",
"values" : {
"pageInfo" : {
"hasNextPage" : false,
"endCursor" : "YXJyYXljb25uZWN0aW9uOjA="
},
"edges" : [ {
"node" : {
"label" : "Spring Meadow"
}
} ]
}
}
} ]
}
}
}, {
"node" : {
"inventory" : {
"aggregated" : null
},
"entityId" : 172,
"productOptions" : {
"pageInfo" : {
"hasNextPage" : false,
"endCursor" : "YXJyYXljb25uZWN0aW9uOjA="
},
"edges" : [ {
"node" : {
"entityId" : 21,
"displayName" : "Your detergent selection",
"__typename" : "MultipleChoiceOption",
"values" : {
"pageInfo" : {
"hasNextPage" : false,
"endCursor" : "YXJyYXljb25uZWN0aW9uOjA="
},
"edges" : [ {
"node" : {
"label" : "Tide Eco Box"
}
} ]
}
}
} ]
}
}
} ]
}
}
} ]
}
}
}
}
Then when I attempt to parse the site object into a type generated by the codegen plugin...
Optional<JsonNode> dataOptional =
Optional.of(objectMapper.readTree(graphQLResponse.getJson()));
System.out.println(dataOptional.get().toPrettyString());
Optional<JsonNode> siteOptional =
dataOptional.map(json -> json.get("data")).map(data -> data.get("site"));
if (siteOptional.isEmpty()) {
throw new NullPointerException();
}
com.attentivemobile.syncprocessor.model.bigcommerce.types.Site site =
objectMapper.treeToValue(siteOptional.get(), Site.class);
I get this
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `graphql.relay.PageInfo` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: com.attentivemobile.syncprocessor.model.bigcommerce.types.Site["products"]->com.attentivemobile.syncprocessor.model.bigcommerce.types.ProductConnection["pageInfo"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1904)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1349)
at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:274)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:313)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:176)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:313)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:176)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)
at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:4650)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2831)
at com.fasterxml.jackson.databind.ObjectMapper.treeToValue(ObjectMapper.java:3295)
at com.attentivemobile.syncprocessor.service.vendor.bigcommerce.Test.test(Test.java:78)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at ...
This is my codegen configuration, via the community maven port
<plugin>
<groupId>io.github.deweyjose</groupId>
<artifactId>graphqlcodegen-maven-plugin</artifactId>
<version>1.16</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaPaths>
<param>
src/main/resources/api/bigcommerce/schema.graphql
</param>
</schemaPaths>
<packageName>com.attentivemobile.syncprocessor.model.bigcommerce</packageName>
<!-- Required because scalars chosen by BigCommerce impose graphql-java scalar mappings-->
<typeMapping>
<BigDecimal>java.math.BigDecimal</BigDecimal>
<Long>java.lang.Long</Long>
</typeMapping>
<generateClient>true</generateClient>
<includeQueries>site</includeQueries>
<includeSubscriptions>[]</includeSubscriptions>
<includeMutations>[]</includeMutations>
<omitNullInputFields>true</omitNullInputFields>
<maxProjectionDepth>20</maxProjectionDepth>
<outputDir>${project.build.directory}/generated-sources/graphqlcodegen</outputDir>
<kotlinAllFieldsOptional>true</kotlinAllFieldsOptional>
<language>java</language>
</configuration>
</execution>
</executions>
</plugin>
and these are the versions of the dgs libraries I'm using
<!-- https://mvnrepository.com/artifact/com.netflix.graphql.dgs.codegen/graphql-dgs-codegen-client-core -->
<dependency>
<groupId>com.netflix.graphql.dgs.codegen</groupId>
<artifactId>graphql-dgs-codegen-client-core</artifactId>
<version>5.1.16</version>
</dependency>
<dependency>
<groupId>com.netflix.graphql.dgs</groupId>
<artifactId>graphql-dgs-client</artifactId>
<version>4.9.20</version>
</dependency>
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the attached schema.txt and the generated query API, then reproduce the PageInfo parsing failure using the schema and response shown in the issue. Compare the generated PageInfo types with the returned pageInfo objects; done means the generated types parse the query response without failure.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- graphql, kotlin
- Domain
- api, tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100