WebFlux How to Chain Queries In Functional Non Blocking Way - spring-boot

I am new to functional paradigm, wondering how to go about doing some querying before creating a new object?
#Override
public Mono<Order> create(CreateOrderRequest specs) {
//itemRepository.findAll(specs.getItemCodes()) //returns Flux<Item>
final Order newOrder = new Order(items);
return orderRepository.insert(newOrder)
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.BAD_REQUEST, "Failed to create order")));
}
How do I chain the commented code in a non blocking way? The query returns Flux<Item> while Order constructor requires a List<Item>

You can use the collectList() method, which will change your Flux<Item> into a Mono<List<Item>>.
After that, you can use the map() method to convert your List<Item> into an Order object, and the flatMap() method to get the saved result.
For example:
return itemRepository
.findAll(specs.getItemCodes())
.collectList()
.map(Order::new)
.flatMap(orderRepository::insert)
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.BAD_REQUEST, "Failed to create order")));

Related

Can this method be tested using mockito?

I am not sure how to test the first method in the service layer with Mockito as it is using the helper method. Below is my failed attempt at a test: I get an InvalidUseOfMatchersException in the second when clause.
Thanks in advance!
#Mock
private EntityRepository EntityRepo;
#InjectMocks
private EntityService EntityService;
public List<DTO> getAllDTOs(){
//first method
return entityRepo.findAll()
.stream()
.map(this::convertEntityToDTO)
.collect(Collectors.toList());
}
//helper method
public DTO convertEntityToDTO(Entity entity) {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration()
.setMatchingStrategy(MatchingStrategies.LOOSE);
DTO dto = new DTO();
dto = modelMapper.map(entity, DTO.class);
return dto;
}
#Test
public void EntityService_GetAll_ReturnsDTOList() {
when(entityRepo.findAll()).thenReturn(Mockito.anyList());
//the second when clause: when(entityService.convertEntityToDTO(Mockito.any(Entity.class)))
.thenReturn(Mockito.any(DTO.class));
List<DTO>DTOList = entityService.getAllDTOs();
Assertions.assertThat(DTOList).isNotNull();
Mockito#any* methods are actually defined in class ArgumentMatchers and can only be used to match the call arguments when setting up a mock or when verifying calls. All matcher methods return null (but have side-effects of modifying a matcher stack to be able to properly detect and match mocked calls).
For instance, you might do Mockito.when(svc.print(Mockito.anyString()).doNothing() when you don't care about the input or Mockito.verify(svc.print(Mockito.anyString()), Mockito.never()) when you want to verify that the method has never been called.
When setting up your mock, you have to provide a real value in your thenReturn call:
when(entityRepo.findAll()).thenReturn(Collections.emptyList());
when(entityService.convertEntityToDTO(Mockito.any(Entity.class)))
.thenReturn(new DTO());

How to link a Vaadin Grid with the result of Spring Mono WebClient data

This seems to be a missing part in the documentation of Vaadin...
I call an API to get data in my UI like this:
#Override
public URI getUri(String url, PageRequest page) {
return UriComponentsBuilder.fromUriString(url)
.queryParam("page", page.getPageNumber())
.queryParam("size", page.getPageSize())
.queryParam("sort", (page.getSort().isSorted() ? page.getSort() : ""))
.build()
.toUri();
}
#Override
public Mono<Page<SomeDto>> getDataByPage(PageRequest pageRequest) {
return webClient.get()
.uri(getUri(URL_API + "/page", pageRequest))
.retrieve()
.bodyToMono(new ParameterizedTypeReference<>() {
});
}
In the Vaadin documentation (https://vaadin.com/docs/v10/flow/binding-data/tutorial-flow-data-provider), I found an example with DataProvider.fromCallbacks but this expects streams and that doesn't feel like the correct approach as I need to block on the requests to get the streams...
DataProvider<SomeDto, Void> lazyProvider = DataProvider.fromCallbacks(
q -> service.getData(PageRequest.of(q.getOffset(), q.getLimit())).block().stream(),
q -> service.getDataCount().block().intValue()
);
When trying this implementation, I get the following error:
org.springframework.core.codec.CodecException: Type definition error: [simple type, class org.springframework.data.domain.Page]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.springframework.data.domain.Page` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 1]
grid.setItems(lazyProvider);
I don't have experience with vaadin, so i'll talk about the deserialization problem.
Jackson needs a Creator when deserializing. That's either:
the default no-arg constructor
another constructor annotated with #JsonCreator
static factory method annotated with #JsonCreator
If we take a look at spring's implementations of Page - PageImpl and GeoPage, they have neither of those. So you have two options:
Write your custom deserializer and register it with the ObjectMapper instance
The deserializer:
public class PageDeserializer<T> extends StdDeserializer<Page<T>> {
public PageDeserializer() {
super(Page.class);
}
#Override
public Page<T> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
//TODO implement for your case
return null;
}
}
And registration:
SimpleModule module = new SimpleModule();
module.addDeserializer(Page.class, new PageDeserializer<>());
objectMapper.registerModule(module);
Make your own classes extending PageImpl, PageRequest, etc. and annotate their constructors with #JsonCreator and arguments with #JsonProperty.
Your page:
public class MyPage<T> extends PageImpl<T> {
#JsonCreator
public MyPage(#JsonProperty("content_prop_from_json") List<T> content, #JsonProperty("pageable_obj_from_json") MyPageable pageable, #JsonProperty("total_from_json") long total) {
super(content, pageable, total);
}
}
Your pageable:
public class MyPageable extends PageRequest {
#JsonCreator
public MyPageable(#JsonProperty("page_from_json") int page, #JsonProperty("size_from_json") int size, #JsonProperty("sort_object_from_json") Sort sort) {
super(page, size, sort);
}
}
Depending on your needs for Sort object, you might need to create MySort as well, or you can remove it from constructor and supply unsorted sort, for example, to the super constructor. If you are deserializing from input manually you need to provide type parameters like this:
JavaType javaType = TypeFactory.defaultInstance().constructParametricType(MyPage.class, MyModel.class);
Page<MyModel> deserialized = objectMapper.readValue(pageString, javaType);
If the input is from request body, for example, just declaring the generic type in the variable is enough for object mapper to pick it up.
#PostMapping("/deserialize")
public ResponseEntity<String> deserialize(#RequestBody MyPage<MyModel> page) {
return ResponseEntity.ok("OK");
}
Personally i would go for the second option, even though you have to create more classes, it spares the tediousness of extracting properties and creating instances manually when writing deserializers.
There are two parts to this question.
The first one is about asynchronously loading data for a DataProvider in Vaadin. This isn't supported since Vaadin has prioritized the typical case with fetching data straight through JDBC. This means that you end up blocking a thread while the data is loading. Vaadin 23 will add support for doing that blocking on a separate thread instead of keeping the UI thread blocked, but it will still be blocking.
The other half of your problem doesn't seem to be directly related to Vaadin. The exception message says that the Jackson instance used by the REST client isn't configured to support creating instances of org.springframework.data.domain.Page. I don't have direct experience with this part of the problem, so I cannot give any advice on exactly how to fix it.

Use Flux in a DTO response

What is the best way to return from controller object with two flux(arrays) inside?
I have two reactive repositories. One with football clubs, another one with countries. I want to return dto like:
public record InitData(Flux<FootballClub> footballclubs, Flux<Country> countries){}
So I can return list instead of flux via .block but this is not good idea. How can I subscribe two repositories in controller and return two arrays?
You can't return multiple Flux instances inside a DTO. Flux need to be subscribed somewhere in order to be useful. Assuming you have the following response DTO:
public class Response {
private List<String> footballClubs;
private List<Integer> countries;
}
You can use .collectList() method to collect all entities emitted by your repository into a List:
private Mono<List<String>> getFootballclubs() {
return footballclubsRepository.select().collectList();
}
private Mono<List<Integer>> getCountries() {
return countriesRepository.select().collectList()
}
And finally, map the resulting Monos into the response DTO:
Mono.zip(getFootballclubs(), getCountries())
.map(tuple2 -> Response.builder().footballClubs(tuple2.getT1()).countries(tuple2.getT2()).build())
Note that this is a valid solution in case we have a limited number of clubs and countries.

Spring Transactions - how to split my method

I have the following method that is called by controller:
#Transactional
public Note getById(Long noteId, Collection<Authority> authorities) {
permissionService.actionAllowed(authorities, Permission.NOTE);
return getNote(noteId);
}
private Note getNote(Long noteId) {
return repository.findById(noteId)
.orElseThrow(() -> new MyException("Note does not exist"));
}
The problem is that we should keep transactions as short as possible so I have to call my validation method permissionService.actionAllowed outside of the trasaction scope. How to do it in the best way?
I don't want to create additional public method with #Transactional... I don't have any idea

JDK8 Functional Programming a function can throw a exception?

I have one requirement
Get the employee information from the employee repository.
Update the employee information with some additional information.
Transform the employee object to gatewayRequest object.
call the gateway service and get the response.
from the response get the return code of the gateway call.
For this requirement, i am using functional programming to achieve the result.
Here I have created the multiple functions in my Service layer
final Function<String, Employee> getRegisteredEmployee =
localId -> employeeRepository.findById(employeeId).
orElseThrow(() -> new ResourceNotFoundException("ResourceNotFound"));
final Function<Employee, Employee> updateEmployeAddressandSave =
employe -> {
String status = //some logic to identitythe Employee
Employee e = new Employee(employee.getName(),employee.getAddress ,"INTERNAL_EMPLOYEE")
Employee emp = employeeRepository.save(e);
return emp;
};
Likewise, I created different functions and then I am using the andThen method of the functional interface to get the results
getRegisteredEmployee.
andThen(updateEmployeAddressandSave).
andThen(transformTheEmployeeToGatewayRequest).
andThen(allgateWayClinet).apply(12);
According to the functional programming model, a function should take input and give some output; it should not throw any exception. But in my example getRegisteredEmployee throws an exception if employee is not found.
Hence, am I not following the functional programming core principles?
what is the alternate way to throw the exception in functional programming?
While not adhering to principles, it is technically possible to create a functional interface that will throw a checked exception.
#FunctionalInterface
interface CheckedFunction<A, B> {
B apply(A a) throws Exception;
}
(Since you're using andThen you'll need to implement that as well using the default keyword. Remember, though, that the functional interface must have at most one non-default method, so you'll have to provide the andThen implementation defaulted.)
So, as an example, you would be able to do something like:
public void doThings(Integer id) throws Exception {
CheckedFunction<Integer, Employee> fn = (id) -> someMethodThatReturnsAnEmployeeOrThrows(id);
fn.apply(id)
.map( ... ) // ... some other stuff
}
As I mentioned, this doe not adhere to principles; I only go down this path when I absolutely have to bubble the exception up. Other Java 8 features such as Optional are more appropriate in this situation. (Since it looks like you're using spring's JPA implementation, you can define your findById method to return an Optional<Employee>.)
Method getRegisteredEmployee can return an Optional object instead of throwing an exception.
final Function<String, Employee> getRegisteredEmployee =
localId -> employeeRepository.findById(employeeId);
final Function<Employee, Employee> updateEmployeAddressandSave =
employe -> {
if(employe.isPresent()) {
employe.get();
...
String status = //some logic to identitythe Employee
Employee e = new Employee(employee.getName(),employee.getAddress ,"INTERNAL_EMPLOYEE")
Employee emp = employeeRepository.save(e);
return new Optional(emp);
} else {
return Optional.empty();
}
};
etc...

Resources