JDK8 Functional Programming a function can throw a exception? - java-8

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...

Related

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.

WebFlux How to Chain Queries In Functional Non Blocking Way

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

How to throw exceptions on search methods in spring data jpa

I am using spring-data-jpa repositories for database operations. I want to throw exceptions if object doesn't exists in database for all methods in my repositories. For example Consider the following method in OrderRepository
findByCustomerAndPayment(Customer customer, Payment payment);
I want to query all orders based on customerId and paymentId. Both the objects are neccessry in the above query. But spring-data-rest returns null if I gave cutomerId doesn't exists in database. I expect spring-data-rest to throw exception if object doesn't exists in database.
How to achieve this?
You just need orElseThrow
orderRepository.findByCustomerAndPayment(customer, payment).orElseThrow(() -> new ResourceNotFoundException("customer", "id", customer.getId()));
If you're using Java 8, you can use Optional<Order> as the return type of the repository method. If the repository method returns an empty Optional calling get on it will throw a NoSuchElementException. Otherwise there is no support for throwing exceptions by repository methods if there are no results.
try {
Optional<Order> result = repository.findByCustomerAndPayment(customer,payment);
Order order = result.get();
} catch(NoSuchElementException e) {
// do something with the exception
}
You can make custom repository implementation like below:
public interface OrderRepositoryCustom {
Order findByCustomerAndPaymentRequired(Customer customer, Payment payment);
}
public class OrderRepositoryImpl implements OrderRepositoryCustom {
#Autowired
OrderRepository orderRepository;
#Override
public Order findByCustomerAndPaymentRequired(Customer customer, Payment payment) {
Order o = orderRepository.findByCustomerAndPayment(customer, payment);
if(o == null) {
throw new IncorrectResultSizeDataAccessException(1);
}
return o;
}
}
Your OrderRepository interface should extend customized:
public interface OrderRepository extends CrudRepository<Order, Long>, OrderRepositoryCustom {
Order findByCustomerAndPayment(Customer customer, Payment payment);
}
Edited
As IncorrectResultSizeDataAccessException is RuntimeException, then no need to throws declaration - i fixed that.
Use Optional together with orElseThrow.
Order findByCustomerAndPayment(Customer customer, Payment payment);
default Order findByCustomerAndPaymentOrThrow(Customer customer, Payment payment) {
return Optional.ofNullable(findByCustomerAndPayment(customer, payment)).orElseThrow();
};

how to get unique values from a column using queryDsl predicate

I am trying to get a unique value from a column say "designation" from a table "employee_register". I dont know how to acheive this using the query Dsl predicate. Can anyone help me with this
You can call distinct() on the Query object. For example (JPA + QueryDSL):
#Test
#Transactional
public void testQueryDSLDistinct() throws Exception {
log.debug("testQueryDSLDistinct started");
JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager);
QEmployeeRegister er = QEmployeeRegister.employeeregister;
List<EmployeeRegister> tuples = queryFactory.select(
Projections.bean(EmployeeRegister.class, er.designation)).distinct()
.from(er).limit(10).fetch();
for (EmployeeRegister record: tuples) {
System.out.println(record.getDesignation());
}
}
I've found this while going through this link
http://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-part-four-jpa-criteria-queries .A similar question was raised by a viewer called raghu and below is the author's answer to the question.May be this one would be helpful to others
Author's answer
You have two options for implementing this:
Use the DISTINCT keyword of JPQL when you are creating query by using the #NamedQuery or #Query annotation.
Call the disctinct() method of the CriteriaQuery class in your specification builder method (The toPredicate() method of the Specification interface gets a reference of the CriteriaQuery object as a parameter).
JPQL Example:
SELECT DISTINCT p FROM Person p WHERE...
Criteria API with Specification Builder:
public class PersonSpecifications {
public static Specification lastNameIsLike(final String searchTerm) {
return new Specification () {
#Override
public Predicate toPredicate(Root personRoot, CriteriaQuery< ?> query,CriteriaBuilder cb) {
query.distinct(true);
//Build Predicate
}
};
}
}
In your case, I would add the following method to the CustomerRepository interface (or whatever your repository interface is):
#Query("SELECT DISTINCT c.lastName FROM Customer c")
public List<String> findLastNames();

Spring / AOP: Best way to implement an activities log in the database

I have been going through some Spring / AOP tutorials and have somewhat familiarized myself with the related concepts.
Now coming to my requirements, I need to create an Activities Log implementation which will save the activities of a logged-in user in the DB which can range from applying for a service or creating new users in case of Admin users, etc. On invocation of any method having an annotation (say #ActivityLog), this information is to be persisted in the form of actorId, actionComment, actionTime, actedUponId, ... etc.
Now, if I create a POJO class (that maps to a ActivityLog table in the DB) and want to save this data from inside the Advice (preferably using the same transaction as the method, method uses #Transactional annotation), how do I actually populate the variables in this POJO?? I can probably get the actorId from the session object & actionTime can simply be new Date() but how about the dynamic values for actionComment / actedUponId?
Any help will be brilliant! (BTW, I have a requirement to not use Hibernate Interceptors.)
Here is a complete example:
#Aspect
#Component
public class WebMethodAuditor {
protected final Log logger = LogFactory.getLog(getClass());
public static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss";
#Autowired
AuditRecordDAO auditRecordDAO;
#Before("execution(* com.mycontrollers.*.*(..))")
public void beforeWebMethodExecution(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
User principal = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Timestamp timestamp = new Timestamp(new java.util.Date().getTime());
// only log those methods called by an end user
if(principal.getUsername() != null) {
for(Object o : args) {
Boolean doInspect = true;
if(o instanceof ServletRequestDataBinder) doInspect = false;
if(o instanceof ExtendedModelMap) doInspect = false;
if(doInspect) {
if(o instanceof BaseForm ) {
// only show form objects
AuditRecord ar = new AuditRecord();
ar.setUsername(principal.getUsername());
ar.setClazz(o.getClass().getCanonicalName());
ar.setMethod(methodName);
ar.setAsString(o.toString());
ar.setAudit_timestamp(timestamp);
auditRecordDAO.save(ar);
}
}
}
}
}
}
If you are looking to get the actionComment and actedUponId from arguments to the annotated method (assuming they're both strings), you can add binding terms to your #Around pointcut like this:
#Around("#annotation(ActivityLog) && args(actionComment,actedUponId)")
public Object logActivity(ProceedingJoinPoint pjp,
String actionComment, String actedUponId) throws Throwable {
// ... get other values from context, etc. ...
// ... write to log ...
pjp.proceed();
}
The args binding in a pointcut can be used in partially-specified mode, in case there are other arguments about that you aren't interested in, and since the aspect is itself a bean, it can be wired into everything else that is going on in the normal way.
Note that if you're mixing declarative transaction management on the same method calls, you've got to get the order of aspects correct. That's done in part by making the aspect bean also implement the Spring Ordered interface, and by controlling the precedence of transactions through the order attribute to <tx:annotation-driven/>. (If that's impossible, you'll be forced to do clever things with direct transaction handling; that's a vastly more painful option to get right…)
You will be getting a reference to the org.aspectj.lang.JoinPoint in your advice.You can get the name of target method being executed with toShortString().You can have a loop-up/property file with the method-name=comments entries.This comments can be populated into the POJO.actionComment.method-name can be set to POJO.actedUponId.
I hope the advice should run within the same transaction, if the data-access method is adviced and the service method uses #Transactional.

Resources