graphql-java-tools icon indicating copy to clipboard operation
graphql-java-tools copied to clipboard

Unable to determine data class for resolver '...' from generic interface! This is most likely a bug with graphql-java-tools.

Open mxmlnglt opened this issue 5 years ago • 9 comments

using this version of the kickstart:

		<dependency>
			<groupId>com.graphql-java-kickstart</groupId>
			<artifactId>graphql-spring-boot-starter</artifactId>
			<version>5.10.0</version>
		</dependency>

my GraphQL schema:

interface Mother {
  # Mother fields
}

type Child implements Mother {
  # Child & Mother's fields
}

my Java classes:

public class Mother {
    // Mother's fields
}
public class Child extends Mother {
    // Child's fields
}
@Component
public abstract class MotherResolver<T extends Mother> implements GraphQLResolver<T> {
    // Resolving methods for Mother's fields
}
@Component
public class ChildResolver extends MotherResolver<Child> {
    // Resolving methods for Child's fields
}

Starting my Spring Boot app, I get the following stack trace:

Caused by: com.coxautodev.graphql.tools.ResolverError: Unable to determine data class for resolver 'com.company.app.graphql.resolver.ChildResolver' from generic interface! This is most likely a bug with graphql-java-tools.
	at com.coxautodev.graphql.tools.NormalResolverInfo.findDataClass(ResolverInfo.kt:31) ~[graphql-java-tools-5.6.1.jar:na]
	at com.coxautodev.graphql.tools.NormalResolverInfo.<init>(ResolverInfo.kt:19) ~[graphql-java-tools-5.6.1.jar:na]
	at com.coxautodev.graphql.tools.SchemaClassScanner$resolverInfos$1.invoke(SchemaClassScanner.kt:38) ~[graphql-java-tools-5.6.1.jar:na]
	at com.coxautodev.graphql.tools.SchemaClassScanner$resolverInfos$1.invoke(SchemaClassScanner.kt:26) ~[graphql-java-tools-5.6.1.jar:na]
	at kotlin.sequences.TransformingSequence$iterator$1.next(Sequences.kt:174) ~[kotlin-stdlib-1.3.10.jar:1.3.10-release-253 (1.3.10)]
	at kotlin.sequences.SequencesKt___SequencesKt.toCollection(_Sequences.kt:691) ~[kotlin-stdlib-1.3.10.jar:1.3.10-release-253 (1.3.10)]
	at kotlin.sequences.SequencesKt___SequencesKt.toMutableList(_Sequences.kt:721) ~[kotlin-stdlib-1.3.10.jar:1.3.10-release-253 (1.3.10)]
	at kotlin.sequences.SequencesKt___SequencesKt.toList(_Sequences.kt:712) ~[kotlin-stdlib-1.3.10.jar:1.3.10-release-253 (1.3.10)]
	at com.coxautodev.graphql.tools.SchemaClassScanner.<init>(SchemaClassScanner.kt:38) ~[graphql-java-tools-5.6.1.jar:na]
	at com.coxautodev.graphql.tools.SchemaParserBuilder.scan(SchemaParserBuilder.kt:164) ~[graphql-java-tools-5.6.1.jar:na]
	at com.coxautodev.graphql.tools.SchemaParserBuilder.build(SchemaParserBuilder.kt:206) ~[graphql-java-tools-5.6.1.jar:na]
	at com.oembedler.moon.graphql.boot.GraphQLJavaToolsAutoConfiguration.schemaParser(GraphQLJavaToolsAutoConfiguration.java:98) ~[graphql-spring-boot-autoconfigure-5.10.0.jar:na]
	at com.oembedler.moon.graphql.boot.GraphQLJavaToolsAutoConfiguration$$EnhancerBySpringCGLIB$$3914e3f2.CGLIB$schemaParser$3(<generated>) ~[graphql-spring-boot-autoconfigure-5.10.0.jar:na]
	at com.oembedler.moon.graphql.boot.GraphQLJavaToolsAutoConfiguration$$EnhancerBySpringCGLIB$$3914e3f2$$FastClassBySpringCGLIB$$27868fdb.invoke(<generated>) ~[graphql-spring-boot-autoconfigure-5.10.0.jar:na]
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at com.oembedler.moon.graphql.boot.GraphQLJavaToolsAutoConfiguration$$EnhancerBySpringCGLIB$$3914e3f2.schemaParser(<generated>) ~[graphql-spring-boot-autoconfigure-5.10.0.jar:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_212]
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_212]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_212]
	at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_212]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	... 138 common frames omitted

I've seen these (somehow) related issues: https://github.com/graphql-java-kickstart/graphql-java-tools/issues/145 https://github.com/graphql-java-kickstart/graphql-java-tools/issues/163 but with the solution you give in the last comment, I don't understand how I would be able to do something like:

class BazResolver extends FooResolver<Baz> {

}

... because that means this resolver is actually a GraphQLResolver<Bar> which makes no sense at all (from a Java inheritance scheme point of view)!!

Or maybe it's just an erroneous copy/paste from https://github.com/graphql-java-kickstart/graphql-java-tools/issues/331...? (but that's doesn't solve my problem still...)

mxmlnglt avatar Jan 02 '20 14:01 mxmlnglt

My only workaround for now is to move the implements GraphQLResolver<T> to the actual resolver:

@Component
public abstract class MotherResolver<T extends Mother> implements GraphQLResolver<T> { // can be removed from here, it's totally useless...
    // Resolving methods for Mother's fields
}
@Component
public class ChildResolver extends MotherResolver<Child> implements GraphQLResolver<Child> { // totally needed here
    // Resolving methods for Child's fields
}

Edit: fixed from GraphQLResolver<T> to GraphQLResolver<Child> in the ChildResolver, thanks @geeseen

mxmlnglt avatar Jan 02 '20 14:01 mxmlnglt

@Component
public class ChildResolver extends MotherResolver<Child> implements GraphQLResolver<T> { // totally needed here
    // Resolving methods for Child's fields
}

Did you mean:

@Component public class ChildResolver extends MotherResolver<Child> implements GraphQLResolver<Child> { ...}

?

geesen avatar Feb 03 '20 11:02 geesen

@Component
public class ChildResolver extends MotherResolver<Child> implements GraphQLResolver<T> { // totally needed here
    // Resolving methods for Child's fields
}

Did you mean:

@Component public class ChildResolver extends MotherResolver<Child> implements GraphQLResolver<Child> { ...}

?

Oh yeah, right, I missed this before posting (probably just a copy-paste problem).

mxmlnglt avatar Feb 03 '20 12:02 mxmlnglt

Ok, as suspected ;-) Unfortunately, it doesn't work for me if I move the GraphQLResolver from the superclass down to the actual class, when there is also a generic typed method in the super class.

For example, if I have the following:

@Component
public abstract class MotherResolver<T extends Mother> { 

     public T getNext(){
        return ...
     }        
}

This is not working (No type variable found for T)

@Component
public class ChildResolver extends MotherResolver<Child> implements GraphQLResolver<Child> { 
    
}

But, if I explicitly overwrite the method and call its super method, it is working:

@Component
public class ChildResolver extends MotherResolver<Child> implements GraphQLResolver<Child> { 
  
    public Child  getNext(){
        return super.getNext();
     }        
}

Of course, this is only an interim solution, because the child resolvers are then inflated unnecessarily and the advantage of Java inheritance does not pay off here - quite apart from the non-existing DRY principle.

Normally, you should be able to define methods centrally in the MotherResolver, which then also apply to all ChildResolvers, without having to touch the ChildResolver individually.

geesen avatar Feb 04 '20 08:02 geesen

Normally, you should be able to define methods centrally in the MotherResolver, which then also apply to all ChildResolvers, without having to touch the ChildResolver individually.

Yes, exactly. That's what I do.

mxmlnglt avatar Feb 06 '20 15:02 mxmlnglt

Normally, you should be able to define methods centrally in the MotherResolver, which then also apply to all ChildResolvers, without having to touch the ChildResolver individually.

Yes, exactly. That's what I do.

And it is working for you?

geesen avatar Feb 06 '20 15:02 geesen

graphql-java-tools could not parse the <T> in MotherResolver<T extends SomeObj> implements GraphQLResolver<T>, we need do this.

guodage avatar Mar 11 '20 06:03 guodage

Any updates on this?

I'm building a sample project and trying to build a common Resolver to resolve properties of classes at one place For example

public interface MyInterface {
    String getSome();
}

public class ClassA implementes  MyInterface {
    String getSome();
// further props
}
public classB implements MyInterface {
    String getSome();
// further props
}


public class MyAweseomeResolver<T extends MyInterface> implements GraphQLResolver<T> {
    public String getSomeString(final T concrete) {
         return concrete.getSome().toUpperCase()
    }
}

Background: I don't want to implement a resolver for each class which are at least doing the same. I just want to have one resolver which applies to all classes implementing one interface.

matsmad avatar Nov 13 '20 09:11 matsmad

@matsmad AFAIK there has been no intervention from someone of the team here; so you'll probably have to apply my workaround: https://github.com/graphql-java-kickstart/graphql-java-tools/issues/349#issuecomment-570226121

mxmlnglt avatar Dec 03 '20 11:12 mxmlnglt