How to set field value of CompletableFuture object with second ComputableFuture object - java

I have a method like:
public CompletableFuture<List<Employee>> handleFutures(CompletableFuture<Factory> factoryCompletableFuture, CompletableFuture<Task> taskCompletableFuture)
throws ExecutionException, InterruptedException {
//logic
}
I want to use CompletableFuture<Task> taskCompletableFuture to set the value of a field task in the CompletableFuture<Factory> factoryCompletableFuture object.
Task class looks like:
public enum Task {
MECHANIC,
ENGINEER
}
Employee class looks like:
public class Employee {
private Task task;
}
Factory class looks like:
public class Factory{
private Optional<List<Employee>> employees;
}
I have a stream like:
Task task = taskCompletableFuture.get();
List<Employee> collect = factoryCompletableFuture.get().getEmployees().stream()
.flatMap(Collection::stream)
.peek(empl -> empl.setTask(task))
.map(CompletableFuture::completedFuture)
.map(CompletableFuture::join)
.collect(toList());
which return List of Employee.
All I want to achieve is wrapping in a gentle way above stream with CompletableFuture to get a result as CompletableFuture<List<Employee>> and call a method logic like:
return factoryCompletableFuture.thenApply(do logic here which will set value and return CompletableFuture).
By the way, I know that Optional with a list is not a good practice but I cannot change this. Peek for setter usage is either not the best option but this maneuver doesn't need an additional object to repack the changed object with eventual forEach usage.
I will be grateful for a suggestion on how to reach a desirable goal.

You simply need to use thenCombine():
public CompletableFuture<List<Employee>> handleFutures(
CompletableFuture<Factory> factoryCompletableFuture,
CompletableFuture<Task> taskCompletableFuture) {
return factoryCompletableFuture.thenCombine(taskCompletableFuture,
(factory, task) -> factory.getEmployees().stream()
.flatMap(Collection::stream)
.peek(empl -> empl.setTask(task))
.collect(toList()));
}

Related

How to use return object of Mono without using block()?

I am trying to learn spring webflux. In ReactiveMongoRepository, I am trying to check if category already exists. If it already exists then return that object otherwise save and return new saved object. Something like following.
public Mono<Category> save(Category category) {
final Mono<Category> byId = repository.findById(category.getId());
final Category block = byId.block();
if (block == null) {
return repository.save(new Category(category.getName()));
} else {
return byId;
}
}
How can I do this without using block()?
Use Mono::switchIfEmpty that provides an alternative Mono in case the former one is completed without data. As long as ReactiveMongoRepository::save returns Mono, you can pass it to generate the alternative one.
return repository.findById(category.getId())
.switchIfEmpty(repository.save(new Category(category.getName())));
In case ReactiveMongoRepository::findById returns a Mono with data, the Mono::switchIfEmpty will not be called.
Edit: Using Mono::defer with a Supplier<Mono> makes the saving operation to be delayed when necessary:
.switchIfEmpty(Mono.defer(() -> repository.save(new Category(category.getName()))));
You can try something like this
public Mono<Category> getCategories(Category category) {
return repository.findByName(category.getName()).doOnNext(o -> {
}).switchIfEmpty(repository.save(category));
}
You need to defer the switchIfEmpty. Otherwise, it'll be triggered eagerly:
return repository.findById(category.getId())
.switchIfEmpty(Mono.defer(() ->respository.save(category)));

Chaining multiple methods fluently akin to a Stream without the verbosity of the Optional type

In a Spring application I tend to take the request body in a controller method and want to pipe it fluently through multiple method calls (returning different types along the way) such as in the following (simplified) example:
public ResponseEntity<FooDto> postFoo(#RequestBody final FooDto requestBody) {
return Optional.of(requestBody) // Optional<FooDto>
.map(mapper::fromDto) // Optional<FooEntity>
.map(service::insertEntity) // Optional<FooEntity>
.map(mapper::fromEntity) // Optional<FooDto>
.map(dto -> ResponseEntity.created(/* ... */).body(dto).build()) // Optional<ResponseEntity<FooDto>>
.orElseThrow(IllegalStateException::new);
}
As you can see I am tempted to apply some FP patterns but the Optional class isn't really suited to do so since the "optionality" implied is artificial and the underlying object of interest should never be empty in the first place. Therefore the final exception won't (hopefully) ever be thrown and alternatively just calling Optional::get isn't really a great option either since Sonarlint complains about an unchecked get call and rightfully so.
Is there any idiomatic way available, maybe even in conjunction with vavr or other FP libraries, to express such a chain of methods better than with such artifical Optional constructs? Otherwise I might have to refrain from doing so and revert back to a classic imperative approach with a dozen of variables.
EDIT: The way I attempt to use Optional easily gets out of hand if working with methods that return Either<ErrorReason, Optional<FooEntity>> which makes this an Optional<Either<ErrorReason, Optional<FooEntity>>> ending up not legible anymore.
The cleanest way to perform what you're looking for is to restore to the imperative style such as:
public ResponseEntity<FooDto> postFoo(final FooDto requestBody) {
final FooEntity fooEntity = fromDto(requestBody);
final FooEntity updatedEntity = insertEntity(fooEntity); // should be void?
final FooDto responseDto = fromEntity(updatedEntity);
return ResponseEntity.created(/* ... */)
.body(responseDto)
.build();
}
I agree with Naman that an imperative style is probably the cleanest way in this case.
If you really really want to do some Optional style like flow you can create your own class
public final class Value<T> {
private final T value;
// Private constructor to force usage of static construction
private Value(T value) {
this.value = value;
}
// Static constructor Optional style
public static <T> Value<T> of(T value) {
return new Value<>(value);
}
public <R> Value<R> map(Function<? super T, ? extends R> mapper) {
return new Value<>(mapper.apply(this.value));
}
// method to unwrap value
public T get() {
return value;
}
}
Then you would use it like
public ResponseEntity<FooDto> postFoo(#RequestBody final FooDto requestBody) {
return Value.of(requestBody) // Value<FooDto>
.map(mapper::fromDto) // Value<FooEntity>
.map(service::insertEntity) // Value<FooEntity>
.map(mapper::fromEntity) // Value<FooDto>
.map(dto -> ResponseEntity.created(/* ... */).body(dto).build()) // Value<ResponseEntity<FooDto>>
.get();
}
Again, I highly discourage this solution and I would just opt for using imperative style.

Get elements with a certain generic type in a list

I am currently working on a train project and I have following question:
I save all rolling stock in a list:
To understand my class hierarchy better, here is a simplified inheritance overview:
RollingStock
Engine
SteamEngine
DieselEngine
...
Coach
FreightCoach
PassengerCoach
...
TrainSet
In my register, I want to save all rolling stock in a list private List<RollingStock> rollingStock;. So far, I have created a list for each rolling stock type (engines, coaches, trainSets). However, I need to delete a certain rolling stock with just its ID and therefore it's easier to save everything in just one list.
As of before, I created an engine like this:
public void createEngine(Engine engine) {
this.engines.add(engine);
}
Now, with just one list I do it like this:
public void createEngine(Engine engine) {
this.rollingStocks.add(engine);
}
This works perfectly fine. For the returnEngines() method I don't seem to find a solution:
It was as easy as this with one list for each rolling stock type:
public List<Engine> returnEngines() {
return engines;
}
Now, I have to filter all engines out of the rolling stock list:
public List<Engine> returnEngines() {
...
return rollingStock.???;
}
I could add the method public String getType() and check for its type.
I can't imagine that there isn't a better solution.
How can this be done?
Stream the list, filter for instances of Engine; map the instances from RollingStock to Engine (with a cast), collect the results into a new List. Like,
public List<Engine> returnEngines() {
return rollingStocks.stream().filter(x -> x instanceof Engine)
.map(x -> (Engine) x).collect(Collectors.toList());
}
The answer from Elliott Frisch is perfectly valid, here is a generified solution, in case you need also a method to filter your register for any type of your hierarchy:
public <T> List<T> returnClazz(Class<T> clazz) {
return rollingStocks.stream()
.filter(clazz::isInstance)
.map(clazz::cast)
.collect(Collectors.toList());
}
Which then can be used by several helper methods, e.g.
public List<TrainSet> returnTrainset() {
return returnClazz(TrainSet.class);
}
public List<Engines> returnEngines() {
return returnClazz(Engine.class);
}
...
or can be called directly.

How to iterate over Mono<List<String>> calling Mono returning method

I'm attempting to achieve the following in the method below
Get All Cars from Dealer X
Create wrapper object that stores a set of all cars and another set of all manufactures 2a. Populate Cars set with the cars obtained in
Step 1
For each Car get all of their independent manufactures
Store all obtained manufactures into the wrapper objects manufactures Set
Return Mono of Car and manufactures
Mono<CarAndManufactures> requestCarAndManufactures(Request req) {
final String dealerId = buildDealerId(req.getDealerRegion(), req.getDealerId());
final CarAndManufactures CarAndManufactures = new CarAndManufactures();
return webSocketClient.getCars(dealerId) //note #getCars returns a Mono
.map(getCarsResponse -> getCarsResponse
.getResult()
.stream()
.map(Car::getId)
.collect(toSet()))
.map(carIds -> {
CarAndManufactures.setCars(carIds);
return CarAndManufactures;
})
.flatMapMany(CarAndManufactures1 -> Flux.fromIterable(CarAndManufactures.getCars().keySet()))
.collectList()
.log("Existing cars")
.flatMap(carIds -> { //This is the problem area
carIds
.stream()
.map(carId -> {
webSocketClient.getManufactures(carId) //Note getManufactures returns a Mono... This method does look like its ever called
.map(getManufactureResponse -> getManufactureResponse
.getResult()
.stream()
.map(Manufacture::getId)
.collect(toSet()))
.map(ManufactureIds -> {
CarAndManufactures.SetManufactures(ManufactureIds); //since the line commented on above is not called the Manufacture Set is empty
return CarAndManufactures;
});
return CarAndManufactures;
});
return just(CarAndManufactures);
}
)
.log("Car And Manufactures");
}
The Set of Manufactures is alway empty doesnt look like webSocketClient.getManufactures(carId) is ever called. Thought I might be missing a .subscribe some where but since this is being used by a webflux controller I think no #subscribes are needed anywhere
I know I'm too late, but maybe someone will find this question and see the answer, I hope that would be helpful.
The reason why webSocketClient.getManufactures(carId) is never called in your code is obvious: nobody subscribes to this publisher since you put this call to simple .map() operator of Stream API.
The entire reactive chain should be holistic, without any "breaks".
After getting ids of cars and putting them to .flatMap(), inside that .flatMap() you should have declared another Flux from those ids, and on that Flux you put another .flatMap() to request manufactures and finally collect them into resulting Set.
Also you should not have declared final CarAndManufactures CarAndManufactures = new CarAndManufactures(); implicilty and then tried to fill this object within the reactive chain. Doing that you're mixing imperative style code with reactive style code which is incorrect way to use reactive.
You should stay in your reactive chain all the way.
So, the way to achieve what yout what is the following: (I also made the code "better" and cleaner):
#Test
public void carsAndManufacturesTest() {
String dealerId = "test dealer";
client.getCars(dealerId) // request Mono<CarsResponse>
.map(CarsResponse::getResult) // getting List<Cars> from response
.map(cars -> // getting ids of cars and collect them to Set<String>
cars.stream()
.map(Car::getId)
.collect(Collectors.toSet())
)
.flatMap(carsIds -> // creating another publisher that will fetch manufactures and build the CarAndManufactures
this.fetchManufacturesIds(carsIds) // fetching Set<String> manufactures for all the carsIds
.map(manufacturesIds -> // we're done here! we have both carsIds and manufactureIds!
new CarAndManufactures( // creating desired object from both carsIds and their manufacturesIds
carsIds,
manufacturesIds)
)
)
.doOnNext(carAndManufactures -> log.info(carAndManufactures.toString()))
.subscribe();
}
/**
* Fetches all the manufactures ids of given cars ids
*
* #param carsIds ids of cars
* #return Mono with all the manufactures ids of given cars ids
*/
public Mono<Set<String>> fetchManufacturesIds(Set<String> carsIds) {
return Flux.fromIterable(carsIds) // creating flux of given cars ids
.flatMap(client::getManufactures) // request Mono<ManufactureResponse> for car id
.map(ManufactureResponse::getResult) // getting List<Manufacture>
.map(manufactures -> // getting ids of manufactures and collect them to Set
manufactures.stream()
.map(Manufacture::getId)
.collect(Collectors.toSet())
)
.collectList() // collecting all the sets of manufactures ids, here we get List<Set<String>>
.map(list -> // flatting all the sets to one set, eventually we get here Set<String>
list.stream()
.flatMap(Collection::stream)
.collect(Collectors.toSet())
);
}
For those who want to test this code I'll leave here the specs of classes. Then in the code above just create the client private Client client = new Client(); (as a field of class where you put those two merhods)
Classes:
/*
================== Classes examples for those who wants to test this code ===================
*/
#Slf4j
class Client {
public Mono<CarsResponse> getCars(String dealerId) {
log.info("Received request to fetch cars by dealer id: {}", dealerId);
List<Car> cars =
List.of(new Car("MUSTANG"),
new Car("FOCUS"),
new Car("FUSION")
);
return Mono.just(new CarsResponse(cars));
}
public Mono<ManufactureResponse> getManufactures(String carId) {
log.info("Received request to fetch manufactures by car id: {}", carId);
List<Manufacture> manufactures =
List.of(new Manufacture("MF BUFFALO"),
new Manufacture("MF CHANGAN"),
new Manufacture("MF CHICAGO"),
new Manufacture("MF DEARBORN")
);
return Mono.just(new ManufactureResponse(manufactures));
}
}
/*
================== Data classes ===================
*/
#Data
#AllArgsConstructor
class CarsResponse {
private List<Car> result;
}
#Data
#AllArgsConstructor
class ManufactureResponse {
List<Manufacture> result;
}
#Data
#AllArgsConstructor
class CarAndManufactures {
private Set<String> cars;
private Set<String> manufactures;
}
#Data
#AllArgsConstructor
class Car {
private String id;
}
#Data
#AllArgsConstructor
class Manufacture {
private String id;
}

How to avoid mutating the state of the object inside a stream?

I have code like people.stream.filter(Object::notNull).map(person -> person.updateAge(...))
I would like to avoid calling updateAge() and even remove that method and make me object immutable. How can I achieve that while keeping the stream structure of the code?
If you want to mutate objects then you are misusing map! it is forEach that is for side effects.
people.forEach(person -> person.updateAge(...))
But no I still like to be functional and use immutable objects. In that case you need to make updateAge takes a new age and return a new person object with that very new age.
Person updateAge(int incrementBy) {
... new Person(..., newAge);
}
And then get a stream of new people like this
people.stream.filter(Object::notNull).map(person -> person.updateAge(...))
I dont want to modify that object directly but rather create a new object will all same fields with age field changed. Is that possible
Yes it is possible. You can override method clone() from Object:
#Override
public Person clone() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
Don't forget to implement Cloneable:
public class Person implements Cloneable {
...
Assuming you have updateAge() method like this:
public Person updateAge(int age) {
this.setAge(age);
return this;
}
Then stream chain will looks like:
List<Person> newPeople = people.stream()
.map(Person::clone)
.map(person -> person.updateAge(...))
.collect(toList());

Categories

Resources