private static ThrowableInfoParseResult parse( List<String> throwableInfoLines, int startIndex, int indent) { // sorry, future huxi final int lineCount = throwableInfoLines.size(); String name = null; StringBuilder message = null; List<ExtendedStackTraceElement> stackTraceElements = null; int omittedElements = 0; ThrowableInfo cause = null; List<ThrowableInfo> suppressedInfos = null; int index = startIndex; for (; index < lineCount; index++) { String currentLine = throwableInfoLines.get(index); Matcher atMatcher = atMatcher(currentLine); if (atMatcher.matches()) { String indentString = atMatcher.group(1); if (indentString.length() != indent + 1) { // we reached wrong nesting... break; } String steString = atMatcher.group(2); ExtendedStackTraceElement este = ExtendedStackTraceElement.parseStackTraceElement(steString); if (este != null) { if (stackTraceElements == null) { stackTraceElements = new ArrayList<ExtendedStackTraceElement>(); } stackTraceElements.add(este); } continue; } Matcher omittedMatcher = omittedMatcher(currentLine); if (omittedMatcher.matches()) { String indentString = omittedMatcher.group(1); if (indentString.length() != indent + 1) { // we reached wrong nesting... break; } omittedElements = Integer.parseInt(omittedMatcher.group(2)); continue; } Matcher messageMatcher = messageMatcher(currentLine); // will always match... if (messageMatcher.matches()) { String indentString = messageMatcher.group(1); String type = messageMatcher.group(2); // either CAUSED_BY_PREFIX, SUPPRESSED_PREFIX or null String remainder = messageMatcher.group(3); // remainder of the String if (ThrowableInfo.CAUSED_BY_PREFIX.equals(type)) { if (index != startIndex) { if (indentString.length() != indent) { // we reached wrong nesting... break; } ThrowableInfoParseResult parsed = parse(throwableInfoLines, index, indent); index = parsed.endIndex - 1; if (parsed.throwableInfo != null) { cause = parsed.throwableInfo; } continue; } } else if (ThrowableInfo.SUPPRESSED_PREFIX.equals(type)) { if (index != startIndex) { if (indentString.length() != indent + 1) { // we reached wrong nesting... break; } ThrowableInfoParseResult parsed = parse(throwableInfoLines, index, indent + 1); index = parsed.endIndex - 1; if (parsed.throwableInfo != null) { if (suppressedInfos == null) { suppressedInfos = new ArrayList<ThrowableInfo>(); } suppressedInfos.add(parsed.throwableInfo); } continue; } } if (message == null) { // first line int colonIndex = remainder.indexOf(CLASS_MESSAGE_SEPARATOR); if (colonIndex > -1) { name = remainder.substring(0, colonIndex); message = new StringBuilder(); message.append(remainder.substring(colonIndex + CLASS_MESSAGE_SEPARATOR.length())); } else { name = remainder; } } else { message.append(NEWLINE); if (indentString != null) { message.append(indentString); } message.append(remainder); } } else { System.out.println("What? " + currentLine); } } ThrowableInfo throwableInfo = null; if (name != null || message != null || stackTraceElements != null || omittedElements != 0 || cause != null || suppressedInfos != null) { // we found *any* info... throwableInfo = new ThrowableInfo(); throwableInfo.setName(name); if (message != null) { throwableInfo.setMessage(message.toString()); } if (stackTraceElements != null) { throwableInfo.setStackTrace( stackTraceElements.toArray(new ExtendedStackTraceElement[stackTraceElements.size()])); } throwableInfo.setOmittedElements(omittedElements); throwableInfo.setCause(cause); if (suppressedInfos != null) { throwableInfo.setSuppressed( suppressedInfos.toArray(new ThrowableInfo[suppressedInfos.size()])); } } return new ThrowableInfoParseResult(throwableInfo, index); }