Skip to content

Commit 40068b8

Browse files
committed
#827 Remove stacktrace elements from FbExceptionBuilder
1 parent 67df11e commit 40068b8

File tree

3 files changed

+82
-5
lines changed

3 files changed

+82
-5
lines changed

src/docs/asciidoc/release_notes.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ Changes per Jaybird 6 release.
3232
See also <<whats-new-in-jaybird-6>>.
3333
For known issues, consult <<known-issues>>.
3434

35+
=== Jaybird 6.0.0
36+
37+
The following was fixed or changed after 6.0.0-beta-1:
38+
39+
* Improvement: stacktraces produced by `FbExceptionBuilder` no longer include `StackTraceElements` of the builder itself (https://github.com/FirebirdSQL/jaybird/issues/827[#827])
40+
3541
[#jaybird-6-0-0-beta-1-changelog]
3642
=== Jaybird 6.0.0-beta-1
3743

src/main/org/firebirdsql/gds/ng/FbExceptionBuilder.java

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,8 @@ private static CachedMessage getCachedMessage(int errorCode) {
282282
*/
283283
public static SQLException ioWriteError(IOException e) {
284284
CachedMessage error = getCachedMessage(isc_net_write_err);
285-
return new SQLNonTransientConnectionException(error.message, error.sqlState, isc_net_write_err, e);
285+
return stripBuilderStackTraceElements(
286+
new SQLNonTransientConnectionException(error.message, error.sqlState, isc_net_write_err, e));
286287
}
287288

288289
/**
@@ -295,7 +296,8 @@ public static SQLException ioWriteError(IOException e) {
295296
*/
296297
public static SQLException ioReadError(IOException e) {
297298
CachedMessage error = getCachedMessage(isc_net_read_err);
298-
return new SQLNonTransientConnectionException(error.message, error.sqlState, isc_net_read_err, e);
299+
return stripBuilderStackTraceElements(
300+
new SQLNonTransientConnectionException(error.message, error.sqlState, isc_net_read_err, e));
299301
}
300302

301303
/**
@@ -306,7 +308,8 @@ public static SQLException ioReadError(IOException e) {
306308
*/
307309
public static SQLException connectionClosed() {
308310
CachedMessage error = getCachedMessage(jb_connectionClosed);
309-
return new SQLNonTransientConnectionException(error.message, error.sqlState, jb_connectionClosed);
311+
return stripBuilderStackTraceElements(
312+
new SQLNonTransientConnectionException(error.message, error.sqlState, jb_connectionClosed));
310313
}
311314

312315
/**
@@ -600,7 +603,7 @@ public SQLException toFlatSQLException() {
600603
SQLException exception = exceptionType.createSQLException(
601604
fullExceptionMessage.toString(), interestingExceptionInfo.sqlState, interestingExceptionInfo.errorCode);
602605
exception.initCause(chain.getException());
603-
return exception;
606+
return stripBuilderStackTraceElements(exception);
604607
}
605608

606609
private void checkNonEmpty() {
@@ -718,6 +721,58 @@ private void checkExceptionInformation() throws IllegalStateException {
718721
}
719722
}
720723

724+
/**
725+
* Removes the {@link StackTraceElement} from this builder class or its nested classes from {@code exception}.
726+
*
727+
* @param exception
728+
* exception to modify
729+
* @return same object as {@exception} after modification
730+
* @since 6
731+
*/
732+
private static SQLException stripBuilderStackTraceElements(SQLException exception) {
733+
exception.setStackTrace(stripBuilderStackTraceElements(exception.getStackTrace()));
734+
return exception;
735+
}
736+
737+
/**
738+
* Removes the {@link StackTraceElement} from this builder class or its nested classes from
739+
* {@code stackTraceElements}.
740+
*
741+
* @param stackTraceElements
742+
* original stacktrace elements
743+
* @return new array of {@link StackTraceElement} with the elements of this builder class or its nested classes
744+
* removed (original array if there were no such elements, or all elements are from this builder class)
745+
* @since 6
746+
*/
747+
private static StackTraceElement[] stripBuilderStackTraceElements(StackTraceElement[] stackTraceElements) {
748+
int startIndex = findFirstNonBuilderElement(stackTraceElements);
749+
// No elements or all elements from this class, return original.
750+
// This is unlikely to happen in practice, unless this method is called multiple times on the same exception
751+
if (startIndex <= 0) return stackTraceElements;
752+
return Arrays.copyOfRange(stackTraceElements, startIndex, stackTraceElements.length);
753+
}
754+
755+
/**
756+
* Finds the first {@link StackTraceElement} that was not produced by this builder class or its nested classes.
757+
*
758+
* @param stackTraceElements
759+
* stacktrace elements to search
760+
* @return position of first element that was not produce by this builder class or its nested classes, {@code -1} if
761+
* all elements are from this builder class
762+
* @since 6
763+
*/
764+
private static int findFirstNonBuilderElement(StackTraceElement[] stackTraceElements) {
765+
final String thisClassName = FbExceptionBuilder.class.getName();
766+
final String nestedClassPrefix = thisClassName + "$";
767+
for (int idx = 0; idx < stackTraceElements.length; idx++) {
768+
String className = stackTraceElements[idx].getClassName();
769+
if (!className.equals(thisClassName) && !className.startsWith(nestedClassPrefix)) {
770+
return idx;
771+
}
772+
}
773+
return -1;
774+
}
775+
721776
private static final class ExceptionInformation {
722777
private final Type type;
723778
private final List<String> messageParameters = new ArrayList<>();
@@ -793,7 +848,7 @@ SQLException toSQLException() {
793848
if (cause != null) {
794849
result.initCause(cause);
795850
}
796-
return result;
851+
return stripBuilderStackTraceElements(result);
797852
}
798853

799854
FBSQLExceptionInfo toSQLExceptionInfo() {

src/test/org/firebirdsql/gds/ng/FbExceptionBuilderTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,22 @@ void exceptionTypeUpgrade_EXCEPTION_to_NON_TRANSIENT() {
307307
"Expected result to be SQLInvalidAuthorizationSpecException (no subclass!)");
308308
}
309309

310+
@Test
311+
void toSQLExceptionStripsBuilderStackTraceElements() {
312+
SQLException result = FbExceptionBuilder.forException(isc_login).toSQLException();
313+
314+
assertEquals(getClass().getName(), result.getStackTrace()[0].getClassName(),
315+
"Expected first StackTraceElement to be from this class");
316+
}
317+
318+
@Test
319+
void toFlatSQLExceptionStripsBuilderStackTraceElements() {
320+
SQLException result = FbExceptionBuilder.forException(isc_login).toFlatSQLException();
321+
322+
assertEquals(getClass().getName(), result.getStackTrace()[0].getClassName(),
323+
"Expected first StackTraceElement to be from this class");
324+
}
325+
310326
/**
311327
* Helper method to assert exception for an uninitialized exception type.
312328
*/

0 commit comments

Comments
 (0)