io.datarouter.exception.utils.ExceptionDetailsDetector Maven / Gradle / Ivy
The newest version!
/*
* Copyright © 2009 HotPads ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.datarouter.exception.utils;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import io.datarouter.exception.utils.nameparser.ExceptionNameParser;
import io.datarouter.exception.utils.nameparser.ExceptionNameParserRegistry;
import io.datarouter.exception.utils.nameparser.ExceptionSnapshot;
import io.datarouter.exception.utils.nameparser.ExceptionSnapshot.ExceptionCauseSnapshot;
import io.datarouter.exception.utils.nameparser.ExceptionSnapshot.StackTraceElementSnapshot;
import io.datarouter.inject.DatarouterInjector;
import io.datarouter.scanner.Scanner;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
@Singleton
public class ExceptionDetailsDetector{
@Inject
private ExceptionNameParserRegistry registry;
@Inject
private DatarouterInjector injector;
public ExceptionRecorderDetails detect(Throwable wholeException, String callOrigin, Set highlights){
return detect(new ExceptionSnapshot(wholeException), callOrigin, highlights);
}
public ExceptionRecorderDetails detect(ExceptionSnapshot snapshot, String callOrigin, Set highlights){
Optional rootCause = snapshot.getRootCause();
Optional parsedName = Optional.empty();
Optional parserAndCauseOpt = Scanner.of(registry
.getNameParserClasses())
.map(injector::getInstance)
.map(ExceptionNameParser.class::cast)
.concatOpt(parser -> parser.getCausesFromType(snapshot)
.map(cause -> new ExceptionParserAndOutput(parser, cause)))
.findFirst();
if(parserAndCauseOpt.isPresent()){
var parserAndCause = parserAndCauseOpt.get();
rootCause = Optional.of(parserAndCause.output().getFirst());
ExceptionNameParser exceptionWithParser = parserAndCause.parser();
parsedName = exceptionWithParser.parseExceptionName(parserAndCause.output());
}
ExceptionCauseSnapshot exception = rootCause
.orElse(new ExceptionCauseSnapshot(null, null, null, List.of()));
Optional stackTraceElement = searchClassName(exception, highlights);
if(stackTraceElement.isEmpty()){
stackTraceElement = exception.stackTraces.stream()
.findFirst();
}
return new ExceptionRecorderDetails(exception, stackTraceElement, parsedName, callOrigin);
}
private static Optional searchClassName(ExceptionCauseSnapshot cause,
Set highlights){
return Scanner.of(cause.stackTraces)
.include(element -> Scanner.of(highlights)
.anyMatch(element.declaringClass::contains))
.findFirst();
}
public record ExceptionParserAndOutput(
ExceptionNameParser parser,
List output){
}
public static class ExceptionRecorderDetails{
public final String className;
public final String methodName;
public final String type;
public final int lineNumber;
public final String detailsMessage;
public final String parsedName;
private ExceptionRecorderDetails(ExceptionCauseSnapshot rootCause, Optional element,
Optional parsedName, String callOrigin){
this.className = element.map(e -> e.declaringClass).orElse("noClass");
this.methodName = element.map(e -> e.methodName).orElse("noMethod");
this.type = rootCause.typeName;
this.lineNumber = element.map(e -> e.lineNumber).orElse(0);
this.detailsMessage = rootCause.detailMessage;
this.parsedName = parsedName.orElse(getDefaultName(type, className, callOrigin));
}
public static String getDefaultName(String type, String className, String callOrigin){
callOrigin = Optional.ofNullable(callOrigin).orElse(className);
return String.format("%s at %s in %s", getSimpleClassName(type), getSimpleClassName(className),
getSimpleClassName(callOrigin));
}
private static String getSimpleClassName(String fullClassName){
return Optional.ofNullable(fullClassName)
.map(ExceptionRecorderDetails::parseName)
.orElse("");
}
private static String parseName(String fullClassName){
String[] tokens = fullClassName.split("\\.");
if(tokens.length < 2){
return fullClassName;
}else if(Character.isUpperCase(tokens[tokens.length - 1].charAt(0))){
return tokens[tokens.length - 1];
}else{
return tokens[tokens.length - 2] + "." + tokens[tokens.length - 1];
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy