【问题标题】:Can you fire CDI 2.0 events of type AbstractClass<? extends Something>?你能触发 Abstract Class< 类型的 CDI 2.0 事件吗?扩展某事>?
【发布时间】:2023-04-08 03:49:01
【问题描述】:

(作为背景,我读过 You think you know everything about CDI events… Think again!,所以我至少对 CDI 事件中的许多边缘情况非常熟悉。)

我使用 Weld 3.0.4.Final 作为 CDI 2.0 的实现。

我有一个 AbstractFoo&lt;? extends T&gt; 实例,我想将它作为 CDI 事件触发。我们称之为payload。这就是我对有效载荷的全部了解。

T 定义为T extends MetaDataMetaData 是一个接口。

由于各种不重要的原因,我必须以编程方式触发有效负载,所以我这样做:

final Event<Object> cdiEventMachinery = beanManager.getEvent();
assert cdiEventMachinery != null;
final TypeLiteral<AbstractFoo<? extends T>> eventTypeLiteral = new TypeLiteral<AbstractFoo<? extends T>>() {
  private static final long serialVersionUID = 1L;
};
final Event<AbstractFoo<? extends T>> broadcaster = 
cdiEventMachinery.select(eventTypeLiteral, someQualifiers);
assert broadcaster != null;

很明显,broadcaster 现在已设置为触发我的有效载荷。我的意图是这些事件应该被传递给寻找AbstractFoo-or-its-subclasses实例的观察者,这些实例由任何扩展MetaData的类型参数化。

但是当我做broadcaster.fire(payload)时,我注意到像这样的观察者方法:

private final void onFoo(@ObservesAsync @MatchingQualifier final Foo<? extends MetaDataSubclass> event) {}

...不要被调用。? extends MetaDataSubclass 似乎是罪魁祸首;如果观察到的参数只是简单的,比如说,Object,那么显然会通知该方法。)

具体来说,假设:

  • MatchingQualifier 文字存在于 someQualifiers 中,并且
  • MetaDataSubclass 是一个扩展 MetaData 的类,并且
  • Foo 是一个扩展 AbstractFoo 的类

...为什么不调用观察者方法?

需要明确的是,我确信这不是错误,而是我的理解中缺少的东西。我想知道我错过了什么。

(交叉发布到developer.jboss.org。)

测试用例

这是一个使用更简单结构的测试用例。

private final void collectionExtendsNumber(@Observes final Collection<? extends Number> payload) {
  System.out.println("*** collection extends Number");
}

private final void collectionExtendsInteger(@Observes final Collection<? extends Integer> payload) {
  System.out.println("*** collection extends Integer");
}

private final void collectionInteger(@Observes final Collection<Integer> payload) {
  System.out.println("*** collection Integer");
}

private final void collectionNumber(@Observes final Collection<Number> payload) {
  System.out.println("*** collection Number");
}

@Test
public void testContainerStartup() {

  final SeContainerInitializer initializer = SeContainerInitializer.newInstance();
  initializer.disableDiscovery();
  initializer.addBeanClasses(this.getClass());
  try (final SeContainer container = initializer.initialize()) {
    assertNotNull(container);
    final BeanManager beanManager = container.getBeanManager();
    assertNotNull(beanManager);
    final TypeLiteral<Collection<? extends Number>> literal = new TypeLiteral<Collection<? extends Number>>() {
      private static final long serialVersionUID = 1L;

    };
    final Event<Collection<? extends Number>> broadcaster = beanManager.getEvent().select(literal);
    assertNotNull(broadcaster);
    final Collection<? extends Number> payload = Collections.singleton(Integer.valueOf(1));
    broadcaster.fire(payload);
  }
}

仅调用第一个观察者方法。我想了解是什么阻止了第二个被调用。我知道 an-unknown-type-that-is-a-Number 不能分配给 an-unknown-type-that-is-a-Integer,但我想要一些方法来选择“正确" 有效载荷的观察者方法。

【问题讨论】:

    标签: java cdi cdi-2.0


    【解决方案1】:

    这是由10.3.1. Assignability of type variables, raw and parameterized types 在规范中定义的。更具体地说,查看您的测试用例,您会遇到以下规范语句:

    • 观察事件类型参数是与事件类型参数具有相同原始类型的实际类型,并且,如果类型被参数化,则事件类型参数可根据这些规则分配给观察事件类型参数,或李>

    事件类型参数 (? extends Number) 不能分配给观察到的事件类型参数(在您的测试用例中为? extends Integer)。您的第三个观察者 (Collection&lt;Integer&gt;) 的情况也是如此。

    Collection&lt;Number&gt; 的最后一个情况看起来有点令人费解,但它遵循相同的规则。您不能将&lt;? extends Number&gt; 分配给&lt;Number&gt;,因为在这种情况下,您可能实际上是在尝试分配Collection&lt;Integer&gt;Collection&lt;Double&gt;Collection&lt;Number&gt;&lt;? extends Number&gt; 可以是其中任何一个)。

    Oracle site 上有一个很好的泛型示例。它表明,给定两种类型,Box&lt;A&gt;Box&lt;B&gt;,您不能根据“内部”类型(AB)的关系来假设可分配性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-01
      • 2018-04-19
      • 2013-09-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多