How to treat a child class like its parent in GraphQL SPQR

291 views Asked by At

I created a wrapper around BigDecimal. Basically just putting a bunch of friendlier methods on top of it. I use it for some of my POJO's fields, and it generates a schema like this

# Built-in java.math.BigDecimal
scalar BigDecimal

input BestDecimalInput {
  scale: Int!
}

Ideally, when I go to make a query I'd be able to treat it the same as BigDecimal. I have a constructor

public BestDecimal(double val) {
        super(val);
    }

which I'd hope it would allow me to use a regular floating point number in my query/mutation, but it doesn't seem to work that way. Basically if the below is a BestDecimal object, I want this to work just as if it were a BigDecimal.

myquery(number: 10){
  whatever
}
1

There are 1 answers

0
kaqqao On BEST ANSWER

There's 2 things you can do.

  • Map you class as a custom scalar. To do this, you have to implement as custom TypeMapper and wire it in.

  • Alternatively, you can provide a custom TypeAdapter that adapts BestDecimal to BigDecimal and vice versa.

Check out the existing implementations of TypeMapper or TypeAdapter, e.g. OptionalIntAdapter (that makes OptionalInt act as an Integer), and make a new one based on that. Or see this answer for a custom scalar.

You can hook it up using generator.withTypeMappersor generator.withTypeAdapters.

Using the Spring Starter, you can add a TypeMapper like this:

@Bean
public ExtensionProvider<GeneratorConfiguration, TypeMapper> mappers() {
    //After IdAdapter is generally a safe place to insert custom mappers
    return (config, mappers) -> mappers.insertAfter(IdAdapter.class, new YouCustomMapper());
}

You can't wire a TypeAdapter directly, unfortunately. You'd have to wire it as a TypeMapper, InputConverter and OutputConverter at the same time, which is annoying. So instead, it's easier to add a custom module that adds a TypeAdapter:

@Bean
public ExtensionProvider<GeneratorConfiguration, Module> modules() {
    return (config, modules) -> modules.append(context -> 
         context.getSchemaGenerator().withTypeAdapters(new YourCustomAdapter()));
}

You can (and should) of course make a proper Module class instead of an anonymous one like I did.