guice 辅助注入 + 多重绑定 + 仿制药

2024-03-24

我试图结合 Guice 的这 3 个功能:注入、多重绑定、泛型。我创建了一个生产项目的原型,所以这里是:

首先,这是泛型的一个小层次结构(在生产情况下有 N 个实体的层次结构):

    public interface Type {
    }
    public class Type1 implements Type{
    }
    public class Type2 implements Type {
    }

接下来,我想通过Factory创建类ToCreate1ToCreate2

基类:

    public abstract class AbstractToCreate<T extends Type> {
        public T type;
        public Integer param;

        public AbstractToCreate(T type, Integer param){
            this.type = type;
            this.param = param;
        }
    }

它的继承者:

    public class ToCreate1 extends AbstractToCreate<Type1>{
        @Inject
        public ToCreate1(Type1 type, @Assisted Integer param) {
            super(type, param);
        }  
    }

   public class ToCreate2 extends AbstractToCreate<Type2> {
        @Inject
        public ToCreate2(Type2 type, @Assisted Integer param) {
            super(type, param);
        }
    }

然后,工厂本身:

    public interface Factory<T extends Type> {
        AbstractToCreate<T> create(Integer param);
    }

所以,现在我想注入一个地图,包含 FactoryFactory 来创建 ToInject1ToInject2 分别。

因此,我使用配置方法创建 Guice 的 AbstractModule

    protected void configure() {
            install(new FactoryModuleBuilder()
                    .implement(new TypeLiteral<AbstractToCreate<Type1>>(){}, ToCreate1.class)
                    .build(new TypeLiteral<Factory<Type1>>(){}));                     
            install(new FactoryModuleBuilder()
                    .implement(new TypeLiteral<AbstractToCreate<Type2>>(){}, ToCreate2.class)
                    .build(new TypeLiteral<Factory<Type2>>(){}));

            MapBinder<String, Factory> mapBinder = MapBinder.newMapBinder(binder(), String.class, Factory.class);
            mapBinder.addBinding("type1").to(new TypeLiteral<Factory<Type1>>(){});
            mapBinder.addBinding("type2").to(new TypeLiteral<Factory<Type2>>(){});
        }

所以,我注入它@Inject public Map<String, Factory> map;一切都好:

    Factory<Type1> factory1 = main.map.get("type1");
    Factory<Type2> factory2 = main.map.get("type2");

    AbstractToCreate<Type1> create1 = factory1.create(1);//create1 is ToCreate1 instance
    AbstractToCreate<Type2> create2 = factory2.create(2);//create2 is ToCreate2 instance

正如我之前提到的,我的生产系统中有更多的类型,因此 AbstractModule 变得太麻烦了。 我试图避免重复的代码并修改了 configure 方法:

    @Override
    protected void configure() {
        this.<Type1>inst(ToCreate1.class);
        this.<Type2>inst(ToCreate2.class);
    }

    private <V extends Type> void inst(Class<? extends AbstractToCreate<V>> clazz) {
        install(new FactoryModuleBuilder()
                .implement(new TypeLiteral<AbstractToCreate<V>>(){}, clazz)
                .build(new TypeLiteral<Factory<V>>(){}));
    }

但这不起作用!吉斯 说:

1) ru.test.genericassistedinject.AbstractToCreate<V> cannot be used as a key; It is not fully specified. 

怎么了?


这里的问题是类型擦除。特别是,这段代码:

private <V extends Type> void inst(Class<? extends AbstractToCreate<V>> clazz) {
    install(new FactoryModuleBuilder()
            .implement(new TypeLiteral<AbstractToCreate<V>>(){}, clazz)
            .build(new TypeLiteral<Factory<V>>(){}));
}

无法工作,因为它依赖于类型参数V帮助做出运行时决策(使用什么绑定),但类型参数V没有运行时表示,因此它的值永远不会直接影响运行时。另一种思考方式是:Java 无法“读取”泛型中类型参数的值;new TypeLiteral<Factory<V>>(){}无论什么,值始终相同V在调用者中实例化。

当您遇到与擦除相关的问题时,通常会遇到这种情况,技巧是添加一个表示您想要的类型的运行时值。在这种情况下,这尤其棘手,因为您想要做的是将类型参数的值表示为更大的类型。

有几种方法可以获取表示静态类型的运行时值。TypeToken是一并且Class是另一个,但它们都不允许您用参数表示类型,然后以编程方式填充该值。幸运的是,Google Guava 包含另一种表示形式,com.google.common.reflect.TypeToken,这对我们有用。TypeTokens 可以表示带有变量的类型,并支持以编程方式用具体表示形式“填充”该变量,例如:

new TypeToken<List<V>>() {}.where(new TypeParameter<V>() {}, Integer.class)

代表类型List<Integer>在运行时。

Using TypeToken我们可以构建我们的类型,如下所示:

 private <V extends Type> void inst(Class<? extends AbstractToCreate<V>> clazz, Class<V> binding) {
    TypeToken<AbstractToCreate<V>> implementationType = new TypeToken<AbstractToCreate<V>>() {}
        .where(new TypeParameter<V>() {}, binding);
    TypeToken<Factory<V>> factoryType = new TypeToken<Factory<V>>() {}
        .where(new TypeParameter<V>() {}, binding);

    @SuppressWarnings("unchecked")  // The type returned by TypeToken::getType is always the type it represents
    Key<AbstractToCreate<V>> key = (Key<AbstractToCreate<V>>) Key.get(implementationType.getType());
    @SuppressWarnings("unchecked")  // as above
    Key<Factory<V>> factoryKey = (Key<Factory<V>>) Key.get(factoryType.getType());

    install(
        new FactoryModuleBuilder()
            .implement(key, clazz)
            .build(factoryKey));
  }

现在我们可以调用inst with:

inst(ToCreate1.class, Type1.class);
inst(ToCreate2.class, Type2.class);

一切都会按预期进行。

不过,这是非常奇特的东西,理解它取决于对类型的编译时和运行时表示之间的差异有很好的理解。如果是我,如果你只希望使用一两次,我就不会这样做,因为混淆负担相当高;只有当这是图书馆或其他东西的一部分并且您可以为每个调用者节省一些工作时,我才会这样做。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

guice 辅助注入 + 多重绑定 + 仿制药 的相关文章

  • Selenium webdriver :列表不是通用的;它不能使用参数 `` 类型进行参数化

    我试图将链接存储在列表中 请按照以下代码操作 public class frameswitch public static void main String args System setProperty webdriver gecko d
  • 无法从 TemporalAccessor 获取 OffsetDateTime

    当我这样做时 String datum 20130419233512 DateTimeFormatter formatter DateTimeFormatter ofPattern yyyyMMddHHmmss withZone ZoneI
  • 无法解析配置“:app:debugRuntimeClasspath”的所有文件。问题

    我的 android studio 遇到了下一个问题 导致 org gradle api internal artifacts ivyservice DefaultLenientConfiguration ArtifactResolveEx
  • 如何使用 Spring Security 跨多个基于 JVM 的应用程序实现单点登录

    我目前正在尝试跨多个基于 JVM Grails Servlet 的 Web 应用程序实现单点登录解决方案 这些应用程序目前都部署在同一个 servlet 容器 当前是 Tomcat 但不想将我的解决方案仅限于 Tomcat 中 所有 Web
  • Java 中的本机方法

    我花了一些时间学习什么是 Java Native 方法以及它们是在平台相关代码 主要是 C 中实现的 但是我在哪里可以找到这些 Java 的本机实现呢 例如 Thread 类的 sleep long millis 方法是本机的 但它的实现代
  • 文件保存在文件系统中 VS 保存在数据库中

    我正在设计一个 servlet 或 Struts2 中的操作 用于文件 图像 文档等 下载 但我想知道哪种更好的方法可以将文件保留在文件系统和数据库中 只需保留文件的路径或将文件保留在数据库中 如 BLOB 我知道当我查询数据库时 哪里的
  • 在 JSP 中对表单操作使用相对路径

    如何在表单操作中使用相对路径
  • Keycloak 社交登录 REST API

    我已经为我的 keycloak 实例启用了谷歌社交登录 但我需要将其用作休息服务 是否有可用于执行此操作的端点 Keycloak 中没有 Google 身份验证 API 但您可以使用以下方法解决它代币交换 https www keycloa
  • 如何连接hibernate和DB2

    我正在运行一个使用 struts 和 hibernate 的应用程序 我目前正在使用 Derby 数据库 现在我必须转向 DB2 数据库 请告诉我 我必须做什么配置 休眠配置文件 我必须设置任何类路径吗 多变的 我知道 DB2 有两个 ja
  • 在 javafx 中注册鼠标处理程序,但处理程序不是内联的

    我有一个 JavaFX 应用程序变得有点大 我想保持代码的可读性 我有一个折线图 我希望内置缩放功能 该功能在单击鼠标时发生 我知道我需要向图表注册鼠标侦听器 我无法从 Oracle 示例中弄清楚什么 即如下所示 http docs ora
  • 在 JSON 对象中强制执行非空字段

    我们的 REST API 接收一些 JSON 对象输入 其中某些字段要求不为空 这些可以是字符串 整数 甚至可以是其他一些类实例作为参考 我们正在尝试找到一种方法来强制这些字段不为空 而不是在 API 中进行空检查的正确方法 当前的 if
  • 如何将 currentTimeMillis 转换为可读的日期格式? [复制]

    这个问题在这里已经有答案了 我想用currentTimeMillis两次 这样我就可以计算持续时间 但我也想以用户可读的格式显示时间和日期 我遇到了麻烦currentTimeMillis有利于计算 但我看不到内置函数可以转换为合适的时间或时
  • 如何使用 UUID 生成唯一的正 Long

    我需要为我的数据库主键列生成唯一的长 ID 我以为我可以用UUID randomUUID getMostSignificantBits 但有时它也会产生一些负多头 这对我来说是个问题 是否可以从 UUID 中仅生成正长 将会有数十亿个条目
  • 如何减少 JSF 中的 javax.faces.ViewState

    减少 JSF 中视图状态隐藏字段大小的最佳方法是什么 我注意到我的视图状态约为 40k 这会在每次请求和响应时下降到客户端并返回到服务器 特别是到达服务器时 这对用户来说会显着减慢 我的环境 JSF 1 2 MyFaces Tomcat T
  • 在 Java 中打开现有文件并关闭它。

    是否可以在java中打开一个文件附加数据并关闭多次 例如 psuedocode class variable declaration FileWriter writer1 new FileWriter filename fn1 writer
  • 有时 Properties.load() 会跳过行

    在以下情况下 Properties load 会跳过 InputStream 的第二行 这是 Java 的错误还是正常行为 public class PropTest public static void main String args
  • Android应用程序中的模式输入

    我想知道是否有其他替代方案可以替代 Android 上平庸的 EditText 密码输入 是否有 API 或开源代码可以集成到我的应用程序中 类似于锁屏图案解锁 Intent 可能会返回哈希值 数字 字符串或代表用户输入的模式的任何内容 我
  • 如何确保超类的子类方法的线程安全?

    我参加了一次面试 并被要求为以下要求设计一个课程 假设我有一个 A 类 它可以有任意数量的子类 即子类 类 A 有一个名为 doSomething 的方法 该方法是同步的 要求是 A 的所有子类都是强制性的重写 doSomething me
  • 如果所有类不在同一个包中,Spring @autowired 不起作用

    我有四个包裹 com spring org Files HomeController java com spring org dao Files SubscriberDao java SubscriberDaoImpl java com s
  • RecyclerView 适配器的 Kotlin 泛型

    我正在尝试编写一个通用的 recyclerview 适配器 我找到了几个例子 然而 仍然无法弄清楚如何实现通用适配器 我写的代码是 open abstract class BaseAdapter

随机推荐

  • 更新未屏蔽的 numpy 数组

    我的问题是双重的 首先 假设我有两个 numpy 数组 它们被部分屏蔽 array old 10 11 12 14 17 array update 5 9 15 8 13 19 16 如何创建一个新数组 其中所有非屏蔽值都被更新或修改 例如
  • Python easygui 无法选择文件

    这是我的代码 import easygui f easygui fileopenbox print f 看起来很简单 但是当我运行它时 我无法选择任何文件 请参见链接中的图 抱歉 如果这很愚蠢 但我已经无计可施了 https i stack
  • 安装国际 PHP 扩展 OSX High Sierra

    如何在 PHP 7 1 7 中安装 intl PHP 扩展 随 osx high Sierra 一起提供 所以我有完全相同的问题 正如其他人在这里评论所指出的 High Sierra 附带安装了 PHP 7 1 并且该 PHP 版本已对其进
  • Flutter TextField 输入验证日期

    我正在尝试编写一个日期输入控件 它接受像 23 12 1997 这样的日期 我希望它做的是自动为用户插入 字符 因此 当他们输入 23 时 监听器返回 23 以便他们可以输入 12 此时 监听器再次添加 让用户通过输入 1997 来完成日期
  • 如何将node.js连接到mysql和wamp/xampp服务器?

    我是一名 PHP 程序员 目前从事 WP CI OC 工作 我是node js的绝对初学者 想知道如何一步步连接MySql和WAMP XAMPP 如果我要直播 那么直播服务器的设置是什么 请让我知道一步一步的方法 按照本教程进行操作 教程在
  • 如何使用计时器移动顶点着色器中的点

    我无法弄清楚如何使用顶点着色器通过计时器为我的对象设置动画 我在窗口中的随机位置有一堆点 我想要做的是将这些点移动到窗口的中心 即 0 0 0 0 然后在某个点到达窗口中心后停止在那里 这是我的顶点着色器代码 layout location
  • 使用 PhoneGap / Cordova 的 Web 应用程序的状态栏通知

    我正在使用最新版本的 PhoneGap 开发适用于 iOS 和 Android 的 Web 应用程序 我想在手机状态栏上向用户发送通知 但我不知道该怎么做 似乎曾经存在过一个 Cordova 插件 StatusBarNotification
  • 使用 Hibernate 验证日期

    我们有现有的酒店管理系统 我被要求在系统的 创建住宿 功能中添加日期验证 该对话框如下所示 结束日期 已经过验证 如下面的代码所示 这 FutureHibernate 中的注释确保日期是将来的日期 NotNull Future DateTi
  • 从调用 forEach() 数组方法的方法返回。 JavaScript

    我正在使用从 JavaScript 中的数组调用的 forEach 方法 当我写作时return 在为数组中的每个元素调用的方法内部的某处 我从为特定元素调用的方法中返回 仅此而已 但我真正想要的是从数组调用 forEach 的方法中返回
  • 如何让 Rust 的 openssl crate 解密来自对称加密 gem 的数据,而不会出现 Node Crypto 自动删除的乱码?

    我正在使用 Rust 中的对称加密 gem 解密 Ruby on Rails 应用程序创建的遗留数据 请参阅我之前的问题如何用另一种语言解密由 Ruby 的 对称加密 gem 加密的数据 https stackoverflow com qu
  • 什么时候应该使用 Throwable 而不是 new Exception?

    Given Throwable is Exception的超类 当我阅读有关编写自己的 例外 的文章时 我看到了以下示例Throwable被用在catch块和其他文本显示new Exception 被用在catch堵塞 我还没有看到什么时候
  • 在Java中实现去抖动

    对于我正在编写的一些代码 我可以使用一个很好的通用实现debounce在爪哇 public interface Callback public void call Object arg class Debouncer implements
  • 获取 pandas 列左侧最接近的值

    我有4个国家的每日气温如下 Day GB US AU CA 1 33 2 32 3 23 4 34 5 23 34 6 45 34 7 34 23 8 34 33 9 34 45 44 12 10 23 23 23 23 11 34 23
  • PhoneGap Android 入门“缺少以下一项”

    我目前正在关注本教程 http docs phonegap com en 2 2 0 guide getting started android index md html Getting 20Started 20with 20Androi
  • 自定义配置部分

    我目前正在尝试在我忙碌的项目中实现自定义配置部分 无论我尝试什么 我都会收到以下错误 为 pageAppearanceGroup pageAppearance 创建配置节处理程序时发生错误 无法从程序集 System Configurati
  • Wix 自定义操作仅在安装期间执行,但不在升级和删除时执行?

    我有一个自定义操作 该操作只能在安装期间执行 而不能在次要版本升级和删除期间执行 我尝试了不同的条件 但 CA 正在次要版本期间执行 1 未安装 或不 删除 全部 并升级产品代码 2 未安装 3 未安装 或未 已安装并删除 全部 并升级产品
  • javascript 中的函数调用排序 - 回调是唯一的方法吗?

    我读过各种线索 比如this one https stackoverflow com questions 1859185 how to force sequential javascript execution例如 但我真的不知道如何完成以
  • 如何在重置表单时运行 JavaScript 代码?

    我知道我们可以将处理程序附加到表单onsubmit 但是我们如何向表单重置事件添加处理程序 通常当点击
  • #1030 - 从存储引擎 Aria 收到错误 176“读取校验和错误的页面”

    创建了新数据库 但由于此错误而无法创建新用户帐户 有谁知道如何解决这一问题 我找不到任何解决方案来解决这个问题 1030 从存储引擎 Aria 收到错误 176 读取校验和错误的页面 就我而言 上述解决方案不起作用 但解决方案类似于建议的
  • guice 辅助注入 + 多重绑定 + 仿制药

    我试图结合 Guice 的这 3 个功能 注入 多重绑定 泛型 我创建了一个生产项目的原型 所以这里是 首先 这是泛型的一个小层次结构 在生产情况下有 N 个实体的层次结构 public interface Type public clas