Stop on first exception during eager singleton creation

674 views
Skip to first unread message

Lóránt Pintér

unread,
Jul 26, 2011, 6:13:16 AM7/26/11
to google-guice
Hi,

I have a system configured via Guice 3.0, built up of many services.
Many of these services are configured as eager singletons. Each
service can fail to start up, and throw an exception in its
constructor. The behavior I'd like to get is if any of the services
throws an exception, the whole Guice.createInjector() call should stop
at that point throwing that exception. However, I don't seem to manage
to get this from Guice.

Currently if a low-level service (such as my JdbcConnectionService
that is the basis of all database-based services) fails to start up,
Guice seems to continue to try to instantiate other eager singletons,
and when those ask for the failed low-level service, Guice tries to
instantiate it again.

In the end there are two problems with this:
* I get dozens of exceptions that are hard to decipher. A single
exception with the original problem would be a lot easier to handle.
It's not important for me if it gets wrapped in CreationException/
ProvisionException or not.
* Some of my low-level services have side-effects, like static
registries being initialized. (Yeah, I know, but this is a legacy
project I'm trying to convert.) If their constructor gets called
multiple times, all kinds of problems can arise.

So, to sum it up, all I want is Guice.createInjector() to fail fast
when it encounters a problem creating eager singletons. How can I get
there? I'm not using ThrowingProviders, and it doesn't strike me as
the tool I'd need for the job either. I'd like to inject object
instances, and not juggle around with Providers if I don't have to.


Thanks,
Lorant

PS: Here's a little sample code to demonstrate what I would like to
have. Currently I get 3 errors, and my FaultyService() constructor
gets called three times. What I would like to have is to stop at the
first exception thrown by FaultyService():


import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Scopes;

public class GuiceExceptionsTest {

public static void main(String[] args) {
Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(Service.class).to(FaultyService.class).asEagerSingleton();
bind(ClassA.class).asEagerSingleton();
bind(ClassB.class).asEagerSingleton();
}
});
// Throws 3 exceptions, one for each class
}

interface Service {}

static class ClassA {
@Inject
ClassA(Service service) {}
}

static class ClassB {
@Inject
ClassB(Service service) {}
}

static class FaultyService implements Service {
static int counter = 0;
FaultyService() {
throw new RuntimeException("Error #" + ++counter);
}
}
}

Devangini

unread,
Jul 30, 2011, 5:55:54 AM7/30/11
to google...@googlegroups.com
is there a similar exception handling mechanism for providers.

e.g.

suppose class A is the main class and classes B and C are injected in the it.
so if an exception occurs in B then C and A should not be instantiated

scott

unread,
Jul 30, 2011, 3:27:31 PM7/30/11
to google-guice
This is just my opinion, but I suspect that this is a "feature" of
Guice, and I don't know of a way to configure different behavior, but
maybe one exists.

I know in your case its the same exception causing the 3 bindings to
fail, but if there were 3 different exceptions while resolving
bindings, Guice will catch the first one and continue on, printing out
the total list of exceptions that occurred while configuring your
module. This can be useful when wiring up your application for the
first time, if it failed fast you'd find the first problem, fix it,
deploy, find the next problem, etc.

For your case, you might be able to separate your bindings using a
child injector to get the behavior you want. Something like:

Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {

bind(Service.class).to(FaultyService.class).asEagerSingleton();
}
});

Injector childInjector = injector.createChildInjector(new
AbstractModule() {
@Override
protected void configure() {
bind(ClassA.class).asEagerSingleton();
bind(ClassB.class).asEagerSingleton();
}
});

This way if FaultyService throws an exception, the application won't
even try to create the child injector.
Reply all
Reply to author
Forward
0 new messages