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