Reputation: 3496
I am using Reactor 2 and Spring 4. Here's the typical code that I have - a Consumer
working with a repository
@Consumer
public class ApplicationService {
@Selector(value="/applications/id", type = SelectorType.URI)
@ReplyTo
public Application byApplicationId(String id) throws ApplicationNotFoundException {
Application app = appRepo.findOne(id);
if(app == null)
throw new ApplicationNotFoundException("Application `" + id + "` could not be found.");
return app;
}
}
Then I have a controller that passes the request to an eventBus
into which I pass requests and return a Promise
@RestController
@RequestMapping("/applications")
public class ApplicationsController {
@RequestMapping(value = "/{id}", method = GET, produces = APPLICATION_JSON_VALUE)
public Promise<Event<Application>> byApplicationId(@PathVariable final String id) {
final Promise<Event<Application>> p = Promises.prepare(env);
eventBus.sendAndReceive("/applications/id", Event.wrap(id), p);
return p;
}
}
Things work but in case of ApplicationService
throwing an exception Promise
s value is not set but I do get following in the console:
16:46:58.003 [main] ERROR reactor.bus.EventBus - null
java.lang.reflect.UndeclaredThrowableException
at org.springframework.util.ReflectionUtils.rethrowRuntimeException(ReflectionUtils.java:302)
...
Caused by: com.metlife.harmony.exceptions.ApplicationNotFoundException: Application `2860c555-0bc4-45e6-95ea-f724ae3f4464` could not be found.
at com.metlife.harmony.services.ApplicationService.byApplicationId(ApplicationService.java:46) ~[classes/:?]
...
Caused by: reactor.core.support.Exceptions$ValueCause: Exception while signaling value: reactor.bus.Event.class : Event{id=null, headers={}, replyTo=reactor.bus.selector.Selectors$AnonymousKey@4, key=/applications/id, data=2860c555-0bc4-45e6-95ea-f724ae3f4464}
Questions are:
do I use Reactor and eventBus
in the wrong way ? and if so, what is the right way
perhaps this functionality is not implemented yet
Upvotes: 9
Views: 9945
Reputation: 12728
A dedicated chapter for handling exception and errors in the Reactive reference is here to read:
https://projectreactor.io/docs/core/release/reference/#error.handling
In any case, reactive pipeline is "contiguous" in its neutral meaning. Hardly you could prevent it from being noticed by the consumer of your methods.
Upvotes: 1
Reputation: 3496
I guess I re-evaluated the strategy of using Reactor in my Spring application.
Now my controller looks like
@RestController
public class GreetingController {
@Autowired
private GreetingService greetingService;
@RequestMapping("/greeting")
public Promise<ResponseEntity<?>> greeting(final @RequestParam(value = "name", defaultValue = "World") String name) {
return greetingService.provideGreetingFor(name).map(new Function<Greeting, ResponseEntity<?>>() {
@Override
public ResponseEntity<?> apply(Greeting t) {
return new ResponseEntity<>(t, HttpStatus.OK);
}
}).onErrorReturn(WrongNameException.class, new Function<WrongNameException, ResponseEntity<?>>() {
@Override
public ResponseEntity<?> apply(WrongNameException t) {
return new ResponseEntity<>(t.getMessage(), HttpStatus.BAD_REQUEST);
}
}).next();
}
}
And the service looks like
@Service
public class GreetingService {
@Autowired
private Environment env;
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
public Stream<Greeting> provideGreetingFor(String name) {
return Streams.just(name).dispatchOn(env).map(new Function<String, Greeting>() {
@Override
public Greeting apply(String t) {
if (t == null || t.matches(".*\\d+.*"))
throw new WrongNameException();
return new Greeting(counter.incrementAndGet(), String.format(template, t));
}
});
}
}
What's bad is that now I have to use Stream<T>
as a result of the method in the service (which is supposedly a business logic), so anyone using the service is now aware of the Stream
-ish nature of the service and as a result Stream
bleeds into other parts of the code, e.g. now I may have to use await()
in the code using the service.
Full application is available at https://github.com/evgeniysharapov/spring-reactor-demo
Upvotes: 4