Distelli/graphql-apigen

Can the generated code be guice-agnostic? (support optionally using it with spring as well)

Closed this issue · 5 comments

We don't use guice much here and tend to use spring boot for our DI container.

In looking over the generated code, it seems that if you were to switch the @Inject(optional=true) guice annotation and have it use the javax.inject @Inject annotation instead (you'd lose the 'optional' part, so I guess they'd all be "required"? would that still work with guice?)

If the main parts that got generated didn't require guice anymore, it seems like it would be possible to create a template in the .stg to generate an @Configuration annotated config to help wire things together for spring users. (Spring and guice can both handle the @Inject annotations, so the core pieces would be remain the same)

Does this sound like something worthwhile?

Swapping out the @Inject annotations would allow marking guice as <optional>true</optional> in the dependencies pom as well.

I'm keen on this, but then usable is decreased. Specifically, if you make this desired change, then the current tests will break (which wire using Guice) with the following error:

1) No implementation for com.distelli.posts.Author was bound.
  while locating com.distelli.posts.Author
    for field at com.distelli.posts.AuthorTypeProvider._impl(AuthorTypeProvider.java:13)
  at com.distelli.posts.PostsModule.configure(PostsModule.java:10)

2) No implementation for com.distelli.posts.InputPost was bound.
  while locating com.distelli.posts.InputPost
    for field at com.distelli.posts.InputPostTypeProvider._impl(InputPostTypeProvider.java:11)
  at com.distelli.posts.PostsModule.configure(PostsModule.java:16)

3) No implementation for com.distelli.posts.Post was bound.
  while locating com.distelli.posts.Post
    for field at com.distelli.posts.PostTypeProvider._impl(PostTypeProvider.java:12)
  at com.distelli.posts.PostsModule.configure(PostsModule.java:12)

3 errors
	at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:466)
	at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:155)
	at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:107)
	at com.google.inject.Guice.createInjector(Guice.java:96)
	at com.google.inject.Guice.createInjector(Guice.java:73)
	at com.google.inject.Guice.createInjector(Guice.java:62)
	at com.distelli.posts.PostsTest.setup(PostsTest.java:142)
	at com.distelli.posts.PostsTest.testQuery(PostsTest.java:162)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
	at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
	at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
	at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
	at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
	at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)

If you have ideas on how to make this easy and drop the dependency, I'm onboard :).

Yeah, that is interesting.

Can the apigen target java 8+?

Doing something like this might get around the issue:

@Inject
private Optional<SomeBean> someBean;

I think Spring will handle that ok, and I assume guice will too?

When you use it, you have to get the instance out of the Optional so the stg would need a little tweaking for that too - but I think it should work. I'll test and see

But this brings up an interesting point - The Author / Post / InputPost seem like they are domain objects. How does the @Inject with those providers work? (does it somehow dynamically consult the Providers each time? how does an instance of Author or Post get into that resolution process?)

On further testing... guice doesn't support @Inject on an optional field:

1) Could not find a suitable constructor in java.util.Optional. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.

I'll poke at this some more and see if there are other options

I came up with this fix here:

f87d1f9

...and released it as 2.0.0. Please let me know if this works for you. I assume that Guice can inject java.util.Optional instances.