Skip to content

ClassCastException when using entity interfaces with Apollo Federation #516

Open
@woofware-engineer

Description

@woofware-engineer

Overview: I am encountering an incompatibility issue between graphql-spqr and com.apollographql.federation when using entity interfaces, as outlined in the Apollo Federation documentation.

Details: The GraphQLSchema generated by graphql-spqr cannot be processed by Apollo's Federation.transform() method. This results in a ClassCastException, specifically:

Caused by: java.lang.ClassCastException: class java.lang.String cannot be cast to class graphql.language.StringValue 

That ClassCastException occurs on this line of the Apollo code.

Context: This exception arises when a GraphQL Interface is included in the _entity federated types. Below is a snippet of the relevant code:

@GraphQLDirective(name = "key")
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface KeyDirective {
    String fields();
}


@KeyDirective(fields = "foo") 
@GraphQLInterface(name = "MyInterface")
public interface MyInterface {

    @GraphQLQuery(name = "foo")
    int getFoo();

  
}

When attempting to transform the schema with Federation:

 GraphQLSchema schema = new GraphQLSchemaGenerator()
                .withBasePackages("org.example")
                .withOperationsFromSingleton(myResolver)
                .generate();

        GraphQLSchema federatedSchema = Federation.transform(schema) 

we'll see the above Exception

Caused by: java.lang.ClassCastException: class java.lang.String cannot be cast to class graphql.language.StringValue (java.lang.String is in module java.base of loader 'bootstrap'; graphql.language.StringValue is in unnamed module of loader 'app')
	at com.apollographql.federation.graphqljava.SchemaTransformer.lambda$retrieveFieldSets$11(SchemaTransformer.java:189)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
	at java.base/java.util.Collections$2.tryAdvance(Collections.java:4820)
	at java.base/java.util.Collections$2.forEachRemaining(Collections.java:4828)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
	at com.apollographql.federation.graphqljava.SchemaTransformer.retrieveFieldSets(SchemaTransformer.java:191)
	at com.apollographql.federation.graphqljava.SchemaTransformer.lambda$getFederatedEntities$6(SchemaTransformer.java:153)
	at graphql.com.google.common.collect.ImmutableList.forEach(ImmutableList.java:422)
	at com.apollographql.federation.graphqljava.SchemaTransformer.lambda$getFederatedEntities$7(SchemaTransformer.java:149)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
	at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
	at com.apollographql.federation.graphqljava.SchemaTransformer.getFederatedEntities(SchemaTransformer.java:146)
	at com.apollographql.federation.graphqljava.SchemaTransformer.build(SchemaTransformer.java:89)
	at org.example.GraphQlController.<init>(GraphQlController.java:35)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:204)

A minimal example project which is replicating the issue is attached.

spqr-federation-interfaces.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions