1

短い答え: Object インスタンスにバインドするには、bind() メソッドに Class<Object> パラメータを指定する必要があります。それは言った:

Class<?> type = got_a_type(); Object object = got_an_object();
// Illegal - compilation error because of type check comparing ? to Object
bind(type).toInstance(object);
// Legal and working 
bind((Class<Object>)type).toInstance(object);

長い話:

古いシステムのjson構成ファイルを次の形式で持っています:

{
    "$type": "test_config.DummyParams",
    "$object": {
        "stringParam": "This is a string",
        "integerParam": 1234,
        "booleanParam": false
    }
}

test_config.DummyParams は、プログラムの実行時に使用できるクラスで、次のようになります。

package test_config;

public class DummyParams {
    public String stringParam;
    public int integerParam;
    public boolean booleanParam;
}

DummyParams タイプのコンストラクターパラメーター (注入する必要がある) を持つ Guice によって作成したいクラスがあります。

@Inject
public class DummyService(DummyParams params) { ... }

現在、DummyParams クラスは実行時にのみ (json 構成ファイルを介して) 提供されるものであり、コンパイル時には認識できないため、この型を Guice バインディングで使用することはできません。

// Can't do this because DummyParams type should come from config file
Object object = ...; // Getting object somehow
bind(DummyParams.class).toInstance((DummyParams)object);

すべてのjson構成ファイルから読み取ったクラスとオブジェクト(タイプとインスタンス)のペアを提供する古いコードがいくつかあります:

class ConfigObject { 
    Class<?> type;
    Object instance;
}

私は単にそれらをバインドしようとしました:

ConfigObject obj = config.read(); // Getting pairs from config files walker
bind(obj.type).toInstance(obj.instance);

しかし、これはコンパイルできません。

ここで質問があります: ランタイムで決定される型のインスタンスをバインドする方法は? 私は IoC の概念を破っており、私がやろうとしていることをすべきでしょうか?

4

2 に答える 2

1

生の型、暗黙的なチェックされていないキャスト、およびいくつかの guava ライブラリの使用と悪用:

public class RuntimeParams {
  public static void main(String[] args) throws ClassNotFoundException, IOException {

    // reads from config and bind in runtime
    final ConfigReader config = new ConfigReader();
    final ConfigObject configObject = config.read();
    final Injector injector = Guice.createInjector(new AbstractModule() {
      @Override protected void configure() {
        bind(configObject.type).toInstance(configObject.instance);
      }
    });

    // use the binded instance
    final DummyParams instance = injector.getInstance(DummyParams.class);
    System.out.println("DummyParams' stringParam: " + instance.stringParam + "\nDummyParams' integerParam: "
        + instance.integerParam + "\nDummyParams' booleanParam: " + instance.booleanParam);
  }
}

class ConfigObject<T> {
  private static final Gson gson = new Gson();

  final T instance;
  final Class<T> type;

  ConfigObject(final String json, final Class<T> type) {
    this.instance = gson.fromJson(json, type);
    this.type = type;
  }
}

class ConfigReader {
  private static final Gson gson = new Gson();

  ConfigObject read() throws ClassNotFoundException, IOException {
    try (final FileReader reader = new FileReader(new File("src/main/resources/runtimeClazzNParams.json"));) {
      final Map<String, Object> configMap = gson.fromJson(reader, Types.mapOf(String.class, Object.class));
      final Class<?> clazz = Class.forName((String) configMap.get("$type"));
      return new ConfigObject<>(gson.toJson(configMap.get("$object")), clazz);
    }
  }
}

これは Vladimir のソリューションに似ていますが、オブジェクトの直接参照ではなく、キャストが暗黙的で生の型になっています。

また、Gson guava クラス メソッドを使用して JSON を解析する新しい方法も作成しました。

于 2013-07-02T10:45:41.537 に答える