To inject a populated Map<String, String>

2,979 views
Skip to first unread message

Karthik Krishnan

unread,
Apr 28, 2008, 1:07:09 PM4/28/08
to google-guice
Hi,

I am working on the webapp which takes a userId and loads all the US
states into a Map<String, String> from an Oracle db. Now, I wish to
make this Map available to everybody. I did something like this.

@Singleton
public class DbManager {
private Map<String, String> states;

@Inject
public DbManager(StatesLoader st) {
this.states = st.getStates();
}

public static Map<String, String> getStatesCodes() {
return states;
}
}

In the DbManagerModule
public class DbManagerModule extends AbstractModule {
@Override
public void configure() {
bind(StatesLoader.class).
toInstance(new StatesLoader());
}
}



Invocation;
public Map<String, String> getStatesCodes() {
Injector injector = Guice.createInjector(new DbManagerModule());
DbManager dbManager = injector.getInstance(DbManager.class);
return dbManager.getStatesCodes();
}

I only want to inject a Map <String, String> object rather than the
Loader object which right now makes a JDBC call to populate the Map
object. Is there a better way to do this? Please help





Robbie Vanbrabant

unread,
Apr 28, 2008, 1:27:57 PM4/28/08
to google...@googlegroups.com
What do you mean "it takes a userId and loads all the US states"? I guess the US states are the same for every user and that they don't change that often.

Anyway, I suppose you want to have that Map<String, String> as a singleton provided by Guice. Some quick ideas:
- Populate a Map before you create the Injector, and bind it toInstance
- Bind to a Provider as an eager singleton that queries the states and returns a Map
- ...

Remember to bind that Map<String,String> using a TypeLiteral.

Cheers
Robbie

Karthik Krishnan

unread,
Apr 29, 2008, 3:38:58 PM4/29/08
to google-guice
Hi Robbie,

Thanks for your reply.

I thought about that. But That would mean creating a StatesLoader as
DAO to query the database and a factory impl to return an instance of
DAO, which in turn would return a Map<String, String> if I were to use
good coding practices. Only then would I be able to inject the Map
object. My intention behind using GUICE was to avoid using a factory
implementation.
For the second option, I did not understand. Are you referring to an
implementation something like this? If yes, I would have instantiate
the Map<String, String> object before binding to a provider.

public class StatesProvider implements Provider<Map<String, String>> {
private Map<String, String> states;

@Inject
public StatesProvider(Map<String, String> states) {
this.states = states;
}

public Map<String, String> get() {
return this.states;
}
}

Again a TypeLiteral object requires an instance to be initialized. I
wanted to do something like this in GUICE, and using a example from
Spring's framework

public class StatesLoader extends ApplicationObjectSupport {

private static Map<String, String> states = new HashMap<String,
String>();

@Override
protected void initApplicationContext() {
// Populate {@link #states} after querying the database.
}

public static Map<String, String> getStates() {
return states;
}
}



On Apr 28, 10:27 am, "Robbie Vanbrabant" <robbie.vanbrab...@gmail.com>
wrote:
> What do you mean "it takes a userId and loads all the US states"? I guess
> the US states are the same for every user and that they don't change that
> often.
>
> Anyway, I suppose you want to have that Map<String, String> as a singleton
> provided by Guice. Some quick ideas:
> - Populate a Map before you create the Injector, and bind it toInstance
> - Bind to a Provider as an eager singleton that queries the states and
> returns a Map
> - ...
>
> Remember to bind that Map<String,String> using a TypeLiteral.
>
> Cheers
> Robbie
>
> On Mon, Apr 28, 2008 at 7:07 PM, Karthik Krishnan <Krishnan.1...@gmail.com>

Robbie Vanbrabant

unread,
Apr 29, 2008, 3:59:36 PM4/29/08
to google...@googlegroups.com
Using that example, the quick solution would be:

public class StatesLoader {


private static Map<String, String> states = new HashMap<String,
String>();

public StatesLoader() { initApplicationContext(); }


 protected void initApplicationContext() {
    // Populate {@link #states} after querying the database.
 }

 public static Map<String, String> getStates() {
    return states;
 }
}

Then in the Module:
bind(StatesLoader.class).asEagerSingleton();

Now, although this works, try to avoid statics and consider using a provider. Something like:
bind(new TypeLiteral<Map<String,String>>(){}).toProvider(StatesProvider.class).asEagerSingleton();

StatesProvider implements Provider<Map<String,String>> {

  public Map<String, String> get() {
    // query and return
  }
}

Then simply @Inject Map<String,String> wherever you need them.
I probably made a typo here and there. But you get the idea.

Hope this helps,
Robbie

Dhanji R. Prasanna

unread,
Apr 29, 2008, 5:28:13 PM4/29/08
to google...@googlegroups.com
Why not make StatesLoader an @Singleton? and simply return the cached value of map after the first get?
The typeliteral/provider around it can eliminate the need for StatesLoader in your clients (and inject the map directly).

Dhanji.
Reply all
Reply to author
Forward
0 new messages