StackTraceFormatter.java

  1. package org.jbehave.core.reporters;

  2. import java.io.ByteArrayOutputStream;
  3. import java.io.PrintStream;
  4. import java.util.regex.Pattern;

  5. import org.jbehave.core.failures.UUIDExceptionWrapper;

  6. public class StackTraceFormatter {
  7.    
  8.     private boolean compressFailureTrace;
  9.    
  10.     public StackTraceFormatter(boolean compressFailureTrace) {
  11.         this.compressFailureTrace = compressFailureTrace;
  12.     }

  13.     public String stackTrace(Throwable cause) {
  14.         if (cause.getClass().getName().equals(UUIDExceptionWrapper.class.getName())) {
  15.             cause = cause.getCause();
  16.         }
  17.         ByteArrayOutputStream out = new ByteArrayOutputStream();
  18.         cause.printStackTrace(new PrintStream(out));
  19.         return stackTrace(out.toString().replaceAll("\r",""));
  20.     }

  21.     protected String stackTrace(String stackTrace) {
  22.         if (!compressFailureTrace) {
  23.             return stackTrace;
  24.         }
  25.         // don't print past certain parts of the stack. Try them even though
  26.         // they may be redundant.
  27.         stackTrace = cutOff(stackTrace, "org.jbehave.core.embedder.");
  28.         stackTrace = cutOff(stackTrace, "org.junit.runners.");
  29.         stackTrace = cutOff(stackTrace, "org.junit.platform.");
  30.         stackTrace = cutOff(stackTrace, "org.apache.maven.surefire.");

  31.         // System.out.println("=====before>" + stackTrace + "<==========");

  32.         // replace whole series of lines with '\t(summary)' The end-user
  33.         // will thank us.
  34.         for (Replacement replacement : REPLACEMENTS) {
  35.             stackTrace = replacement.from.matcher(stackTrace).replaceAll(replacement.to);
  36.         }
  37.         return stackTrace;
  38.     }

  39.     private String cutOff(String stackTrace, String at) {
  40.         if (stackTrace.indexOf(at) > -1) {
  41.             int ix = stackTrace.indexOf(at);
  42.             ix = stackTrace.indexOf("\n", ix);
  43.             if (ix != -1) {
  44.                 stackTrace = stackTrace.substring(0, ix) + "\n...";
  45.             }
  46.         }
  47.         return stackTrace;
  48.     }

  49.     private static class Replacement {
  50.         private final Pattern from;
  51.         private final String to;

  52.         private Replacement(Pattern from, String to) {
  53.             this.from = from;
  54.             this.to = to;
  55.         }
  56.     }

  57.     @SuppressWarnings("checkstyle:LineLength")
  58.     private static Replacement[] REPLACEMENTS = new Replacement[] {
  59.         new Replacement(
  60.                 // JDK 18+
  61.                 Pattern.compile("\\tat java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke\\(DirectMethodHandleAccessor.java:\\d+\\)\\n"
  62.                         + "\\tat java.base/java.lang.reflect.Method.invoke\\(Method.java:\\d+\\)"),
  63.                 "\t(reflection-invoke)"),
  64.         new Replacement(
  65.                 // JDK 9+
  66.                 Pattern.compile("\\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0\\(Native Method\\)\\n"
  67.                         + "\\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke\\(NativeMethodAccessorImpl.java:\\d+\\)\\n"
  68.                         + "\\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke\\(DelegatingMethodAccessorImpl.java:\\d+\\)\\n"
  69.                         + "\\tat java.base/java.lang.reflect.Method.invoke\\(Method.java:\\d+\\)"),
  70.                 "\t(reflection-invoke)"),
  71.         new Replacement(
  72.                 // JDK 1.8
  73.                 Pattern.compile("\\tat sun.reflect.NativeMethodAccessorImpl.invoke0\\(Native Method\\)\\n"
  74.                         + "\\tat sun.reflect.NativeMethodAccessorImpl.invoke\\(NativeMethodAccessorImpl.java:\\d+\\)\\n"
  75.                         + "\\tat sun.reflect.DelegatingMethodAccessorImpl.invoke\\(DelegatingMethodAccessorImpl.java:\\d+\\)\\n"
  76.                         + "\\tat java.lang.reflect.Method.invoke\\(Method.java:\\d+\\)"),
  77.                 "\t(reflection-invoke)"),
  78.         new Replacement(
  79.                 Pattern.compile("\\tat org.codehaus.groovy.reflection.CachedMethod.invoke\\(CachedMethod.java:\\d+\\)\\n"
  80.                         + "\\tat org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod.invoke\\(ClosureMetaMethod.java:\\d+\\)\\n"
  81.                         + "\\tat org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite\\$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke\\(PojoMetaMethodSite.java:\\d+\\)\\n"
  82.                         + "\\tat org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call\\(PojoMetaMethodSite.java:\\d+\\)\\n"
  83.                         + "\\tat org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall\\(CallSiteArray.java:\\d+\\)\\n"
  84.                         + "\\tat org.codehaus.groovy.runtime.callsite.AbstractCallSite.call\\(AbstractCallSite.java:\\d+\\)\\n"
  85.                         + "\\tat org.codehaus.groovy.runtime.callsite.AbstractCallSite.call\\(AbstractCallSite.java:\\d+\\)"),
  86.                 "\t(groovy-closure-invoke)"),
  87.         new Replacement(
  88.                 Pattern.compile("\\tat org.codehaus.groovy.reflection.CachedMethod.invoke\\(CachedMethod.java:\\d+\\)\\n"
  89.                         + "\\tat groovy.lang.MetaMethod.doMethodInvoke\\(MetaMethod.java:\\d+\\)\\n"
  90.                         + "\\tat org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod\\(ClosureMetaClass.java:\\d+\\)\\n"
  91.                         + "\\tat org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnCurrentN\\(ScriptBytecodeAdapter.java:\\d+\\)"),
  92.                 "\t(groovy-instance-method-invoke)"),
  93.         new Replacement(
  94.                 Pattern.compile("\\tat org.codehaus.groovy.reflection.CachedMethod.invoke\\(CachedMethod.java:\\d+\\)\n"
  95.                         + "\\tat org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod.invoke\\(ClosureMetaMethod.java:\\d+\\)\n"
  96.                         + "\\tat org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite\\$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke\\(PojoMetaMethodSite.java:\\d+\\)\n"
  97.                         + "\\tat org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call\\(PojoMetaMethodSite.java:\\d+\\)\n"
  98.                         + "\\tat org.codehaus.groovy.runtime.callsite.AbstractCallSite.call\\(AbstractCallSite.java:\\d+\\)"),
  99.                 "\t(groovy-abstract-method-invoke)"),
  100.         new Replacement(
  101.                 Pattern.compile("\\tat org.codehaus.groovy.reflection.CachedMethod.invoke\\(CachedMethod.java:\\d+\\)\\n"
  102.                         + "\\tat groovy.lang.MetaMethod.doMethodInvoke\\(MetaMethod.java:\\d+\\)\\n"
  103.                         + "\\tat groovy.lang.MetaClassImpl.invokeStaticMethod\\(MetaClassImpl.java:\\d+\\)\\n"
  104.                         + "\\tat org.codehaus.groovy.runtime.InvokerHelper.invokeStaticMethod\\(InvokerHelper.java:\\d+\\)\\n"
  105.                         + "\\tat org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeStaticMethodN\\(ScriptBytecodeAdapter.java:\\d+\\)"),
  106.                 "\t(groovy-static-method-invoke)"),
  107.         new Replacement(
  108.                 Pattern.compile("\\tat sun.reflect.NativeConstructorAccessorImpl.newInstance0\\(Native Method\\)\\n"
  109.                         + "\\tat sun.reflect.NativeConstructorAccessorImpl.newInstance\\(NativeConstructorAccessorImpl.java:\\d+\\)\\n"
  110.                         + "\\tat sun.reflect.DelegatingConstructorAccessorImpl.newInstance\\(DelegatingConstructorAccessorImpl.java:\\d+\\)\\n"
  111.                         + "\\tat java.lang.reflect.Constructor.newInstance\\(Constructor.java:\\d+\\)"),
  112.                 "\t(reflection-construct)"),
  113.         new Replacement(
  114.                 Pattern.compile("\\tat org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(Current|)\\(CallSiteArray.java:\\d+\\)\\n"
  115.                         + "\\tat org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(Current|)\\(AbstractCallSite.java:\\d+\\)\\n"
  116.                         + "\\tat org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(Current|)\\(AbstractCallSite.java:\\d+\\)"

  117.                 ), "\t(groovy-call)"),
  118.         // This one last.
  119.         new Replacement(Pattern.compile("\\t\\(reflection\\-invoke\\)\\n" + "\\t\\(groovy\\-"), "\t(groovy-")
  120.     };

  121. }