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

Ignore Interface on GraphQL Model Classes for Schemabuilder #503

Open
michaelsonnleitner opened this issue Nov 4, 2020 · 16 comments
Open

Comments

@michaelsonnleitner
Copy link

I have following GraphQL Endpoint with following Java Model and Interface.

@GraphQLApi
public class ModelGraphQL {
    @Query
    public Model getModel(@Name("id") long id) {
        return new Model(id);
    }
}
public class Model implements AnyInterface {
   public void someMethod() {  }
}
public class Model2 implements AnyInterface {
   public void someMethod() {  }
}
public interface AnyInterface {
void someMethod();
}

Is it possible to be able to tell the schemabuilder not to add all Types implementing AnyInterface to the schema.

eg. Cloneable and Serializable is not added to schema.

@phillip-kruger
Copy link
Member

Hi @michaelsonnleitner . I don't think at the moment that there is a way, you can try and use events (see https://quarkus.io/blog/experimental_graphql/#events-and-custom-execution) to manually remove that as a workaround for now.

I'll keep this issue open and we can maybe look at supporting @Ignore on Type level.

@michaelsonnleitner
Copy link
Author

the real problem is that the schema parse can not deal with following model

public class MyList extends ArrayList<Model>

getting following error on startup:

Caused by: io.smallrye.graphql.schema.SchemaBuilderException: No class info found for parametrizedParentType name [java.util.ArrayList]
	at io.smallrye.graphql.schema.creator.ReferenceCreator.getReference(ReferenceCreator.java:286)
	at io.smallrye.graphql.schema.creator.ReferenceCreator.createReferenceForPojoField(ReferenceCreator.java:149)
	at io.smallrye.graphql.schema.creator.FieldCreator.createFieldForPojo(FieldCreator.java:114)
	at io.smallrye.graphql.schema.creator.type.TypeCreator.addFields(TypeCreator.java:104)
	at io.smallrye.graphql.schema.creator.type.TypeCreator.create(TypeCreator.java:72)
	at io.smallrye.graphql.schema.creator.type.TypeCreator.create(TypeCreator.java:41)
	at io.smallrye.graphql.schema.SchemaBuilder.createAndAddToSchema(SchemaBuilder.java:197)
	at io.smallrye.graphql.schema.SchemaBuilder.addTypesToSchema(SchemaBuilder.java:130)
	at io.smallrye.graphql.schema.SchemaBuilder.generateSchema(SchemaBuilder.java:111)
	at io.smallrye.graphql.schema.SchemaBuilder.build(SchemaBuilder.java:80)
	at io.smallrye.graphql.schema.SchemaBuilder.build(SchemaBuilder.java:67)
	at io.smallrye.graphql.servlet.StartupListener.contextInitialized(StartupListener.java:61)
	at io.undertow.servlet.core.ApplicationListeners.contextInitialized(ApplicationListeners.java:187)
	at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:217)
	at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:186)
	at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:42)
	at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
	at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
	at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
	at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
	at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
	at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
	at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:252)

@phillip-kruger
Copy link
Member

Ok, that is a different story. Yes that is not supported at the moment, but again, let's keep this issue open and add support for this.

@phillip-kruger
Copy link
Member

@michaelsonnleitner - can you create a reproducer ? That will fast track this.

@michaelsonnleitner
Copy link
Author

michaelsonnleitner commented Nov 9, 2020

I have added it to following example. https://github.com/michaelsonnleitner/sample-async-graphql/blob/master/src/main/java/at/raiffeisen/graphql/Adress2nd.java

Adress2nd is not referenced in my GraphQL Resource but indirectly referenced by https://github.com/michaelsonnleitner/sample-async-graphql/blob/master/src/main/java/at/raiffeisen/graphql/AdressCode.java

following schema is generated:

interface AdressCode {
  code: String
}

type Adress implements AdressCode {
  code: String
  detailAdresses: DetailAdress
  id: BigInteger!
  lines: [String]
}

type Adress2nd implements AdressCode {
  code: String
  id: BigInteger!
  lines: [String]
}
...

It would be nice to add @Ignore on AdressCode Interface

@phillip-kruger phillip-kruger added this to the 1.0.16 milestone Nov 9, 2020
@phillip-kruger
Copy link
Member

Ok cool. I would think that the @Ignore must be on Adress2nd ?

@michaelsonnleitner
Copy link
Author

yes and no ;)

ignore on AdressCode would ignore any other class implementing it
igonre on Adress2nd would only ignore that class.

@phillip-kruger
Copy link
Member

phillip-kruger commented Nov 9, 2020

Ok, so if added to the interface, we also do not create the

interface AdressCode {
  code: String
}

part in the schema ?

@michaelsonnleitner
Copy link
Author

in my opinion not. but I am new in graphql

@phillip-kruger
Copy link
Member

mmm, But that would not make sense, if you add @Ignore on the AddressCode interface, I would assume we need to ignore that interface ?

@michaelsonnleitner
Copy link
Author

yes ignore and not add to schema (in my opinion)

@phillip-kruger
Copy link
Member

This requires a change in the spec to allow using the annotation on TYPE:
I created eclipse/microprofile-graphql#346 for that.

@phillip-kruger phillip-kruger removed this from the 1.0.16 milestone Nov 20, 2020
@t1
Copy link
Collaborator

t1 commented May 12, 2022

Do I get this right: if the interface is @Ignored, the subclasses should still be in the schema, but not with the common interface, which is possible in GraphQL? But what would happen if Adress2nd would be @Ignored, but the code actually returns it?

@phillip-kruger
Copy link
Member

I don't think we finalized on how this should work. Probably something that needs discussion on spec level

@robp94
Copy link
Contributor

robp94 commented Jun 15, 2022

Would be nice to have this.

@mikoma
Copy link

mikoma commented Jun 5, 2024

I've come across the same issue on a slightly different usecase. I have a type class that implements an interface and has subclasses for input. The input classes also appear as a type in the schema, even though they are never returned anywhere.

public interface Asset {
    @NonNull @Id
    UUID getId();
}

public class MyAsset implements Asset{
    private UUID id;
    private String name;
    
    @Override @NonNull @Id
    public UUID getId() { return id; }
    @NonNull
    public String getName() { return name; }
    
    protected void setId(UUID id) { this.id = id; }
    protected void setName(String name) { this.name = name; }
}

public class MyAssetUpdate extends MyAsset {
    @Override
    public void setName(@NonNull String name) { super.setName(name); }
}

@GraphQLApi
public class ApiGqlResource {
    @Query
    public MyAsset getMyAsset() {
        return new MyAsset();
    }

    @Mutation
    public MyAsset updateMyAsset(@NonNull MyAssetUpdate data) {
        return data;
    }
}

Generated schema:

interface Asset {
  id: ID!
}

type Mutation {
  updateMyAsset(data: MyAssetUpdateInput!): MyAsset
}

type MyAsset implements Asset {
  id: ID!
  name: String
}

type MyAssetUpdate {
  id: ID!
  name: String!
}

input MyAssetUpdateInput {
  name: String!
}

The generated type MyAssetUpdate is never returned and does not serve any purpose and should not show up in my schema.
It also becomes conflicting, if I decided that I want to omit the Input suffix from the names of the input fields.
I can't do it because the schema creation will throw an error, because type and input would have the same names.

@Input("MyAssetUpdate")
public class MyAssetUpdate extends MyAsset {
    @Override
    public void setName(@NonNull String name) { super.setName(name); }
}

throws this exception

Caused by: graphql.AssertException: All types within a GraphQL schema must have unique names. No two provided types may have the same name.
No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types).
You have redefined the type 'MyAssetUpdate' from being a 'GraphQLObjectType' to a 'GraphQLInputObjectType'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants