Rewriting a try catch in Java to Kotlin - java

Thinking of rewriting java try catch to Kotlin.
In case of an error, just need to log a status.
Is using Arrow with kotlin an overkill ?
sample implementation in Kotlin/Arrow:
fun some_method(): <SomeReturnType>{
Try.invoke {
//code which will return SomeReturnType
}.getOrElse { throwable ->
when (throwable) {
is RuntimeException -> {
// do something
}
is SomeOtherEception -> {
// do something
}
else -> {do something}
}
}
}

Related

How do i handle or log exception for Method references?

I have the code snippet below. But i was wondering how to try catch exception with method references. I want to write try catch block for getUserByUserId method, probably log it and catch with NotFoundException. How do i refactor this code in case of method reference userService::getUserByUserId?
List<String> listofIds= ldapUsers.stream()
.map(PersonDTO::getUserId)
.map(userService::getUserByUserId)
.filter(Optional::isPresent)
.map(Optional::get)
.map(User::get_id)
.collect(Collectors.toList());
You could write a mapper function in the class you are doing the chaining of calls:
private Optional<User> getUser(PersonDTO personDTO) {
try {
return userService.getUserByUserId(personDTO.getUserId());
} catch (Exception ex) {
log.error("Your message here", ex);
throw new NotFoundException();
}
}
And use it like this:
List<String> listofIds = ldapUsers.stream()
.map(PersonDTO::getUserId)
.map(this::getUser)
.filter(Optional::isPresent)
.map(Optional::get)
.map(User::get_id)
.collect(Collectors.toList());
Leave the stream like that add the logic you want in the getUserByUserId method. If it doesn't find a user it logs the error and throws the exception.
EDIT: since you can't modify the method, you can do the following:
List<String> listofIds= ldapUsers.stream()
.map(PersonDTO::getUserId)
.map(userId -> {
User user = userService.getUserByUserId(userId);
if(user == null) {
log.error("User not found");
throw new NotFoundException();
}
return user;
})
.filter(Optional::isPresent)
.map(Optional::get)
.map(User::get_id)
.collect(Collectors.toList());
If it's unchecked exception, you don't need to do anything. But if its checked exception then you can do something like this:
..
.map((userService) -> {
try{
...//call userService#getUserByUserId
}catch(NotFoundException e){
//log or do something else
}
}) ...

Annotation not working in Kotlin, wrong init?

I am working in a small feature for a Kotlin project and I am trying to do an annotation.
I want to "encapsulate" a method inside a try catch.
Lets say I annotate a method like this
#LogException
fun foo(){
//do something
}
So I want to process the annotation to later do something like this:
try{
foo()
}catch(exception: Exception){
// do something
//log
}
Is it even possible?
I started with tutorial for Kotlin (that should not be so different than Java) https://medium.com/#elye.project/annotation-tutorial-for-dummies-in-kotlin-1da864acc442 But then I am using this
#AutoService(Processor::class)
To register my processor and I think is not initializing my annotation.
So far this is my code:
#Target(AnnotationTarget.FUNCTION)
#Retention(AnnotationRetention.SOURCE)
#Documented
annotation class LogException(
val name: String,
val statusCode: Int = 500
)
and my processor:
#AutoService(Processor::class)
class MyProcessor : AbstractProcessor() {
val logger = LoggerFactory.getLogger(MyProcessor::class.java)
override fun process(annotations: MutableSet<out TypeElement>?, roundEnv: RoundEnvironment?): Boolean {
//do something
logger.info("info")
return false
}
override fun getSupportedAnnotationTypes(): MutableSet<String> {
logger.info("info")
return mutableSetOf(LogException::class.java.canonicalName)
}
}
At the moment I am not able to see any in my logs, or even if I change it for an exception.
I am using this annotation in a method.
#LogException
fun foo(){
//do something
}
Any idea what Im missing?
//do something and //log something is just example to dont paste all code
It's not possible to change the existing code using annotation processors. They can only create new files. If you want to change existing ones, write Kotlin compiler plugin.
If you only want to get rid of boilerplate catch blocks, use an inline function which wraps an original function with try-catch:
inline fun runLogging(code: () -> Unit) = try {
code()
} catch (e: Exception) {
yourLogger.log(e)
}
fun foo() = runLogging {
throw Exception() // will be logged
}
Or you can make runLogging generic function which handles only specified exceptions:
inline fun <reified E : Exception> runLogging(code: () -> Unit) = try {
code()
} catch (e: Exception) {
if (e is E) yourLogger.log(e)
else throw e
}
fun foo() = runLogging<FileNotFoundException> {
throw FileNotFoundException() // will be logged
}
fun bar() = runLogging<FileNotFoundException> {
throw Exception() // will be rethrown
}

Best way to parse DBXException java

So I recently asked the question of how to handle Dropbox API Exceptions here. I learned that I would have to parse the DBXEception into its subclasses which there are many of. Now Thinking about this I am wondering what would be the best way to go about handling this.
Currently I plan on using instanceof and checking like this if I want the program to try again it will return true and the program will try again maybe with a exponential backoff with server request
public boolean parseDBX(DbxException e)
{
if(e instanceof AccessErrorException) {//handle Error
}else if (e instanceof DbxApiException) {//handle Error
}etc
}
It would be called in a catch block like this
for(int i =0;;i++) {
try {
ListFolderResult result = client.files().listFolder("/Saves/"+prefName);
while (true) {
for (Metadata metadata : result.getEntries()) {
System.out.println(metadata.getPathLower());
//metadata.
}
if (!result.getHasMore()) {
break;
}
result = client.files().listFolderContinue(result.getCursor());
}
} catch (ListFolderErrorException e) {
createDefFolder();
} catch (DbxException e) {
if(codeHandler.parse(e)&&i<10) {
continue;
}else {
log.write("Error 5332490: a problem was encountered while trying to check for the root file"+e.getMessage());
throw new IOException();
}
}
}
So My Question is there a way to use a switch statement instead(From what I have found the answer is no), and if not, is there a better way to handle checking for the type of exception.
The best approach is to avoid "parsing" the exception at all by catching exceptions of the appropriate type:
try {
...
} catch (AccessErrorException aee) {
...
} catch (DbxApiException dae) {
...
}
In cases when this is not desirable you could associate your own integer ID with each exception type, put it in a Map, and use it in your parse method to distinguish among subtypes in a switch:
static Map<Class,Integer> parseId = new HashMap<>();
static {
parseId.put(AccessErrorException.class, 1);
parseId.put(DbxApiException.class, 2);
...
}
...
public void parseDBX(DbxException e) {
Integer id = parseId.get(e.getClass());
if (id != null) {
switch (id.intValue()) {
...
}
}
}

Java 8 generic Retry if specific exception

I'm finding myself writing alot of retry loops that look like
int triesRemaining = 3;
while (triesRemaining > 0) {
try {
<MY FUNCTION CALL>
LOGGER.info("success");
break;
} catch (Exception e) {
if (e.getCause() instanceof SocketTimeoutException) {
triesRemaining--;
LOGGER.info(e.getMessage() + " trying again. Tries Remaining: " + triesRemaining);
} else {
LOGGER.error(e.getMessage(), e);
return;
}
}
}
if (triesRemaining == 0) {
LOGGER.error("Failed over too many times");
}
I want to write a generic function that accepts a Lambda and only retries on a specific error (in the above case thats SocketTimeoutException). I've seen some functions that accept a Runnable which is fine, but they don't seem to allow limiting to specific exceptions.
Any advice?
Well it's already done. It also accepts list of exceptions on which you want to retry. It also provides linear/exponential retry strategies.
Have a look https://github.com/rholder/guava-retrying
A simple example from it's readme, you can compose and use a retryer like:-
Callable<Boolean> callable = new Callable<Boolean>() {
public Boolean call() throws Exception {
return true; // do something useful here
}};
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.retryIfResult(Predicates.<Boolean>isNull())
.retryIfExceptionOfType(IOException.class)
.retryIfRuntimeException()
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.build();
try {
retryer.call(callable);
} catch (RetryException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
Have a look to org.springframework.retry
There is an annotation #Retryable which corresponding to your need. You can specify the type of exception to retry and configure the number of attempt, etc...
Check out Failsafe:
RetryPolicy retryPolicy = new RetryPolicy()
.retryOn(SocketTimeoutException.class)
.withMaxRetries(3);
Failsafe.with(retryPolicy)
.onRetry((c, f, ctx) -> log.warn("Failure #{}. Retrying.", ctx.getExecutions()))
.onFailure(e -> LOGGER.error(e.getMessage(), e))
.run(() -> myFunctionCall());
What's the problem of just making this function to accept a Runnable argument and then run it in <MY FUNCTION CALL>?
public static void retry(Runnable r) {
// ...
while (triesRemaining > 0) {
try {
r.run();
LOGGER.info("success");
break;
}
// ...
}
then call it (if you prefer - with a lambda):
retry(() -> {
connectToServer();
// todo what-ever-you-want
});
I believe you're looking for pure Java based solution. Based on assumption, I would say Java 8 uses functional interface, an interface with single abstract method. I would create a new RetryCommand class that has a run method which takes in a function.

testng - creating KnownFault and IntermittentFailure annotations

I would like to annotate some of my test cases with KnownFault - which would do pretty much what expectedException does plus some magic using YouTrack's REST API. I would also like to have an IntermittentFailure attribute which would mean that I'm aware that the test might occasionally fail with [exception] [message] but I wouldn't want this to block the rest of my build chain.
After some research I found that my test class should implement IHookable, then I could have something like this:
#Override
public void run(IHookCallBack callBack, ITestResult result) {
callBack.runTestMethod(result);
if (result.getThrowable().getCause() instanceof IllegalArgumentException){
System.out.println("This is expected.");
result.setThrowable(null);
}
else{
System.out.println("Unexpected exception");
}
}
The problem with this is the actual implementation of invokeHookable:
final Throwable[] error = new Throwable[1];
IHookCallBack callback = new IHookCallBack() {
#Override
public void runTestMethod(ITestResult tr) {
try {
invokeMethod(thisMethod, testInstance, parameters);
} catch (Throwable t) {
error[0] = t;
tr.setThrowable(t); // make Throwable available to IHookable
}
}
#Override
public Object[] getParameters() {
return parameters;
}
};
hookable.run(callback, testResult);
if (error[0] != null) {
throw error[0];
}
Unfortunately that last line means that my test case is going to throw an exception no matter what as the error array is completely out of my hands in the run method.
So, what would be the proper way of intercepting an exception and handling it the way I want to?
What you are trying to do is really interesting. You should try to propose changes on https://github.com/cbeust/testng/pull/
But maybe IHookable is not the best listener you can use. Did you try IInvokedMethodListener?
void afterInvocation(IInvokedMethod method, ITestResult result) {
if (result.getThrowable().getCause() instanceof IllegalArgumentException) {
System.out.println("This is expected.");
result.setThrowable(null);
result.setStatus(SUCCESS); // If you want to change the status
} else {
System.out.println("Unexpected exception");
}
}

Categories

Resources