So, I don't even know how Guice could possibly break this cycle. There
is no instance that can be created such that the incoming parameter can
be initialized properly. That being said, hk2 should certainly NOT hang
here, but instead should detect this very simple cycle. I'll look into
that, because it should truly throw an exception in this case, almost
immediately. (Actually, I wonder if it IS throwing an exception... do
you have a ImmediateErrorHandler
<
https://hk2.java.net/2.4.0-b06/apidocs/org/glassfish/hk2/utilities/ImmediateErrorHandler.html>
defined?)
The proper way to fix this (and this is why JSR-330 invented Provider in
the first place) is to use a Provider (and also, do NOT use
provider.get() in your constructor, since that would also have the same
cycle).
Only one of your three implementation classes need to use it, so picking
one at random to break the cycle, it'd be like this:
*class* ServiceClientImpl *implements* ServiceClient {
*private*Provider<MessageHandler> _handler_;
@Inject
*void* registerHandler(Provider<MessageHandler> _handler_) {
*this*.handler = handler;
}
}
Obviously, other fixes would include using proxies, but I agree that can
get messy and bring in stuff you may not want to have there.
On 11/17/2014 6:15 PM, Mirko Raner wrote:
>
> Hi all,
>
>
> I'm currently dealing with migrating some code from Guice to HK2, and
> we are running into some troubles with circular dependencies in
> @Immediate scope.
>
> Please consider the following interfaces and implementations:
>
>
> *interface* MessageHandler _{_
>
> _}_
>
> *interface* RepositoryClient _{_
>
> _}_
>
> *interface* ServiceClient _{_
>
> _}_
>
> *class* MessageHandlerImpl *implements* MessageHandler {
>
> *private* RepositoryClient _handler_;
>
> @Inject
>
> MessageHandlerImpl(RepositoryClient handler) {
>
> *this*.handler = handler;
>
> }
>
> }
>
> *class* RepositoryClientImpl *implements* RepositoryClient {
>
> *private* ServiceClient _client_;
>
> @Inject
>
> *public* RepositoryClientImpl(ServiceClient client) {
>
> *this*.client = client;
>
> }
>
> }
>
> *class* ServiceClientImpl *implements* ServiceClient {
>
> *private* MessageHandler _handler_;
>
> @Inject
>
> *void* registerHandler(MessageHandler _handler_) {
>
> *this*.handler = handler;
>
> }
>
> }
>
>
> In particular, please note that there is effectively a circular
> dependency between the three implementation glasses. Not good,
> definitely a code smell, but also not the end of the world, and, for
> purposes of this discussion, let's just say it cannot easily be avoided.
>
> In the existing Guice code, there are no problems with instantiating
> the classes. Guice figures out the correct order to instantiate the
> classes and to break the cycle; no proxies or other trickery are
> involved under the hood, AFAICT.
>
>
> To translate the Guice code to HK2, we replaced .asEagerSingletion()
> with .in(Immediate.class). It is my understanding that this is HK2's
> closest equivalent of eager singletons.
>
> Now, if we try to instantiate the objects with HK2, we run into a
> deadlock inside the ImmediateHelper class. The following JUnit test
> demonstrates the issue; Guice produces the correct object graph,
> whereas HK2 times out:
>
>
> *import* org.glassfish.hk2.api.Immediate;
>
> *import* org.glassfish.hk2.api.ServiceLocator;
>
> *import* org.glassfish.hk2.utilities.ServiceLocatorUtilities;
>
> *import* org.glassfish.hk2.utilities.binding.AbstractBinder;
>
> *import* org.junit.Test;
>
> *import* com.google.inject.AbstractModule;
>
> *import* com.google.inject.Guice;
>
> *import* com.google.inject.Injector;
>
> *import**static* org.junit.Assert./assertNotNull/;
>
> *public**class* CircularDependencyInjectionHK2vsGuice {
>
> @Test(timeout=5000)
>
> *public**void* testHK2Immediate() {
>
> ServiceLocator serviceLocator =
> ServiceLocatorUtilities./createAndPopulateServiceLocator/();
>
> ServiceLocatorUtilities./enableImmediateScope/(serviceLocator);
>
> AbstractBinder binder = *new* AbstractBinder() {
>
> @Override
>
> *protected**void* configure() {
>
> bind(ServiceClientImpl.*class*).to(ServiceClient.*class*).in(Immediate.*class*);
>
> bind(MessageHandlerImpl.*class*).to(MessageHandler.*class*).in(Immediate.*class*);
>
> bind(RepositoryClientImpl.*class*).to(RepositoryClient.*class*);
>
> }
>
> };
>
> ServiceLocatorUtilities./bind/(serviceLocator, binder);
>
> MessageHandler messageHandler =
> serviceLocator.getService(MessageHandler.*class*);
>
> ServiceClient serviceClient =
> serviceLocator.getService(ServiceClient.*class*);
>
> /assertNotNull/(messageHandler);
>
> /assertNotNull/(serviceClient);
>
> }
>
> @Test(timeout=5000)
>
> *public**void* testGuiceEagerSingleton() {
>
> AbstractModule module = *new* AbstractModule() {
>
> @Override
>
> *protected**void* configure() {
>
> bind(ServiceClient.*class*).to(ServiceClientImpl.*class*).asEagerSingleton();
>
> bind(MessageHandler.*class*).to(MessageHandlerImpl.*class*).asEagerSingleton();
>
> bind(RepositoryClient.*class*).to(RepositoryClientImpl.*class*);
>
> }
>
> };
>
> Injector injector = Guice./createInjector/(module);
>
> MessageHandler messageHandler =
> injector.getInstance(MessageHandler.*class*);
>
> ServiceClient serviceClient = injector.getInstance(ServiceClient.*class*);
>
> /assertNotNull/(messageHandler);
>
> /assertNotNull/(serviceClient);
>
> }
>
> }
>
> Is this a bug in HK2's Immediate resolution code? Should I file a JIRA
> issue?
>
> Or am I doing something else wrong that sends HK2 into a deadlock?
>
>
> Thanks,
>
>
> Mirko
>
>
>
> This email and any attachments may contain information which is
> confidential and/or privileged. The information is intended
> exclusively for the addressee and the views expressed may not be
> official policy, but the personal views of the originator. If you are
> not the intended recipient, be aware that any disclosure, copying,
> distribution or use of the contents is prohibited. If you have
> received this email and any file transmitted with it in error, please
> notify the sender by telephone or return email immediately and delete
> the material from your computer. Internet communications are not
> secure and Lab49 is not responsible for their abuse by third parties,
> nor for any alteration or corruption in transmission, nor for any
> damage or loss caused by any virus or other defect. Lab49 accepts no
> liability or responsibility arising out of or in any way connected to
> this email.
>