有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java绑定通用服务及其实现和子类型

免责声明:请接受我大量的代码来解释这个场景

在maven模块(核心)中,我们有以下几个类:

abstract class ReportingEvent {
}

abstract class Element {

    public <E extends ReportingEvent> Optional<E> getReportEvent() {
        return Optional.empty();
    }

}

服务,例如:

public interface Reporting<E extends ReportingEvent> {
    void report(E event);
}

interface InternalService {
}

public class InternalServiceImpl implements InternalService {

    @Inject
    Reporting<ReportingEvent> reporting; // 1. Possible to use a generic type? How?

    private void reportEvents(BatchRequest batchRequest) {
        batchRequest.stream()
                // section below is of importance
                .map(m -> m.getEntity().getReportEvent()) // the generic method from 'Element'
                .filter(Optional::isPresent)
                .map(Optional::get)
                .forEach(event -> reporting.report(event)); // method from 'Reporting'
    }
}

class CoreBindingModule extends AbstractModule {
    protected void configure() {
        bind(InternalService.class).to(InternalServiceImpl.class).in(Singleton.class);
    }
}

此外,在我们部署的另一个maven模块(consumer)中,我们有与上述功能相关并实现这些功能的类,如下所示:

abstract class BaseReporting extends ReportingEvent {
}

class ColdReporting extends BaseReporting {
}

abstract class Node extends Element {
}

class Cold extends Node {
    @Override
    public Optional<ColdReporting> getReportEvent() {
        return Optional.ofNullable(new ColdReporting()); // some business logic
    }
}

class ReportingImpl implements Reporting<ReportingEvent> { // 2. Use 'BaseReporting' here
    void report(ReportingEvent event){}
}

class ConsumerBindingModule extends AbstractModule {
    protected void configure() {
        bind(new TypeLiteral<Reporting<ReportingEvent>>() {}).to(ReportingImpl.class).in(Singleton.class);
    }
}

上面的代码运行良好。但问题是使用与模块不太相关的类型

A因此,如果我将使用者模块中的绑定更改为

bind(new TypeLiteral<Reporting<BaseReporting>>() {}).to(ReportingImpl.class).in(Singleton.class);

class ReportingImpl implements Reporting<BaseReporting> {
    void report(BaseReporting event){}
}

我犯了个错误

No implementation for Reporting<ReportEvent> was bound.
while locating Reporting<ReportEvent> for field at InternalServiceImpl.reporting(InternalServiceImpl.java:21)

这是相关的,我无论如何也不能在核心模块中使用Reporting<BaseReporting>

BReporting注入为:

@Inject
Reporting<? extends ReportingEvent> reporting;

然后想法陈述

 Required type: capture of ? 
 Provided: ReportingEvent

在线上

...forEach(event -> reporting.report(event))

在试图解决代码部分提到的12问题时,有没有办法避开这种情况


共 (1) 个答案

  1. # 1 楼答案

    (我可能在重复你大部分已经知道的内容)

    撇开与GUI相关的模块和配置不谈,您的问题可以写为

    Reporting<ReportingEvent> reportingEvent = new ReportingImpl();
    Reporting<? extends ReportingEvent> reporting = baseReporting;
    reporting.report(reportingEvent); //won't work
    

    这和

    List<? extends String> list = new ArrayList<>();
    list.add("a"); //won't work
    

    比如说,你有一个HotReporting类,它扩展了BaseReporting,所以你有这样的东西

    public class ReportingImpl implements Reporting<ReportingEvent> { 
        public void report(ReportingEvent event){}
    }
    public class ColdReportingImpl implements Reporting<ColdReporting> { 
        public void report(ColdReporting event){}
    }
    
    public class HotReportingImpl implements Reporting<HotReporting> { 
        public void report(HotReporting event){}
    }
    

    假设您为Reporting<? extends ReportingEvent> reporting字段注入了HotReportingImpl

    在代码中,如果m.getEntity().getReportEvent()返回一个ColdReporting怎么办?它与这里的report方法所期望的(a HotReporting)不兼容


    选项1:

    我会尝试去掉泛型类型参数,并将Reporting定义为

    public interface Reporting {
        void report(ReportingEvent event);
    }
    
    public class BaseReportingImpl implements Reporting {
        @Override
        public void report(ReportingEvent event) {
    
        }
    }
    //... and so on
    

    问题:

    • 如果在实现中依赖于ReportingEvent的确切子类型(需要类型转换,这不好)
    • 尽管如此,HotReportingImpl仍然可以获取ColdReporting对象作为参数

    选项2:

    通过向InternalService中添加类型参数,可以使其成为泛型的


    如果实现Reporting的类必须处理ReportingEvent的具体类型,那么Element返回基类型(ReportingEvent)似乎是不对的

    看看Typesafe heterogeneous containers by Joshua Bloch。你的问题与此重叠。可以使用该类型参数维护从ReportingEvent类型到Reporting相应子类的映射