Performing side-effects in Vavr - java-8

I'm going through Vavr Usage Guide's section about performing side-effects with Match and other "syntactic sugar" as they call it. Here is the example given there:
Match(arg).of(
Case($(isIn("-h", "--help")), o -> run(this::displayHelp)),
Case($(isIn("-v", "--version")), o -> run(this::displayVersion)),
Case($(), o -> run(() -> {
throw new IllegalArgumentException(arg);
}))
);
and then it goes into discussing how run should not be run outside of lambda body, etc.
IMHO, something was lacking in the explanation to give me full clarity, i.e. is run an existing method on some Vavr interface (which I couldn't find) or should it be my own method in the surrounding code base?
So I endeavored and spelled out the above example just slightly to be something that I can run and see the results of it:
#Test public void match(){
String arg = "-h";
Object r = Match(arg).of(
Case($(isIn("-h", "--help")), o -> run(this::displayHelp)),
Case($(isIn("-v", "--version")), o -> run(this::displayVersion)),
Case($(), o -> run(() -> {
throw new IllegalArgumentException(arg);
}))
);
System.out.println(r);
}
private Void run(Supplier<String> supp) {
System.out.println(supp.get());
return null;}
private String displayHelp() {return "This is a help message.";}
private String displayVersion() {return "This is a version message.";}
Could someone please confirm that I'm on the right track with how this was envisioned to function by Vavr's designers or did I totally go off on a tangent in which case I'd appreciate some guidance as to how it should be.
Thank you in advance.
Updated:
import static io.vavr.API.run;
#Test public void match1() {
String arg = "-h";
Object r = Match(arg).of(
Case($(isIn("-h", "--help")), o -> run(this::displayHelp)),
Case($(isIn("-v", "--version")), o -> run(this::displayVersion)),
Case($(), o -> run(() -> {
throw new IllegalArgumentException(arg);
}))
);
System.out.println("match: " +r);
}
//private Void run(Supplier<Void> supp) {supp.get();}
private void displayHelp() {System.out.println("This is a help message.");}
private void displayVersion() {System.out.println("This is a version message.");}

It's io.vavr.API.run. According to the Javadoc, you're supposed to import the basic VAVR functionality via
import static io.vavr.API.*;
The run function calls a Runnable (a function () -> void) once and returns (Void)null. It's used because
Case($(isIn("-h", "--help")), o -> this.displayHelp())
does not work when displayHelp() is void, since void isn't a well-behaved type in Java. Specifically, Supplier<void> and Function<?, void> do not work. Additionally,
Case($(isIn("-h", "--help")), this.displayHelp())
would execute displayHelp() before the match, so the matching is useless. This rules out all three (ignoring argument number) overloads of Case. run fixes this, because Supplier<Void> and Function<?, Void> are possible, and taking a Runnable means the action can be deferred until the argument to Case is needed.

Related

How to suppress Kotlin unused parameter warning in all test classes?

In parameterized tests I use hint parameter to clarify test case naming. From the static analyzer point of view this parameter is never used, so this warning from kotlin-maven-plugin appears in the build log:
[WARNING] /Users/test/TestSizeCreation.kt: (42, 10) Parameter 'hint' is never used
How to suppress such warnings globally in all tests?
Example of test with hint:
#ParameterizedTest(name = "Size {index}: {0}")
#MethodSource("invalidAges")
fun shouldFailToCreateAge(hint: String, sizeCandidate: Int) {
assertThatThrownBy { Size(sizeCandidate) }
.isInstanceOf(InvalidInput::class.java)
.hasMessageStartingWith("Could not recognize size: ")
}
companion object {
#JvmStatic
fun invalidAges(): Stream<Arguments> =
Stream.of(
arguments("negative", -5),
arguments("zero", 0),
arguments("too much", 1000)
)
}
Two possible options (there may be more):
The first is to annotate the parameter as being unused, like this:
#Suppress("UNUSED_PARAMETER") either at the function or parameter level.
The second option is to use a lambda inside your test to execute the actual code, and then use an underscore to ignore the first parameter, like this:
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.Arguments.arguments
import org.junit.jupiter.params.provider.MethodSource
import java.util.stream.Stream
class Stack {
#ParameterizedTest(name = "Size {index}: {0}")
#MethodSource("invalidAges")
fun shouldFailToCreateAge(hint: String, sizeCandidate: Int) {
process(hint, sizeCandidate) { _, size ->
println("add your test using size here $size")
}
}
private fun process(hint: String, sizeCandidate: Int, block: (String, Int) -> Unit) {
block(hint, sizeCandidate)
}
companion object {
#JvmStatic
fun invalidAges(): Stream<Arguments> =
Stream.of(
arguments("negative", -5),
arguments("zero", 0),
arguments("too much", 1000)
)
}
}
I ended up using this function introduced only in the src/test context:
// this function used only to avoid "Parameter is never used" warning
// on intentionally unused parameters
fun Any?.touch() = Unit
This how it looks in a test method:
#ParameterizedTest(name = "Size {index}: {0}")
#MethodSource("invalidAges")
fun shouldFailToCreateAge(hint: String, sizeCandidate: Int) {
hint.touch()
assertThatThrownBy { Size(sizeCandidate) }
.isInstanceOf(InvalidInput::class.java)
.hasMessageStartingWith("Could not recognize size: ")
}
Why:
The #Suppress("UNUSED_PARAMETER") is intended strictly for special situations in rare cases. And would be inappropriate to put it in all Parameterized tests making it noisy. It also could cause missing real cases of unused parameters, helping garbage code appear.
The touch method clearly shows intention. And it looks like a minimal evil.

How to handle errors in Spring reactor Mono or Flux?

I have below code retuning Mono<Foo>:
try {
return userRepository.findById(id) // step 1
.flatMap(user -> barRepository.findByUserId( user.getId()) // step 2
.map(bar-> Foo.builder().msg("Already exists").build()) // step 3
.switchIfEmpty(barRepository.save(Bar.builder().userId(user.getId()).build()) // step 4
.map(bar-> Foo.builder().msg("Created").build()) // step 5
))
.doOnError(throwable -> Mono.just(handleError(throwable)));
} catch(Exception e) {
log.error("from catch block");
return Mono.just(handleError(e));
}
If error occurs in step 1 (e.g. user does not exist by the specified id), will it be caught by doOnError or by try catch block or none of these two?
Same question if error happens in step 2, step3, step 4.
What is the correct code so that error is always caught by doOnError and eliminate try catch?
I am using
public interface UserRepository extends ReactiveMongoRepository<User, String> same for barRepository.
handleError(throwable) simply does log.error(e.getMessage() and retuns Foo.
I think the first error is in the title: "Mono or Flux" is not related with the error handling.
Mono can only emit one item at the most (streams one element)
Flux can emit more complex stuff (i.e. List)
To handle errors you can follow this example:
return webClient.get()
.uri(url)
.retrieve()
.bodyToMono(ModelYouAreRetrieving.class)
.doOnError(throwable -> logger.error("Failed for some reason", throwable))
.onErrorReturn(new ModelYouAreRetrieving(...))
.block();
DoOnError will only perform side effects and assuming the findById are will return a Mono.Error() if it fails something like this should work.
return userRepository.findById(id)
.flatMap ( user ->
barRepository.findByUserId(user.getId())
.map((user,bar)-> Foo.builder().msg("Already exists").build())
.switchIfEmpty(barRepository.save(Bar.builder().userId(user.getId()).build())
.map(bar-> Foo.builder().msg("Created").build())
))
.onErrorReturn(throwable -> Mono.just(handleError(throwable)));
The try catch will only work if you either call a blocking operation of the chain, or a runtime error occurs before you enter the reactive chain. the doOn operations do not modify the chain, they are used for side effects only. Since flatMap expects a producer, you will need to return a Mono from the call, and in this case if an error occurs, then it will just propagate the error. In all reactive chains the error will propagate unless otherwise handled.
Use Exceptions.propagate(e) which wraps a checked exception into a special runtime exception that can be handled by onError
Below Code tries to covers User attributes in upper case. Now, when it encounters kyle the checked exception is throws and MIKE is returned from onErrorReturn
#Test
void Test19() {
Flux.fromIterable(Arrays.asList(new User("jhon", "10000"),
new User("kyle", "bot")))
.map(x -> {
try {
return toUpper(x);
} catch (TestException e) {
throw Exceptions.propagate(e);
}
})
.onErrorReturn(new User("MIKE", "BOT")).subscribe(x -> System.out.println(x));
}
protected final class TestException extends Exception {
private static final long serialVersionUID = -831485594512095557L;
}
private User toUpper(User user) throws TestException{
if (user.getName().equals("kyle")) {
throw new TestException();
}
return new User(user.getName().toUpperCase(), user.getProfession().toUpperCase());
}
Output
User [name=JHON, profession=10000]
User [name=MIKE, profession=BOT]
#Gianluca Pinto's last line of code is also incorrect. The code won't be compiled. onErrorReturn is not suitable for complicated error handling. What you should use is onErrorResume.
see: https://grokonez.com/reactive-programming/reactor/reactor-handle-error#21_By_falling_back_to_another_Flux
onErrorResume will fall back to another Flux and let you catch and manage the exception thrown by previous Flux. if look into the implementation of onErrorReturn, you will find onErrorReturn is actually using onErrorResume.
So here the code should be:
.onErrorResume(throwable -> Mono.just(handleError(throwable)));
The last line of the code of #James Ralston is wrong. The correct code should be:
return userRepository.findById(id)
.flatMap ( user ->
barRepository.findByUserId(user.getId())
.map((user,bar)-> Foo.builder().msg("Already exists").build())
.switchIfEmpty(barRepository.save(Bar.builder().userId(user.getId()).build())
.map(bar-> Foo.builder().msg("Created").build())
))
.onErrorReturn(Mono.just(handleError(throwable)));
While creating the reactive flow, we need to use onError* as it provides a fallback Mono/Flux while doOn* are side-effect operators.
NOTE: The examples are in Kotlin
Below is an example:
fun saveItems(item: Item) = testRepository.save(item)
.onErrorResume {
Mono.error(
onErrorResumeHandler(
it,
"APP-1002",
"Error occurred while saving the something :P, contact admin"
)
)
}
fun onErrorResumeHandler(exception: Throwable, errorCode: String, errorMessage: String) =
if (exception is TestRepositoryException) exception else
TestServiceException(errorCode, errorMessage)
There should be a central exception handler, we can create by extending AbstractErrorWebExceptionHandler. The order is -2 to supersede the default.
Below is an example:
#Component
#Order(-2)
class BaseControllerAdvice(
errorAttributes: ErrorAttributes,
resources: WebProperties.Resources,
applicationContext: ApplicationContext,
serverCodecConfigurer: ServerCodecConfigurer
) : AbstractErrorWebExceptionHandler(errorAttributes, resources, applicationContext) {
val log = logger()
init {
setMessageWriters(serverCodecConfigurer.writers)
}
override fun getRoutingFunction(errorAttributes: ErrorAttributes?) =
router {
RequestPredicates.all().invoke(this#BaseControllerAdvice::renderErrorResponse)
}
//RouterFunctions.route(RequestPredicates.all(),this::renderErrorResponse)
fun renderErrorResponse(
request: ServerRequest
): Mono<ServerResponse> {
val errorPropertiesMap = getErrorAttributes(
request,
ErrorAttributeOptions.defaults()
)
val ex: ApplicationException = getError(request) as ApplicationException
log.info("Error attributes:{}", request)
return ServerResponse.status(HttpStatus.BAD_REQUEST)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(ErrorResponseVO(ex.errorCode, ex.errorMessage)))
}
data class ErrorResponseVO(val errorMessage: String, val errorCode: String)
}

Kotlin not able to convert gradle's Action class to a lambda

So, while this is quite a kotlin-dsl for gradle specific issue, I think it overall applies to the kotlin language itself, so I am not going to use that tag.
In the gradle API, the class Action<T> is defined as:
#HasImplicitReceiver
public interface Action<T> {
/**
* Performs this action against the given object.
*
* #param t The object to perform the action on.
*/
void execute(T t);
}
So ideally, this should work in kotlin (because it is a class with a SAM):
val x : Action<String> = {
println(">> ${it.trim(0)}")
Unit
}
But I get the following two errors:
Unresolved reference it
Expected Action<String> but found () -> Unit
Fwiw, even Action<String> = { input: String -> ... } doesn't work.
Now here's the really intriguing part. If I do the following in IntelliJ (which btw, works):
object : Action<String> {
override fun execute(t: String?) {
...
}
}
IntelliJ pops the suggestion Convert to lambda, which when I do, I get:
val x = Action<String> {
}
which is better, but it is still unresolved. Specifying it now:
val x = Action<String> { input -> ... }
gives the following errors Could not infer type for input and Expected no parameters. Can someone help me with what is going on?
This is because the Action class in gradle is annotated with HasImplicitReceiver. From the documentation:
Marks a SAM interface as a target for lambda expressions / closures where the single parameter is passed as the implicit receiver of the invocation (this in Kotlin, delegate in Groovy) as if the lambda expression was an extension method of the parameter type.
(emphasis mine)
So, the following compiles just fine:
val x = Action<String> {
println(">> ${this.trim()}")
}
You could even just write ${trim()} and omit the this in front of it.
You need reference the function with class name, like:
val x: Action<String> = Action { println(it) }

JDK8 type inference issue

I'm trying to run the following code which is compiled fine under JDK8 thanks to type inference:
public static <A,B> B convert(A a) {
return (B) new CB();
}
public static void main(String[] args) {
CA a = new CA();
CB b = convert(a); //this runs fine
List<CB> bl = Arrays.asList(b); //this also runs fine
List<CB> bl1 = Arrays.asList(convert(a)); //ClassCastException here
}
However, running this throws ClassCastException: CB cannot be cast to [Ljava.lang.Object, but the CB b = convert(a) works fine.
Any idea why?
Whenever you create a generic method with a signature that promises to return whatever the caller wishes, you are asking for trouble. You should have got an “unchecked” warning from the compiler which basically means: unexpected ClassCastExceptions may occur.
You expect the compiler to infer
List<CB> bl1 = Arrays.asList(YourClass.<CA,CB>convert(a));
whereas the compiler actually inferred
List<CB> bl1 = Arrays.asList(YourClass.<CA,CB[]>convert(a));
as far as I know, because it prefers method invocations not requiring a varargs packaging (which is compatible with pre-varargs code).
This fails because your convert method does not return the expected array type.

Hide Swift "Will never be executed" warning

I've got some code that is generating warnings like so:
code path.swift:9:13: warning: will never be executed
fatalError()
^
code path.swift:9:13: note: a call to a noreturn function
fatalError()
^
The compiler output doesn't give any -W arguments I can use to silence these in my source file. How can I stop these warnings?
Please note this is testing code and everything is working as designed - removing the lines complained about is not a solution
The Swift compiler does not have an option to suppress warnings
(as far as I know). The only chance is to avoid the warnings.
In your particular case I don't have a full explanation
for the warning, but a possible workaround. As you said in the comments,
the problem occurs with the Nimble framework in
expect{ fatalError() }.to(throwError()) // Warning: Will never be executed
Here, { fatalError() } is a closure of type () -> Void,
and expect ultimately calls the Expression initializer
public init(expression: () throws -> T?, location: SourceLocation, isClosure: Bool = true)
which takes a closure of type () throws -> T? as the first parameter.
The problem is now related to the optional return type T?.
This can be stripped down to the following minimal self-contained example:
let cl1 : () -> Void = { fatalError() } // No warning
let cl2 : () -> Void? = { fatalError() } // Warning: Will never be executed
Only the second line generates a warning.
I assume that the compiler creates some wrapper code to convert
the Void return type from fatalError() to Void?, and then warns
that the wrapper code is never executed.
As a workaround, you can make the closure type explicit as
let cl3 : () -> Void? = { _ -> Void in fatalError() } // No warning
or assign the closure to an intermediate variable:
let fatalClosure = { fatalError() }
let cl4 : () -> Void? = fatalClosure // No warning
This can be applied to your case:
expect {
_ -> Void in fatalError()
}.to(throwError())
But note that fatalError() – when called – terminates the program
immediately. There is no chance to "catch" that termination.

Resources