com.aegisql.util.function.ExceptionHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ftry Show documentation
Show all versions of ftry Show documentation
Functional wrapper for try-catch-finally
The newest version!
/*
*Copyright (c) 2015, AEGIS DATA SOLUTIONS, All rights reserved.
*/
package com.aegisql.util.function;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Class ExceptionHandler.
* @author Mikhail Teplitskiy
*
* @param the generic type
*/
public final class ExceptionHandler implements ExceptionBlock {
/** The Constant log. */
public static final Logger log = LoggerFactory.getLogger(ExceptionHandler.class);
/** The exception class. */
private final Class exceptionClass;
/** The registered classes. */
private final Set> registeredClasses = new LinkedHashSet<>();
/** The exception block. */
private final ExceptionBlock exceptionBlock;
/** The terminal flag */
private final boolean isTerminal;
/**
* Instantiates a new exception handler.
*
* @param exceptionClass the exception class
* @param exceptionBlock the exception block
*/
public ExceptionHandler(Class exceptionClass, ExceptionBlock exceptionBlock) {
this.exceptionClass = exceptionClass;
this.exceptionBlock = exceptionBlock;
this.registeredClasses.add(exceptionClass);
this.isTerminal = true;
}
/**
* Instantiates a new exception handler.
*
* @param exceptionClass the exception class
* @param exceptionBlock the exception block
* @param terminal the terminal flag
*/
private ExceptionHandler(Class exceptionClass, ExceptionBlock exceptionBlock, boolean isTerminal) {
this.exceptionClass = exceptionClass;
this.exceptionBlock = exceptionBlock;
this.registeredClasses.add(exceptionClass);
this.isTerminal = false;
}
/* (non-Javadoc)
* @see com.aegisql.util.function.ExceptionBlock#accept(java.lang.Throwable)
*/
@Override
public void accept(T error) throws Throwable {
exceptionBlock.accept(error);
}
/**
* Gets the exception class.
*
* @return the exception class
*/
public Class getExceptionClass() {
return exceptionClass;
}
/**
* Gets the registered exception classes.
*
* @return the registered exception classes
*/
public Set> getRegisteredExceptionClasses() {
return Collections.unmodifiableSet(registeredClasses);
}
/**
* Or catch.
*
* @param the generic type
* @param t2Class the t2 class
* @param eb the eb
* @return the exception handler
*/
public ExceptionHandler orCatch(final Class t2Class,ExceptionBlock eb) {
Objects.requireNonNull(eb);
if(this.registeredClasses.contains(t2Class)) {
throw new RuntimeException("Class already registered: "+t2Class.getName());
}
Class tClass = this.getExceptionClass();
boolean tFo = tClass.isAssignableFrom(t2Class);
boolean oFt = t2Class.isAssignableFrom(tClass);
ExceptionHandler eh = new ExceptionHandler(t2Class,(T2 t)->{
Class> errClass = t.getClass();
boolean tFe = tClass.isAssignableFrom(errClass);
boolean eFt = errClass.isAssignableFrom(tClass);
boolean oFe = t2Class.isAssignableFrom(errClass);
boolean eFo = errClass.isAssignableFrom(t2Class);
log.trace("this:<"+tClass.getSimpleName()+"> other:<"+t2Class.getSimpleName()+"> actual:<"+errClass.getSimpleName()+">");
log.trace("t<->o:{}<->{}; t<->e:{}<->{}; o<->e:{}<->{};",tFo,oFt,tFe,eFt,oFe,eFo);
try {
if(tFe && eFt) {
log.trace("It's this:<{}>",errClass.getSimpleName());
this.accept((T)t);
return;
}
if(oFe && eFo) {
log.trace("It's other:<{}>",errClass.getSimpleName());
eb.accept(t);
return;
}
try {
if(!tFe && !eFt && !isTerminal) {
log.trace("Try <{}> anyway with:<{}>",tClass.getSimpleName(),errClass.getSimpleName());
T ex = (T)t;
this.accept(ex);
return;
}
} catch(Throwable x) {
if(x == t) {
if(!oFe && !eFo) {
log.trace("Try <{}> last time with:<{}>",t2Class.getSimpleName(),errClass.getSimpleName());
eb.accept(t);
return;
}
} else {
throw x;
}
}
T tt = tClass.cast(t);
log.trace("sending to <{}> :<{}>",tClass.getSimpleName(),errClass.getSimpleName());
this.accept(tt);
} catch(ClassCastException t2) {
try {
t2Class.cast(t);
} catch(ClassCastException t4) {
log.trace("give up with <{}>",errClass.getSimpleName());
throw t;
}
log.trace("sending to <{}> :<{}>",t2Class.getSimpleName(),errClass.getSimpleName());
eb.accept(t);
} catch (Throwable t3) {
throw t3;
}
},false);
eh.registeredClasses.addAll(this.registeredClasses);
return eh;
}
/**
* Wrap throwable.
*
* @param the generic type
* @return the function
*/
public static Function,Function> wrapThrowable() {
return wr->thr->{
try {
Constructor con = wr.getConstructor(Throwable.class);
return con.newInstance(thr);
} catch (Exception e) {
throw new RuntimeException("(Throwable) constructor is unavailable for "+wr.getName(),e);
}
};
}
/**
* Wrap commented throwable.
*
* @param the generic type
* @return the function
*/
public static Function,Function>> wrapCommentedThrowable() {
return wr->str->thr->{
try {
Constructor con = wr.getConstructor(String.class,Throwable.class);
return con.newInstance(str,thr);
} catch (Exception e) {
throw new RuntimeException("(String,Throwable) constructor is unavailable for "+wr.getName(),e);
}
};
}
/**
* To string.
*
* @param t the t
* @return the string
*/
public static String toString(Throwable t) {
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
String exceptionAsString = sw.toString();
return exceptionAsString;
}
}