question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Inheritance & GraphQLInterface

See original GitHub issue

Hey, I’ve got problem with creating some abstraction over my code and schema. What I want to achieve is, that in GraphQL Schema, “MyList” implements Interface, and I could see fields from PageableAndSortableList class only in Schema “Interface”.

@GraphQLType(name = "MyList")
public class MyGraphQLList<T> extends PageableAndSortableList {

    private List<T> pageList;
    private Order order;
    private int limit;
    private String cursor;

    @GraphQLNonNull
    public String getCursor() {
        return cursor;
    }

}
@GraphQLInterface(name = "Interface")
public abstract class PageableAndSortableList {

    protected Long total;

    protected Integer count;

    protected String next;

}

Having something like this with proper getters and setters ofc, I receive the following error on spring boot app start:

Caused by: graphql.schema.validation.InvalidSchemaException: invalid schema: object type ‘MyList_Contact’ does not implement interface ‘Interface’ because field ‘count’ is missing object type ‘MyList_Contact’ does not implement interface ‘Interface’ because field ‘next’ is missing object type ‘MyList_Contact’ does not implement interface ‘Interface’ because field ‘total’ is missing at graphql.schema.GraphQLSchema$Builder.build(GraphQLSchema.java:241) ~[graphql-java-7.0.jar:na] at graphql.schema.GraphQLSchema$Builder.build(GraphQLSchema.java:231) ~[graphql-java-7.0.jar:na] at io.leangen.graphql.GraphQLSchemaGenerator.generate(GraphQLSchemaGenerator.java:824) ~[spqr-0.9.6.jar:na] at com.example.demo.graphql.GraphQLController.<init>(GraphQLController.java:43) ~[classes/:na] at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_121] at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_121] at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_121] at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_121] at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:142) ~[spring-beans-4.3.14.RELEASE.jar:4.3.14.RELEASE] … 20 common frames omitted

Could you help me with some solution.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:10 (4 by maintainers)

github_iconTop GitHub Comments

4reactions
kaqqaocommented, Feb 12, 2018

I’ve just tested this, and as long as you have the getters on the abstract class, it works as expected:

@GraphQLInterface(name = "Interface")
    public static abstract class PageableAndSortableList {

        private Long total;
        private Integer count;
        private String next;

        public Long getTotal() {
            return total;
        }

        public void setTotal(Long total) {
            this.total = total;
        }

        public Integer getCount() {
            return count;
        }

        public void setCount(Integer count) {
            this.count = count;
        }

        public String getNext() {
            return next;
        }

        public void setNext(String next) {
            this.next = next;
        }
    }

The reason why it may be failing for you is that the abstract class and the implementation class are not in the same package and you didn’t set the global basePackages. If there is a finite set of base packages where all the stuff in your app that you want exposed resides, you can simply use GraphQLSchemaGenerator#withBasePackages to configure the packages.

E.g. generator.withBasePackages("com.your.company"). If possible, this is the recommended approach.

One reason why this is important is that nested classes are normally scanned for getters to expose as GraphQL fields even when they’re not annotated with @GraphQLQuery. But there is no way to know if some of the inherited getters are framework methods or default Java stuff that should’t be exposed. So, what BeanResolverBuilder does by default is filter the methods my package. If you don’t set any base packages, it only considers the package of the scanned class as acceptable (MyGraphQLList in your case). And if some super classes/interfaces are from a different package, their methods will be filtered out. This is likely what happened, so MyGraphQLList ended up without the total, count and next fields, and is thus not a valid implementation if its interface.

You can also set a separate ResolverBuilder per type, if you can’t or don’t want to set the base packages globally. E.g.

generator.withNestedResolverBuildersForType(new TypeToken<MyGraphQLList<String>>(){}.getType(), new BeanResolverBuilder("some.package"))

This way it will only use some.packge as the criteria when mapping MyGraphQLList<String> and not other types.

Unfortunately, the code will not work in your case because of a bug in the hashCode implementation in a library SPQR uses under the hood. I’ll have that fixed asap.

0reactions
daviestobialexcommented, Jul 2, 2019

@kaqqao I deeply apologize. I was using an older version of your library version 0.03 I switched to version 0.05 and it works now.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Can a GraphQL input type inherit from another type or interface?
No, the spec does not allow input types to implement interfaces. And GraphQL type system in general does not define any form of...
Read more >
Inheritance and interfaces - GraphQLite
Modeling inheritance​ ... Some of your entities may extend other entities. GraphQLite will do its best to represent this hierarchy of objects in...
Read more >
Interfaces and inheritance - TypeGraphQL
Interfaces and inheritance ... The main idea of TypeGraphQL is to create GraphQL types based on TypeScript classes. In object-oriented programming it is...
Read more >
Unions and interfaces - Apollo GraphQL Docs
Unions and interfaces are abstract GraphQL types that enable a schema field to return one of multiple object types. Union type.
Read more >
Proposal: Add Interface inheritance for definitions #335 - GitHub
It's similar but not related. Inheritance implies that the parent interface's fields are implicitly included in the child interface's schema. Additionally, you' ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found