Skip to content

Cannot use GraphQL argument object whose generic type is declared on @SchemaMapping method #349

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
crispydc opened this issue Apr 8, 2022 · 3 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@crispydc
Copy link

crispydc commented Apr 8, 2022

We have a project built using spring-graphql version 1.0.0-M2 that includes filtering logic using input objects with fields of Enum generics. This approach works fine in M2, but when attempting to upgrade to M4 these Enum input fields were now always blank regardless of what was sent in the query. In the latest M6 version, queries including these fields now result in an INTERNAL_ERROR similar to this:

org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'filter' on field 'enums[0]': rejected value [ONE]; codes [typeMismatch.target.enums[0],typeMismatch.target.enums,typeMismatch.enums[0],typeMismatch.enums,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [target.enums[0],enums[0]]; arguments []; default message [enums[0]]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.lang.Enum' for property 'enums[0]'; nested exception is java.lang.IllegalArgumentException: The target type java.lang.Enum does not refer to an enum]

I was able to recreate the issue we're seeing on a clean spring-boot 2.7.0-M3 project with spring-boot-starter-graphql and the following:

enum.graphqls

type Query {}

extend type Query {
    enums(filter: EnumFilterInput!): [FancyEnum]
}

input EnumFilterInput {
    enums: [FancyEnum]
}

enum FancyEnum {
    ONE
    TWO
    THREE
}

EnumController.java

@Controller
public class EnumController {

    @QueryMapping
    public List<FancyEnum> enums(@Argument EnumFilterInput<FancyEnum> filter) {
        return filter.getEnums();
    }
}

EnumFilterInput.java

public class EnumFilterInput<E extends Enum<E>> {

    private List<E> enums;

    public List<E> getEnums() {
        return enums;
    }

    public void setEnums(List<E> enums) {
        this.enums = enums;
    }
}

FancyEnum.java

public enum FancyEnum {
    ONE, TWO, THREE
}

The above project on spring-boot 2.6.6 with spring-graphql 1.0.0-M2 works as expected with the following query:

query {
  enums(filter:{
    enums:[ONE]
  })
}

However on spring-boot 2.7.0-M3 and spring-boot-starter-graphql (1.0.0-M6) this query fails with the error given above.

Was this an intended change made to the project or is this an issue that can be resolved in a future release? If it is intended, is there a way to get something similar working that is properly supported by spring-graphql?

Thanks in advance for any help you can provide.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Apr 8, 2022
@koenpunt
Copy link
Contributor

Between M2 and M3 argument serialization changed from JSON encode/decode to using a DataBinder, which caused some things to work differently, or not work at all anymore. I experienced something similar with a custom OptionalInput generic type.

We were able to work around it by defining a static of(value) method for every generic type argument.

sealed class OptionalInput<out T> {

    // ...

    companion object {
        @JvmStatic
        fun of(value: String?): OptionalInput<String> {
            return Defined(value)
        }
    }
}

Or I think the equivalent java code:

class OptionalInput<T> {
    // ...

    static OptionalInput<String> of(String value) {
        return new OptionalInput.Defined(value);
    }
}

Definitely not perfect, and also doesn't work recursively, but solved the majority of the issues we had with it.

@koenpunt
Copy link
Contributor

See also the comments on this PR: #140

@rstoyanchev
Copy link
Contributor

Indeed as @koenpunt pointed out, we switched from JSON (de)-serialization to using DataBinder for the reasons explained in #122.

Given that DataBinder is only has the actual object to populate, in this case created through the default constructor, it does not the actual enum type to convert to. I confirmed that it works with a class that declares the generic parameter type:

public class FancyEnumFilterInput extends EnumFilterInput<FancyEnum> {
}

@Controller
public class EnumController {

	@QueryMapping
	public List<FancyEnum> enums(@Argument FancyEnumFilterInput filter) {
		return filter.getEnums();
	}

}

The problem relates more generally to any class-level, generic parameter. We might be able to register a TypeDescriptor and ConvertingPropertyEditorAdapter on the DataBinder for fields whose type is class-level, generic parameter, where the type information would come from the method parameter declaration.

@rstoyanchev rstoyanchev added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged labels Apr 13, 2022
@rstoyanchev rstoyanchev added this to the 1.0 Backlog milestone Apr 13, 2022
@rstoyanchev rstoyanchev changed the title Input Objects with Generic Enums Fail @Argument Input Objects with Generic Type Fail with a Type Mismatch Error Apr 13, 2022
@rstoyanchev rstoyanchev self-assigned this Oct 21, 2022
@rstoyanchev rstoyanchev modified the milestones: 1.1 Backlog, 1.1.0 Oct 21, 2022
@rstoyanchev rstoyanchev changed the title @Argument Input Objects with Generic Type Fail with a Type Mismatch Error @Argument object with enum generic type fails with type mismatch error Oct 21, 2022
rstoyanchev added a commit that referenced this issue Oct 24, 2022
@rstoyanchev rstoyanchev changed the title @Argument object with enum generic type fails with type mismatch error Cannot use GraphQL argument object whose generic type is declared on @SchemaMapping method Nov 9, 2022
koenpunt pushed a commit to koenpunt/spring-graphql that referenced this issue Feb 2, 2023
koenpunt pushed a commit to koenpunt/spring-graphql that referenced this issue Feb 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants