Skip to content
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

Java classes with Optional constructor args for GraphQL input types fail with InaccessibleObjectException #470

Closed
nilshartmann opened this issue Aug 21, 2022 · 2 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@nilshartmann
Copy link
Contributor

Hi,

I noticed an error (bug?) when using java.lang.Optional on classes for Input-Types in Java.

As a simple example, please see the following schema, that contains nullable input types and fields:

input ContactInput {
    phone: String
}

input AccountInput {
    id: String!

    # nullable, In Java: Optional<String>
    fullname: String

    # nullable, In Java: Optional<ContactInput>
    contact: ContactInput
}

type Mutation {
    createAccount(input: AccountInput!): String!
}

In Java, the AccountInput is represented by a Java Record that contains two fields wrapped in java.util.Optional:

record ContactInput(String phone) {}

record AccountInput(String id,
                      Optional<String> fullname,
                      Optional<ContactInput> contact) { }
 
@MutationMapping
public String createAccount(@Argument AccountInput input) {
  // ...
} 

When I run the mutation and do not specify the contact field everything is fine:

mutation {
  createAccount(input:{
    id: "1",
    fullname: "Klaus"
  })
}

But as soon as I add the contact field to my Mutation...

mutation {
  createAccount(input:{
    id: "1",
    fullname: "Klaus",
  
    contact: {
      phone: "123"
    }
  })
}

...I receive the following error:

2022-08-21 15:55:33.277 ERROR 33878 --- [o-31080-exec-10] s.g.e.ExceptionResolversExceptionHandler : Unresolved InaccessibleObjectException for executionId 117b4274-4eee-e636-3f0e-49d32e34f290

java.lang.reflect.InaccessibleObjectException: Unable to make private java.util.Optional(java.lang.Object) accessible: module java.base does not "opens java.util" to unnamed module @18d87d80
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354) ~[na:na]
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297) ~[na:na]
	at java.base/java.lang.reflect.Constructor.checkCanSetAccessible(Constructor.java:188) ~[na:na]
	at java.base/java.lang.reflect.Constructor.setAccessible(Constructor.java:181) ~[na:na]
	at org.springframework.util.ReflectionUtils.makeAccessible(ReflectionUtils.java:202) ~[spring-core-5.3.22.jar:5.3.22]
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:194) ~[spring-beans-5.3.22.jar:5.3.22]
	at org.springframework.graphql.data.GraphQlArgumentBinder.createValue(GraphQlArgumentBinder.java:304) ~[spring-graphql-1.0.1.jar:1.0.1]
	at org.springframework.graphql.data.GraphQlArgumentBinder.createValueOrNull(GraphQlArgumentBinder.java:235) ~[spring-graphql-1.0.1.jar:1.0.1]
	at org.springframework.graphql.data.GraphQlArgumentBinder.createValue(GraphQlArgumentBinder.java:291) ~[spring-graphql-1.0.1.jar:1.0.1]
	at org.springframework.graphql.data.GraphQlArgumentBinder.bind(GraphQlArgumentBinder.java:163) ~[spring-graphql-1.0.1.jar:1.0.1]
	at org.springframework.graphql.data.method.annotation.support.ArgumentMethodArgumentResolver.resolveArgument(ArgumentMethodArgumentResolver.java:58) ~[spring-graphql-1.0.1.jar:1.0.1]
	at org.springframework.graphql.data.method.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:83) ~[spring-graphql-1.0.1.jar:1.0.1]
	at org.springframework.graphql.data.method.annotation.support.DataFetcherHandlerMethod.getMethodArgumentValues(DataFetcherHandlerMethod.java:170) ~[spring-graphql-1.0.1.jar:1.0.1]
	at org.springframework.graphql.data.method.annotation.support.DataFetcherHandlerMethod.invoke(DataFetcherHandlerMethod.java:115) ~[spring-graphql-1.0.1.jar:1.0.1]
	at org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer$SchemaMappingDataFetcher.get(AnnotatedControllerConfigurer.java:514) ~[spring-graphql-1.0.1.jar:1.0.1]
...

(Btw: the same error occurs if the Optional does not contain a Record but a regular Class. )

The optional fullname (String) on the other hand seems to make no problems and works as expected.

I built a simple example that demonstrates the problem: https://github.com/nilshartmann/spring-graphql-optional

Not sure, but I think, when Optionals are allowed for primitive types, it should work with own objects too?

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

Thanks for the sample and the description. Indeed it looks we're not handling non-primitive constructor args wrapped in Optional.

@rstoyanchev rstoyanchev added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Sep 8, 2022
@rstoyanchev rstoyanchev added this to the 1.0.2 milestone Sep 8, 2022
@rstoyanchev rstoyanchev changed the title Java classes with Optional fields for GraphQL input types fail with InaccessibleObjectException Java classes with Optional constructor args for GraphQL input types fail with InaccessibleObjectException Sep 8, 2022
@nilshartmann
Copy link
Contributor Author

Hi @rstoyanchev, if there is anything I can help/contribute to solve this issue, please let me know.

@rstoyanchev rstoyanchev self-assigned this Sep 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants