Is it possible to return the Optional value from method only if it's present, but if it's not just continue with a normal method flow. Something like this:
public Message processMessage(Message message) {
// ErrorMessage is subclass of Message; only returned if validator found some violations, otherwise empty optional
Optional<ErrorMessage> error = validator.validate(message);
if (error.isPresent()) return error.get();
// returns different possible subclasses of Message
return service.processMessage(message);
}
Is there any prettier way to write this?
Your problem is indeed that the return types do not match. orElseGet only works when the supplier returns a subtype of the Optional type.
To work around this, you can force a cast to the parent type first:
return error.<Message>map(m -> m).orElseGet(() -> service.processMessage(message));
or equivalently:
return error.map(m -> (Message) m).orElseGet(() -> service.processMessage(message));
I simply would go with Optional.orElseGet and an explicit cast in between:
public Message processMessage(final Message message) {
return validator.validate(message)
.map(Message.class::cast)
.orElseGet(() -> service.processMessage(message));
}
I am not able to test it currently but it may give u an idea, may be you can implement something like below
return Optional.ofNullable(message)
.map(validator::validate)
.orElseGet(service::processMessage)
Looking at that snippet, it looks like the validate method on the validator doesn't quite have the proper return type. Consider using e.g. io.vavr.control.Either or io.vavr.control.Validation monad. Take a look at a possible signature for validate:
Either<SpecificError, ? extends Message> validate(Message message);
Now the map and fold combinators can be used like so:
validator
.validate(message)
.map(message -> service.processMessage(message))
.fold(error -> new ErrorMessage(error), success -> success); // the left function can be replaced by Function.identity()
to yield Message.
Related
I have a java 8 functional interface that accepts a list of validators that are applied on an object and returns the validation result. The validation results are accumulated in the reduce phase. The code as follows:
public interface LogicalTableValidator extends Function<LogicalTable, ValidationResult> {
static LogicalTableValidator addAll(LogicalTableValidator... validators) {
// Need to break out of this validator stream, based on the criticality of a particular validation error
return logicalTable -> Arrays.stream(validators).map(v -> v.apply(logicalTable))
.reduce(new ValidationResult(logicalTable.getUid()), (validationResult, currentResult) -> {
validationResult.addValidationMessages(currentResult.getValidationMessages());
return validationResult;
});
}
}
This validation logic gets called from here
LogicalTableValidator logicalTableValidators = LogicalTableValidator.addAll(getValidators());
List<ValidationResult> ltValidationResults = logicalTables.stream()
.parallel()
.map(logicalTableValidators)
.collect(Collectors.toList());
The problem I am facing is that, I am not able to break from the validation logic conditionally. This will be the case when I am applying the validators on the logicalObject, if the validation fails with a critical error, I dont need to run rest of the validators. Instead I need to stop the validation process right there.
A work around would be not to use lambda expression for validation and use the following code instead.
return new LogicalTableValidator() {
#Override
public ValidationResult apply(LogicalTable t) {
ValidationResult result = new ValidationResult(t.getUid());
for (LogicalTableValidator validator : validators) {
ValidationResult currentResult = validator.apply(t);
List<ValidationMessage> messages = currentResult.getValidationMessages();
Boolean exit = false;
for (ValidationMessage message : messages) {
if(StringUtils.equalsIgnoreCase(message.getSeverity(), "1")) {
exit = true;
break;
}
}
result.addValidationMessages(currentResult.getValidationMessages());
if (exit) break;
}
return result;
}
};
It seems, not using lambda expression in functional interface, defeats the purpose of using functional interface, but I couldn't figure out a way to conditionally break out of the validation loop. Is there any alternative I can use? Should this code be structured in a different way?
You can try something like below. In peek it collect ValidationMessages. In filter and findFirst it stop after first error message. It is replacement for takeWhile that was mentioned in comments, you can also check this.
public interface LogicalTableValidator extends Function<LogicalTable, ValidationResult> {
static LogicalTableValidator addAll(LogicalTableValidator... validators) {
logicalTable -> {
ValidationResult result = new ValidationResult(logicalTable.getUid());
Arrays.stream(validators).map(v -> v.apply(logicalTable))
.peek(currentResult -> result.addValidationMessages(currentResult.getValidationMessages()))
.filter(currentResult -> currentResult.getValidationMessages().stream()
.filter(message -> StringUtils.equalsIgnoreCase(message.getSeverity(), "1"))
.count() > 0)
.findFirst()
.orElse(null);
return result;
}
}
}
There are two distinct things: 1. breaking logicalTables stream and 2. breaking validators stream.
For logicalTables, your stream is parallel and even if the break was possible you would obtain potentially different results.
For validators stream, Stream.takeWhile seems to be the closest to pure stream-based solution. Unfortunately, it is in JDK since Java 9 and moreover it doesn't comprise invalid ValidationResult into resulting stream. Alternatives might exist in external libraries though the imperative code seems to me as simplest and readable enough at this moment.
Hello What am I doing wrong here
I want to get the foundation Id , if its not present then get Insurance Type.. the code snippets are pasted below .. but I get an error at the orElse part I even tried orElseGet() ...It says "target type of Lambda must be an interface"..
String type = getFoundationId(companyInsurances).orElse(()->getInsuranceType(insurance, companyInsurances));
…
private Optional<String> getInsuranceType(Insurance insurance, List<CompanyInsurance> companyInsurances) {
return InsurancePeriodHelper.findFirstCompanyInsuranceOfType(companyInsurances, CompanyInsuranceType.POLICY_HOLDER.getValue())
.map(companyInsurance-> insurance.getProduct());
}
private Optional<String> getFoundationId(List<CompanyInsurance> companyInsurances) {
return InsurancePeriodHelper.findFirstCompanyInsuranceOfType(companyInsurances, CompanyInsuranceType.FOUNDATION.getValue())
.map(companyInsurance -> companyInsurance.getCompany().getFoundationIdentifier().toString());
}
With Java-9 and above you could simply chain such Optionals using Optional.or as:
String type = getFoundationId(companyInsurances)
.or(() -> getInsuranceType(insurance, companyInsurances))
.orElse("defaultValue");
I am trying to re-write a scala example of a POC project from Manning's "Akka in Action" in Java. The project is a small Http server for creating events and buying tickets.
I am at a point when an actor can send an Optional<Event> to my RestApi. Depending on whether the value is present I should complete the call with OK, else NOT_FOUND.
In Scala the snippet looks as follow:
get {
// GET /events/:event
onSuccess(getEvent(event)) {
_.fold(complete(NotFound))(e => complete(OK, e))
}
}
...where getEvent returns an Option[Event] (equivalent of java's Optional<Event>). This is how I rewrote it in Java:
get(() -> onSuccess(() -> getEvent(event), eventGetRoute()))
...
//and eventGetRoute() is a function:
private Function<Optional<Event>, Route> eventGetRoute() {
return maybeEvent -> maybeEvent.map(event -> complete(OK, event, Jackson.marshaller())).orElseGet(() -> complete(NOT_FOUND));
}
This doesn't compile: Bad return type in lambda expression: Route cannot be converted to RouteAdapter. The longer (and first) complete returns a RouteAdapter and the second one returns a Route. If I re-write the above function like this:
private Function<Optional<Event>, Route> eventGetRoute() {
return maybeEvent -> {
if(maybeEvent.isPresent()) {
return complete(OK, maybeEvent.get(), Jackson.marshaller());
}
return complete(NOT_FOUND);
};
}
...then the compiler doesn't complain, but then it is not right way to map an Optional.
Java doesn't have fold method for Optional (not in SE8 at least), which allows passing the fallback-to value first.
I'm curious whether it is possible to write this function in respecting functional style.
Update:
As asked in the comments, these are the signatures of the complete methods from akka-http javadsl library:
def complete(status: StatusCode): Route = RouteAdapter(
D.complete(status.asScala))
and
def complete[T](status: StatusCode, value: T, marshaller: Marshaller[T, RequestEntity]) = RouteAdapter {
D.complete(ToResponseMarshallable(value)(fromToEntityMarshaller(status.asScala)(marshaller)))
}
What is return type of complete(OK, maybeEvent.get(), Jackson.marshaller())?
I assume RouteAdapter. If so cast it to Route so chain will be binded to Route not RouteAdaper and at the end will not have troubles with casting from super class to subclass.
I am trying to understand and use Java 8 - Optional feature. I would like to refactor this code block. Without Optional I have such a condition.
ClassA objA = findObject();
if(objA == null || objA.isDeleted()){
throw Exception("Object is not found.");
}
I want to transform this block using Optional wrapper. I have read about filter, ifPresent functions but I could not find a way. Maybe it is simple but I am new to Java 8. I would appreciate if you could help.
You shouldn't use Optional<T> to solely replace the if statement as it's no better and doesn't gain you any benefit. A much better solution would be to make the findObject() method return Optional<ClassA>.
This makes the caller of this method decide what to do in the "no value" case.
Assuming you've made this change, you can then leverage the Optional<T> type:
findObject().filter(a -> !a.isDeleted()) // if not deleted then do something
.map(...) // do some mapping maybe?
... // do some additional logic
.orElseThrow(() -> new Exception("Object is not found."));//if object not found then throw exception
see the Optional<T> class to familiarise your self with the API and the methods that are available.
#Eric as you mentioned in your comment, if you don't want (can't) change the return type of findObject() for some constraints, you can do the following :
ClassA objA = findObject();
Optional<ClassA> myOpt =
Optional.ofNullable(objA)
.filter(e->!e.isDeleted())
.orElseThrow(()->new Exception("Object is not found.");
return list.stream()
.filter(tmm -> tmpAddress.type() == 1)
.findFirst()
.orElseThrow(()->{
logger.error("ERROR");//something like this
exceptionHandler.handler("some exception
return null;
});
I have a method which accepts Mono as a param.
All I want is to get the actual String from it. Googled but didn't find answer except calling block() over Mono object but it will make a blocking call so want to avoid using block(). Please suggest other way if possible.
The reason why I need this String is because inside this method I need to call another method say print() with the actual String value.
I understand this is easy but I am new to reactive programming.
Code:
public String getValue(Mono<String> monoString) {
// How to get actual String from param monoString
// and call print(String) method
}
public void print(String str) {
System.out.println(str);
}
Getting a String from a Mono<String> without a blocking call isn't easy, it's impossible. By definition. If the String isn't available yet (which Mono<String> allows), you can't get it except by waiting until it comes in and that's exactly what blocking is.
Instead of "getting a String" you subscribe to the Mono and the Subscriber you pass will get the String when it becomes available (maybe immediately). E.g.
myMono.subscribe(
value -> System.out.println(value),
error -> error.printStackTrace(),
() -> System.out.println("completed without a value")
)
will print the value or error produced by myMono (type of value is String, type of error is Throwable). At https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html you can see other variants of subscribe too.
According to the doc you can do:
String getValue(Mono<String> mono) {
return mono.block();
}
be aware of the blocking call
Finally what worked for me is calling flatMap method like below:
public void getValue(Mono<String> monoString)
{
monoString.flatMap(this::print);
}
What worked for me was the following:
monoString.subscribe(this::print);
Simplest answer is:
String returnVal = mono.block();
This should work
String str = monoString.toProcessor().block();
Better
monoUser.map(User::getId)