Skip to content

Typed Client: all classes for the possibleTypes have to be present #2224

@jmini

Description

@jmini

On the GitLab GraphQL server (no password required), the WorkItemWidget type (kind INTERFACE) has multiple possible types.

You can run a query like this:

query {
  workItemsByReference(contextNamespacePath: "gitlab-org",
    refs: [
      "&9290"
    ]) {
    nodes {
      id
      iid
      title
      webUrl
      workItemType {
        name
      }
      widgets {
        ... on WorkItemWidgetLabels {
          labels {
            nodes {
              id
              title
            }
          }
        }
        ... on WorkItemWidgetLinkedItems {
          blocked
          blockedByCount
          blockingCount
          linkedItems {
            nodes {
              linkId
              linkType
              linkCreatedAt
              linkUpdatedAt
              workItem {
                id
              }
            }
          }
        }
      }
    }
  }
}

https://gitlab.com/-/graphql-explorer

With the java typed client, you need to have all the sub-types declared (as empty class), even if you are only interested in two widgets.

import org.eclipse.microprofile.graphql.Name;

import io.smallrye.graphql.api.Union;
import jakarta.json.bind.annotation.JsonbSubtype;
import jakarta.json.bind.annotation.JsonbTypeInfo;

@Union
@JsonbTypeInfo(key = "__typename", value = {
        @JsonbSubtype(alias = "WorkItemWidgetAssignees", type = WorkItemWidgetAssignees.class),
        @JsonbSubtype(alias = "WorkItemWidgetAwardEmoji", type = WorkItemWidgetAwardEmoji.class),
        @JsonbSubtype(alias = "WorkItemWidgetColor", type = WorkItemWidgetColor.class),
        @JsonbSubtype(alias = "WorkItemWidgetCrmContacts", type = WorkItemWidgetCrmContacts.class),
        @JsonbSubtype(alias = "WorkItemWidgetCurrentUserTodos", type = WorkItemWidgetCurrentUserTodos.class),
        @JsonbSubtype(alias = "WorkItemWidgetDescription", type = WorkItemWidgetDescription.class),
        @JsonbSubtype(alias = "WorkItemWidgetDesigns", type = WorkItemWidgetDesigns.class),
        @JsonbSubtype(alias = "WorkItemWidgetDevelopment", type = WorkItemWidgetDevelopment.class),
        @JsonbSubtype(alias = "WorkItemWidgetHealthStatus", type = WorkItemWidgetHealthStatus.class),
        @JsonbSubtype(alias = "WorkItemWidgetHierarchy", type = WorkItemWidgetHierarchy.class),
        @JsonbSubtype(alias = "WorkItemWidgetIteration", type = WorkItemWidgetIteration.class),
        @JsonbSubtype(alias = "WorkItemWidgetLabels", type = WorkItemWidgetLabels.class),
        @JsonbSubtype(alias = "WorkItemWidgetLinkedItems", type = WorkItemWidgetLinkedItems.class),
        @JsonbSubtype(alias = "WorkItemWidgetMilestone", type = WorkItemWidgetMilestone.class),
        @JsonbSubtype(alias = "WorkItemWidgetNotes", type = WorkItemWidgetNotes.class),
        @JsonbSubtype(alias = "WorkItemWidgetNotifications", type = WorkItemWidgetNotifications.class),
        @JsonbSubtype(alias = "WorkItemWidgetParticipants", type = WorkItemWidgetParticipants.class),
        @JsonbSubtype(alias = "WorkItemWidgetRolledupDates", type = WorkItemWidgetRolledupDates.class),
        @JsonbSubtype(alias = "WorkItemWidgetStartAndDueDate", type = WorkItemWidgetStartAndDueDate.class),
        @JsonbSubtype(alias = "WorkItemWidgetStatus", type = WorkItemWidgetStatus.class),
        @JsonbSubtype(alias = "WorkItemWidgetTimeTracking", type = WorkItemWidgetTimeTracking.class),
        @JsonbSubtype(alias = "WorkItemWidgetWeight", type = WorkItemWidgetWeight.class)
})
@Name("WorkItemWidget")
public interface WorkItemWidget {
}

If one is missing (as in this example) you get this stacktrace:

java.lang.RuntimeException: SRGQLDC035010: Cannot instantiate WorkItemWidgetEmailParticipants
	at io.smallrye.graphql.client.impl.typesafe.reflection.TypeInfo.lambda$subtype$9(TypeInfo.java:474)
	at java.base/java.util.Optional.orElseThrow(Optional.java:403)
	at io.smallrye.graphql.client.impl.typesafe.reflection.TypeInfo.subtype(TypeInfo.java:474)
	at io.smallrye.graphql.client.impl.typesafe.json.JsonObjectReader.readObject(JsonObjectReader.java:32)
	at io.smallrye.graphql.client.impl.typesafe.json.JsonObjectReader.read(JsonObjectReader.java:27)
	at io.smallrye.graphql.client.impl.typesafe.json.JsonReader.read(JsonReader.java:62)
	at io.smallrye.graphql.client.impl.typesafe.json.JsonReader.readJson(JsonReader.java:37)
	at io.smallrye.graphql.client.impl.typesafe.json.JsonArrayReader.readItem(JsonArrayReader.java:41)
	at io.smallrye.graphql.client.impl.typesafe.json.JsonArrayReader.lambda$read$0(JsonArrayReader.java:33)

Setting allowUnexpectedResponseFields does not help here.

        WorkitemClientApi gqlApi = TypesafeGraphQLClientBuilder.newBuilder()
                .endpoint("https://gitlab.com/api/graphql")
                .header("Authorization", "Bearer " + gitlabToken) //no needed for the discussed read query
                .allowUnexpectedResponseFields(true)
                .build(WorkitemClientApi.class);

Complete project: https://github.com/jmini/gitlab-experiments/tree/main/smallrye-graphql-client

I am not sure if something can be done about this, but I wanted to share this with you (and it might help other users).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions