简体   繁体   English

将通用服务与其实现和子类型绑定

[英]Binding generic service with its implementation and subtypes

Disclaimer: Bear with me for a good amount of code to explain the scenario.免责声明:请耐心等待我提供大量代码来解释该场景。

In one of the maven modules (core), we have the following classes:在其中一个 maven 模块(核心)中,我们有以下类:

abstract class ReportingEvent {
}

abstract class Element {

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

}

services such as:服务,例如:

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);
    }
}

Further in another maven module(consumer) that we deploy, we have classes related to and implementing the above as:此外,在我们部署的另一个 maven 模块(消费者)中,我们有与上述相关并实现上述内容的类:

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);
    }
}

The above code works fine.上面的代码工作正常。 But the problem is the use of types that don't quite relate to the modules.但问题是使用了与模块不太相关的类型。

A... So if I change the binding in the consumer module to A...所以如果我将消费者模块中的绑定更改为

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

with

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

I get an error我收到一个错误

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

which is relevant and I cannot make use of Reporting<BaseReporting> in the core module anyway.这是相关的,无论如何我都无法在核心模块中使用Reporting<BaseReporting>

B... On the other hand if I try to inject Reporting as: B...另一方面,如果我尝试将Reporting注入为:

@Inject
Reporting<? extends ReportingEvent> reporting;

then IDEA states然后 IDEA 声明

 Required type: capture of ? Provided: ReportingEvent

on the line在线上

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

Is there a way to get around this situation while trying to solve for 1 and 2 as mentioned in the code sections?在尝试解决代码部分中提到的12 时,有没有办法解决这种情况?

(I might be restating what you already know for the most part) (我可能会在很大程度上重申您已经知道的内容)

Keeping aside your Guice related modules and configuration, your problem can be written down as撇开与 Guice 相关的模块和配置,您的问题可以写成

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

which is identical to这与

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

Say, you have a HotReporting class that extends BaseReporting , thus you have something like this说,你有一个扩展BaseReportingHotReporting类,因此你有这样的东西

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){}
}

Assume if you injected a HotReportingImpl for the field Reporting<? extends ReportingEvent> reporting假设您HotReportingImpl为字段Reporting<? extends ReportingEvent> reporting注入了一个HotReportingImpl Reporting<? extends ReportingEvent> reporting Reporting<? extends ReportingEvent> reporting . Reporting<? extends ReportingEvent> reporting

In your code what if m.getEntity().getReportEvent() returns a ColdReporting ?在您的代码中,如果m.getEntity().getReportEvent()返回ColdReporting怎样? It is not compatible with what the report method expects here (a HotReporting ).它与这里的report方法所期望的不兼容(一个HotReporting )。


Option 1:选项1:

I would try to get rid of the generic type parameters and define Reporting as我会尝试摆脱泛型类型参数并将Reporting定义为

public interface Reporting {
    void report(ReportingEvent event);
}

public class BaseReportingImpl implements Reporting {
    @Override
    public void report(ReportingEvent event) {

    }
}
//... and so on

Problems:问题:

  • If you relied on the exact subtype of a ReportingEvent in the implementation (need typecasts which is not good).如果您在实现中依赖ReportingEvent的确切子类型(需要不好的类型转换)。
  • Still, a HotReportingImpl can get a ColdReporting object as an argument.尽管如此, HotReportingImpl可以获取ColdReporting对象作为参数。

Option 2:选项 2:

You can make the InternalService generic by adding the type parameters to it.您可以通过向其添加类型参数来使InternalService泛型


If the classes implementing Reporting have to deal with concrete types of ReportingEvent , then it doesn't seem right for Element to return the base type ( ReportingEvent ).如果实现类Reporting必须处理的具体类型ReportingEvent ,那么它看起来不正确的Element返回基本类型( ReportingEvent )。

Have a look at Typesafe heterogeneous containers by Joshua Bloch .看看Joshua Bloch 的 Typesafe 异构容器 Your problem overlaps with that.你的问题与此重叠。 You can maintain a mapping from the type of ReportingEvent to the corresponding subclass of Reporting with that type argument.您可以使用该类型参数维护从ReportingEvent的类型到相应的Reporting子类的映射。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM