Search code examples
javaspring-bootgraphql-java

Schema input type always "LinkedHashMap cannot be cast..."


My schema.grapqls looks like...

scalar BigDecimal
...
input TemplateLineItemInput {
    partMasterId: String!
    partMasterIdPath: String!
    actionType: String!
    actionQuantity: BigDecimal!
}
...
type Mutation {
    ...
    createLineItem(id: ID! input: TemplateLineItemInput!): TemplateBom
}

My POJOs are all Lombok-ie and were working great until I tried to create that input.

import lombok.Builder;
import lombok.Data;

import java.math.BigDecimal;

@Data
@Builder
public class TemplateLineItemInput {
  private final String partMasterId;
  private final String partMasterIdPath;
  private final String actionType;
  private final BigDecimal actionQuantity;
}

I believe I have the mutation it wired up correctly...

@Component
public class TemplateBomDataWiring  implements RuntimeWiringBuilderCustomizer {
  private static final Logger LOG = LoggerFactory.getLogger(TemplateBomDataWiring.class);

  private final TemplateBomService templateBomService;

  public TemplateBomDataWiring(TemplateBomService templateBomService) {
    this.templateBomService = templateBomService;
  }

  @Override
  public void customize(RuntimeWiring.Builder builder) {
    builder.scalar(Scalars.GraphQLBigDecimal);
    builder.scalar(GraphQLDate);
    builder.type("Query", typeWiring -> typeWiring.dataFetcher("templateBom", env -> {
      final String id = env.getArgument("id");
      return templateBomService.getTemplateBom(id);
    }));
    builder.type("Mutation", typeWiring -> typeWiring.dataFetcher("create", env -> {
      final String partMasterId = env.getArgument("partMasterId");
      return templateBomService.createTemplateBom(partMasterId);
    }));
    builder.type("Mutation", typeWiring -> typeWiring.dataFetcher("createLineItem", env -> {
      final String id = env.getArgument("id");
      final TemplateLineItemInput input = env.getArgument("input");
      return templateBomService.createTemplateLineItem(id, input);
    }));
  }

But I can't get the query to parse in GraphiQL. I get no stacktrace server side, I just get this in the GraphiQL UI...

{
  "errors": [
    {
      "message": "class java.util.LinkedHashMap cannot be cast to class com.example.boa.domain.TemplateLineItemInput (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.example.boa.domain.TemplateLineItemInput is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @617a9621)",
      "locations": [
        {
          "line": 42,
          "column": 3
        }
      ],
      "path": [
        "createLineItem"
      ],
      "extensions": {
        "classification": "INTERNAL_ERROR"
      }
    }
  ],
  "data": {
    "createLineItem": null
  }
}

I'm working pretty much off the https://www.graphql-java.com/documentation/v16/ docs

How do I get my input type to map into the TemplateLineItemInput POJO on graphql-java:16.2?


Solution

  • You can use spring boot to automatically define your runtime wiring. And you can write query fetchers or mutation fetchers by implementing

    GraphQLQueryResolver
    GraphQLMutationResolver
    

    If you are doing the runtime wiring, the complex input parameters other than basic types will always be passed as key, value pairs in a LinkedHashmap. So you have to convert the passed linkedHashmap into the class you expect as below.

    ObjectMapper objectMapper = new ObjectMapper();
                String input = objectMapper.writeValueAsString(env.getArgument("input"));
                final String arg = env.getArgument("input");
                return templateBomService.createTemplateLineItem(id, objectMapper.readValue(arg,TemplateLineItemInput.class));