我正在尝试根据运行时在类路径上可用的类来确定创建类的新实例的最佳方法。
例如,我有一个需要在多个类中解析JSON响应的库。该库具有以下界面:
JsonParser.java:
public interface JsonParser { <T> T fromJson(String json,Class<T> type); <T> String toJson(T object); }
该类有多个实现,即GsonJsonParser,JacksonJsonParser,Jackson2JsonParser,目前,库的用户需要根据他们在项目中包含的库来“选择”使用它们的实现。例如:
JsonParser parser = new GsonJsonParser(); SomeService service = new SomeService(parser);
我想要做的是动态地选择类路径中的哪个库,并创建正确的实例,以便图书馆的用户不必考虑它(甚至必须知道内部实现另一个类解析JSON)。
我正在考虑类似于以下内容:
try { Class.forName("com.google.gson.Gson"); return new GsonJsonParser(); } catch (ClassNotFoundException e) { // Gson isn't on classpath,try next implementation } try { Class.forName("com.fasterxml.jackson.databind.ObjectMapper"); return new Jackson2JsonParser(); } catch (ClassNotFoundException e) { // Jackson 2 was not found,try next implementation } // repeated for all implementations throw new IllegalStateException("You must include either Gson or Jackson on your classpath to utilize this library");
这将是一个适当的解决方案吗?这似乎是一个黑客,以及使用异常来控制流。
有没有更好的方法来做到这一点?
基本上你想创建自己的JsonParserFactory。我们可以看到它在
Spring Boot framework中的实现方式:
public static JsonParser getJsonParser() { if (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper",null)) { return new JacksonJsonParser(); } if (ClassUtils.isPresent("com.google.gson.Gson",null)) { return new GsonJsonParser(); } if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml",null)) { return new YamlJsonParser(); } return new BasicJsonParser(); }
所以你的做法和这个几乎是一样的,除了使用ClassUtils.isPresent
method。