Skip to content

Known Issues

Oryan edited this page Jun 18, 2021 · 3 revisions

NoClassDefFoundError when using Spring Boot

If you're using graphl-java-tools with Spring Boot version lower than 2.2 you need to set the kotlin.version in your Spring Boot project explicitly to version 1.3.70, because Spring Boot Starter parent currently overrides it with a 1.2.* version of Kotlin. graphql-java-tools requires 1.3.* however because of its coroutine support. If you don't override this version you will run into a NoClassDefFoundError.

Spring Boot team has indicated the Kotlin version will be upgraded to 1.3 in Spring Boot 2.2.

Upload scalars within input objects cannot be parsed

Original issue.

Scalars work fine by themselves (or in an array) but not if they are defined as a field on an input object. This is because input objects can be arbitrarily complex and so they are parsed using a Jackson object mapper. If for some reason the default mapper doesn't know how to parse that scalar it will fail. For most scalars, this can be worked around by providing an StdDeserializer with the mapper via the objectMapperProvider option. However, for the Upload scalar, which is often mapped to a Spring Part or MultipartFile this is becomes tricky because there is no standard way to instantiate these objects manually. And so, mocks are the best option available in this case. A full working example is provided here.


A second way to overcome this is by replacing Part or MultipartFile with String in our resolvers while holding a reference to the actual files in a custom context object.
In the controller method, before calling the GraphQL executor, we need to update the query with file references.
For example, if the HTTP request would look something like this:

operations: {"operationName":"uploadFile","variables":{"input": [{"file": null},{"file": null}]},"query":"mutation uploadFile($input: [FileInput]) { uploadFile(input: $input) { id }"}

map: { "file0": ["variables.input.0.file"] , "file1":["variables.input.1.file"]}

We will update the input to look like this:

..."input": [{"file": "file0"}, {"file": "file1"}]...

This requires parsing the query's JSON to get to the specific nodes that represent files and modify them.
Finally we need to create a mapping from these references (file0, file1...) to the actual file parts in the context object (Map<String, Part/MultipartFile> files)
And we should be able to retrieve the file parts from the context:

    public void uploadFile(
        List<FileInput> input,
        GraphQLContext context
    ) {
        context.getFile(input.get(0).getFile());
        ...
    }

    class FileInput {
        String file;
        String path;
    }