javaspring-bootgraphqlgraphql-javagraphql-spqr

Access to protected field of parent object through child object via a query schema


I am using graphql-spqr So that I don't have to create schema.graphql files.

I have a base class in which most of my other classes inherit from. For example

@GraphQLInterface(name = "BaseResponse", implementationAutoDiscovery = true)
@ToString
@Data
public class BaseResponse {

    @JsonInclude(Include.NON_NULL)
    protected String responseCode;

    @JsonInclude(Include.NON_NULL)
    protected String responseDescription;

    protected String hash;

}

Other classes inherit from the above base class as below

@ToString(callSuper = true)
@Data
@AllArgsConstructor
public class GetAllGroupResponse extends BaseResponse {

    private List<Group> groups;
}

When I set the parent values of GetAllGroupResponse like below

 getAllGroupResponse.setResponseCode(ResponseCodeEnum.SH_97.getRespCode());  
 getAllGroupResponse.setResponseDescription(ResponseCodeEnum.SH_97.getRespDescription());

I wish to retrieve the value of responseCode from my graphql query request

{ getAllPagable(pageNumber : 1, numberOfRecords : 3) { responseCode groups { groupName } } }

but it throws an error below which tells me it can't see the responseCode variable because it is not a direct property of the class GetAllGroupResponse

Validation error of type FieldUndefined: Field 'responseCode' in type 'GetAllGroupResponse' is undefined @ 'getAllPagable/responseCode'

PS. BaseResponse is from a different package/library project that was imported into the current project

UPDATE

Based on the GitHub issues raised and solutions provided. I created a bean as below

@Bean
    public ExtensionProvider<GeneratorConfiguration, ResolverBuilder> resolverBuilderExtensionProvider() {
        String[] packages = {"com.sheeft.microservices.library", "com.sheeft.mircoservice.groups"};
        return (config, current) -> {
            List<ResolverBuilder> resolverBuilders = new ArrayList<>();

            //add a custom subtype of PublicResolverBuilder that only exposes a method if it's called "greeting"
            resolverBuilders.add(new PublicResolverBuilder() {
                @Override
                public PublicResolverBuilder withBasePackages(String... basePackages) {
                    return super.withBasePackages(packages); //To change body of generated methods, choose Tools | Templates.
                }

            });
            //add the default builder
            resolverBuilders.add(new AnnotatedResolverBuilder().withBasePackages(packages));

            return resolverBuilders;
        };
    }

and now I get an error which says the following

object type 'GetAllGroupResponse' does not implement interface 'BaseResponse' because field 'responseCode' is missing

So I decided to add the getResponseCode getter method manually and it runs successfully. When I the call the /graphql endpoint it throws an exception

Object required to be not null", "trace": "graphql.AssertException: Object required to be not null


Solution

  • I think all you need is to set the base packages for your project. E.g.

    generator.withBasePackages("your.root.package", "library.root.package")
    

    Or, if you're using SPQR Spring Starter, add

    graphql.spqr.base-packages=your.root.package,library.root.package
    

    to your application.properties file, for the same effect.

    This is needed when you have a hierarchy of classes across multiple packages (or even libraries, like in your case) to let SPQR know which packages should be exposed, because otherwise it might accidentally expose some framework code or even core Java things like getClass.