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

Type dictionary for ListType

Open mmatela opened this issue 4 years ago • 2 comments

I'm trying to define some graphQL types dynamically using a typeDefinitionFactory and the fact that field values can be resolved using the Map.get() method. It seems to be working fine as long as I don't have fields with list types. Here's a minimal example of the problem I bumped into:

	public static class MyFooType {
		public String bar;
	}
	
	public static class FooResolver extends HashMap<String, Object> implements GraphQLQueryResolver {
		@Override
		public Object get(Object key) {
			if ("foo".equals(key))
				return Arrays.asList(new MyFooType(), new MyFooType());
			throw new IllegalArgumentException("unknown field " + key);
		}
	}
	
	public static void main(String[] args) {
		GraphQLSchema schema =
				SchemaParser.newParser().schemaString("type Query{ foo: [FooType] } type FooType { bar: String }")
						.resolvers(new FooResolver())
						.dictionary("FooType", MyFooType.class)
						.build().makeExecutableSchema();
		System.out.println("OK!");
	}

This causes an exception:

Exception in thread "main" graphql.kickstart.tools.SchemaClassScannerError: Unable to match type definition (ListType{type=TypeName{name='FooType'}}) with java type (java.lang.Object): Java class is not a List or generic type information was lost: class java.lang.Object
	at graphql.kickstart.tools.TypeClassMatcher.error(TypeClassMatcher.kt:20)
	at graphql.kickstart.tools.TypeClassMatcher.match(TypeClassMatcher.kt:78)
	at graphql.kickstart.tools.TypeClassMatcher.match(TypeClassMatcher.kt:23)
	at graphql.kickstart.tools.SchemaClassScanner.scanResolverInfoForPotentialMatches(SchemaClassScanner.kt:257)
	...

I guess the problem could be that the framework doesn't know whether to expect a java.util.List or a java array as the foo value. Is there a way to pass this information? I tried .dictionary("[FooType]", List.class), but that results in another exception:

Exception in thread "main" graphql.kickstart.tools.SchemaClassScannerError: Class in supplied dictionary 'java.util.List' specified type name '[FooType]', but a type definition with that name was not found!
	at graphql.kickstart.tools.SchemaClassScanner.<init>(SchemaClassScanner.kt:53)
	at graphql.kickstart.tools.SchemaParserBuilder.scan(SchemaParserBuilder.kt:153)

mmatela avatar Sep 18 '20 13:09 mmatela

Did you solve it?

nnrudakov avatar Mar 25 '21 09:03 nnrudakov

Nope, I had to add a wrapper class and declare an accessor method for each Collection<?> value in the map, lots of boilerplate.

mmatela avatar Jun 02 '21 17:06 mmatela

Closing this since it's old but here is a working example anyway:

    @Test
    fun `bing`() {
        val schema = SchemaParser.newParser()
                .schemaString(
                    """
                    type Query{ foo: [FooType] }
                    type FooType { bar: String }
                    """)
                .resolvers(FooResolver())
                .dictionary("FooType", FooType::class.java)
                .build().makeExecutableSchema()
    }

    private class FooResolver : GraphQLQueryResolver {
        fun foo(): List<FooType> = listOf()
    }
    data class FooType(val bar: String = "")

oryan-block avatar Jan 31 '24 20:01 oryan-block