1

I want to stream events multiple events, all inherited from the same base type, from a mongoDB, using the spring ReactiveMongoRepository. Next I want to have them all differently handled and thus defined several overloads of a handle method, all for one child. However, the compiler complains, he can't find a proper method.

The problem is exemplarily shown in this test method:

@Test
public void polymorphismTest() {
    this.createFlux()
            .map(this::polymorphicMethod)
            .subscribe();
}

private Flux<A> createFlux() {
    A1 a1 = new A1();
    a1.string1 = "foo";
    A2 a2 = new A2();
    a2.string2 = "bar";
    return Flux.just(a1, a2);
}

private void polymorphicMethod(A1 a1) {
    System.out.println(a1.string1);
}

private void polymorphicMethod(A2 a2) {
    System.out.println(a2.string2);
}

I somehow understand the issue, since the compiler can't know I have a proper method for all inherited classes. However, it would be nice to have a solution similar to my approach, since it is (in my eyes) clean and readable.

I know, a solution would be to define the handle as an abstract method in the base type and implement it in the inherited classes, but this would break the functional approach of the rest of the application, plus events in a database should be POJOs.

I also would love to avoid the typical command pattern approach with one huge mapping of types to functions, but if there is no other idea this might be the solution.

PeMa
  • 1,559
  • 18
  • 44
  • I don't think there is any magical solution based on polymorphism alone, especially if you want to process the elements in the same original sequence. Command pattern it is! – Simon Baslé Jan 31 '19 at 10:16

1 Answers1

2

You can utilize Spring to provide types to help Reactor sort appropriate "events" into appropriate "event handlers".

For example, you can define the following:

public interface EventListener<E extends EventType> {
    default Class<E> getType() {
        return (Class<E>) GenericTypeResolver.resolveTypeArgument(getClass(), EventListener.class);
    }

    Mono<Void> execute(E event);
}

You can now do this:

EventListener<E> listener = ...
sourceFlux.ofType(listener.getType()).flatMap(listener::execute)

With Spring you can define multiple EventListener instances (either by creating classes inheriting it and using @Component or defining an @Configuration with many @Bean instances of that interface) which you can collect by @Autowire or @Bean to "register" for these events.

This avoids needing to define huge maps and has about as much code as if you were trying to handle each event type anyway.

danthonywalker
  • 368
  • 3
  • 14
  • First thanks for your answer. I am not sure if I finally got it, but it seems the `ofType()` function is filtering the `Flux` by type ``. This is not what I need. I have several events with the same parent that need to be processed sequentially. – PeMa Jan 30 '19 at 17:29