java - CDI:观察特定类型实体的选择/取消选择(数据表层次结构)

标签 java events dependency-injection cdi observer-pattern

我在页面上显示了数据表的层次结构。

顶部有一个可以选择的 CashValueCalculation 实体列表。如果您选择其中一个,则其下方会显示另一个可选 Paymentstream 实体的数据表。然后第三次,如果您选择这种实体,则会显示 Payment 实体的最后一个数据表。

为此有 3 个 CDI bean:CashValueCalculationManagerPaymentStreamManagerPaymentManager,形成层次结构:

`CashValueCalculationManager`
    |
    +- `PaymentstreamManager`
        |
        +- `PaymentstreamManager`

这些 bean 应该在选择/取消选择事件时对其 bean 作出 react (UI 实际上是通过 PrimeFaces p:dataTable 使用 JSF 完成的)。

每个 bean 都继承自具有实体 PK 的框架类,并且实体类本身是通用的。这是一些相关代码:

public abstract class BaseManager<K, T extends Entity<K>> extends BaseCdiViewBean implements Manager<K, T>
{
    private static final long serialVersionUID = 1L;

    private List<T> entities;

    private T selectedEntity;
    private EMode mode; // VIEW, ADD, EDIT, REMOVE

    // CDI event producers

    @Inject
    @SingleSelect
    private Event<T> selectEvent;

    @Inject
    @SingleUnselect
    private Event<T> unselectEvent;

    ...

    @Override
    public void setSelectedEntity(T selectedEntity)
    {
        if (selectedEntity == null)
        {
            // null entity not really selectable, interpret as clear selection command
            this.setSelectedEntity(null);

            // fire CDI event to 0-n observers
            this.unselectEvent.fire(this.newEntity()); // cannot pass null to CDI events, use a new entity created from a concrete bean
            return;
        }

        // here we have a non-null selected entity
        this.selectedEntity = selectedEntity;

        // fire CDI event to 0-n observers
        this.selectEvent.fire(selectedEntity);
    }

    ...
}

Entity 接口(interface)只是:

public interface Entity<K>
{
    public K getPk();
    public void setPk(K pk);
}

两个子管理器 PaymentStreamManagerPaymentManager 继承自 BaseSubManager 并充当其父管理器 CashValueCalculationManager 的观察者和 PaymentStreamManager 分别(这就是他们应该做的):

public abstract class BaseSubManager<K, T extends Entity<K>, P extends Entity<?>> extends BaseManager<K, T> implements SubManager<K, T, P>
{
    private static final long serialVersionUID = 1L;

    private P parentEntity;

    @Override
    public P getParentEntity()
    {
        return this.parentEntity;
    }

    @Override
    public void setParentEntity(P parentEntity)
    {
        this.parentEntity = parentEntity;
    }

    public void onSelect(@Observes @SingleSelect P selectedParentEntity)
    {
        System.out.println(this.getClass().getSimpleName() + ": selected parent entity: " + selectedParentEntity);
        this.setParentEntity(selectedParentEntity);
    }   

    public void onUnselect(@Observes @SingleUnselect P unselectedParentEntity)
    {
        System.out.println(this.getClass().getSimpleName() + ": unselected parent entity: " + unselectedParentEntity);
        this.setParentEntity(null);
    }
}

@SingleSelect 注释:

@Qualifier
@Retention(RUNTIME)
@Target({FIELD, PARAMETER})
public @interface SingleSelect
{
    // no additional interface
}

@SingleUnselect注释:

@Qualifier
@Retention(RUNTIME)
@Target({FIELD, PARAMETER})
public @interface SingleUnselect
{
    // no additional interface
}

我现在想要的是 PaymentstreamManager 接收来自 CashValueCalculationManager 的事件,并且 PaymentManager 接收来自 PaymentstreamManager 的事件

但是,每次我选择顶级管理器 CashValueCalculationManager 的实体时,两个子管理器的 @Observer 方法都会接收事件(当然还有方法调用,这不是我需要的):

在选择测试时:

21:17:34,310 INFO  [stdout] PaymentManager: selected parent entity: CashValueCalculation[pk=2]
21:17:34,312 INFO  [stdout] PaymentStreamManager: selected parent entity: CashValueCalculation[pk=2]

取消选择测试时:

21:19:20,176 INFO  [stdout] PaymentStreamManager: unselected parent entity: CashValueCalculation[pk=null]
21:19:20,177 INFO  [stdout] PaymentManager: unselected parent entity: CashValueCalculation[pk=null]

:

为什么这不能立即起作用?我需要在代码中更改哪些内容才能使其正常工作?

谢谢

最佳答案

有根据的猜测:

由于泛型是通过类型删除实现的,因此运行时在 BaseManager 中基本上会发生以下事件:

@Inject
@SingleSelect
private Event<Object> selectEvent;

@Inject
@SingleUnselect
private Event<Object> unselectEvent;

另一方面,您观察到以下情况:

public void onSelect(@Observes @SingleSelect Object selectedParentEntity)
public void onUnselect(@Observes @SingleUnselect Object unselectedParentEntity)

...这显然与每个事件匹配。

我尝试的是,向限定符注释添加一个类值,例如:

@Qualifier
@Retention(RUNTIME)
@Target({FIELD, PARAMETER})
public @interface SingleSelect
{
    public Class<?> value();
}

@Inject
@SingleSelect(SomeConcreteType.class)
private Event<Object> selectEvent;

public void onSelect(@Observes @SingleSelect(SomeConcreteType.class) P selectedParentEntity)

这样,您的容器应该能够在运行时区分各种事件。

关于java - CDI:观察特定类型实体的选择/取消选择(数据表层次结构),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44912981/

相关文章:

java - 添加到大型 Java 集合,性能瓶颈

java - Jetty:设置通用主机

node.js - 获取错误 event.js :174 throw er; everytime I save any scss file

c# - 无法从未打开的数据库创建命令

java - ArangoDB Spring Data 2,java.lang.Object/无效的映射类型

android - 检测屏幕截图 Android

Mysql - 仅运行一个从计划事件内部调用的存储过程实例

Scala:使用依赖注入(inject)协调类型类

java - Dagger 没有按预期覆盖模块

java - 如何使用 Java 在 selenium WebDriver 中按 CTRL+T 和 CTRL+TAB?