1

I am trying to bind a bunch of types from a properties Map where the type of Key is String and the type of value in the map is String, Boolean, Int, Long, etc or even some type of object.

This is in scala but the same applies to java

   class GuiceFlagsModule(
      flags: Map[String, Any])
      extends AbstractModule
      with Logging {

      def configure() {
        for ((flagName, flag) <- flags) {
          debug("Binding flag: " + flagName + " = " + flag)
          val key2 = Key.get(value.getClass, new FlagImpl(flagName))
          binder.bind(key2).toInstance(value)
        }
      }
    }

The last line here does not compile

binder.bind(key2).toInstance(value)

How can I get this to compile so it binds the generic type correctly?

I just tried this out in java and it seems to work in intellij but then fails on javac compiler :(.

public void tryMe(Object someObj) {
    Binder b = null;
    Key k = Key.get(someObj.getClass(), new FlagImpl("name"));
    b.bind(k).toInstance(someObj);
}

so how to do this in java or scala?

I managed to get it working in java like so

public static void bind(Binder binder, String flagName, Object value) {
    Key<Object> key = Key.get((Class) value.getClass(), new FlagImpl(flagName));
    binder.bind(key).toInstance(value);
}

I still do not have it working in scala

thanks, Dean

Dean Hiller
  • 19,235
  • 25
  • 129
  • 212

2 Answers2

1

You need to ensure that the type parameter of Key<T> matches the type of value.

The bad news is: I don't know of any safe way to do this, at least in the general case. The good news is that it can be done easily with an unchecked cast. I don't know Scala well enough to say for sure, but in Java I would write it like this:

public static <T> void bind(Binder binder, String flagName, T value) {
  @SuppressWarnings("unchecked")
  Class<T> valueClass = (Class) value.getClass();
  Key<T> key = Key.get(valueClass, new FlagImpl(flagName));
  binder.bind(key).toInstance(value);
}

Unfortunately the unchecked cast is needed because getClass() doesn't return Class<T> like you would think, due to type erasure (what else?).

If you know the type of value it's easier:

public static <T> void bind(
    Binder binder, String flagName, Class<T> valueClass, T value) {
  Key<T> key = Key.get(valueClass, new FlagImpl(flagName));
  binder.bind(key).toInstance(value);
}

But that of course just pushes the problem out to the caller.

Community
  • 1
  • 1
Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135
0

The posted solution did not work for me:

public static void bind(Binder binder, String flagName, Object value) {
    Key<Object> key = Key.get((Class) value.getClass(), new FlagImpl(flagName));
    binder.bind(key).toInstance(value);
}

This would bind everything to the java.lang.Class object. However, this worked:

Class impl = ...
Class intrf = ...
binder.bind(intrf).to(impl);
GaspardP
  • 4,217
  • 2
  • 20
  • 33