93 lines
4.1 KiB
Java
93 lines
4.1 KiB
Java
package io.gitlab.jfronny.commons;
|
|
|
|
import java.util.*;
|
|
import java.util.function.Function;
|
|
|
|
public class StringFormatter {
|
|
public static String toString(Object o) {
|
|
if (o == null) return "null";
|
|
else if (o instanceof Double d) return toString((double) d);
|
|
else if (o instanceof Float f) return toString((float) f);
|
|
else if (o instanceof Throwable t) return toString(t, Objects::toString);
|
|
else if (o.getClass().isArray()) return arrayToString(o);
|
|
else return o.toString();
|
|
}
|
|
|
|
public static String toString(double d) {
|
|
double abs = Math.abs(d);
|
|
if (abs >= 1000 || abs % 1.0 == 0) return String.format(Locale.US, "%.0f", d);
|
|
else if (abs >= 0.1) return String.format(Locale.US, "%.4f", d);
|
|
else return toStringPrecise(d);
|
|
}
|
|
|
|
public static String toStringPrecise(double d) {
|
|
if (d % 1.0 == 0) return String.format(Locale.US, "%.0f", d);
|
|
else return String.format(Locale.US, "%s", d);
|
|
}
|
|
|
|
public static String toString(float f) {
|
|
float abs = Math.abs(f);
|
|
if (abs >= 1000 || abs % 1.0 == 0) return String.format(Locale.US, "%.0f", f);
|
|
else if (abs >= 0.1f) return String.format(Locale.US, "%.4f", f);
|
|
else return toStringPrecise(f);
|
|
}
|
|
|
|
public static String toStringPrecise(float f) {
|
|
if (f % 1.0f == 0) return String.format(Locale.US, "%.0f", f);
|
|
else return String.format(Locale.US, "%s", f);
|
|
}
|
|
|
|
public static String toString(Throwable t, Function<Throwable, String> stringify) {
|
|
return stringify.apply(t) + "\n" + getStackTrace(t, stringify);
|
|
}
|
|
|
|
public static String getStackTrace(Throwable t) {
|
|
return getStackTrace(t, Objects::toString);
|
|
}
|
|
|
|
public static String getStackTrace(Throwable t, Function<Throwable, String> stringify) {
|
|
StringBuilder sb = new StringBuilder();
|
|
getStackTrace(sb, t, new StackTraceElement[0], "", "", Objects.requireNonNull(stringify), new HashSet<>(), true);
|
|
return sb.toString();
|
|
}
|
|
|
|
private static void getStackTrace(StringBuilder sb, Throwable t, StackTraceElement[] enclosingTrace, String caption, String prefix, Function<Throwable, String> stringify, Set<Throwable> dejaVu, boolean skipHeader) {
|
|
if (!skipHeader) sb.append(prefix).append(caption);
|
|
|
|
if (!dejaVu.add(t)) {
|
|
sb.append("[CIRCULAR REFERENCE: ").append(stringify.apply(t)).append("]\n");
|
|
return;
|
|
}
|
|
|
|
StackTraceElement[] trace = t.getStackTrace();
|
|
int m = trace.length - 1;
|
|
int n = enclosingTrace.length - 1;
|
|
while (m >= 0 && n >= 0 && trace[m].equals(enclosingTrace[n])) {
|
|
m--; n--;
|
|
}
|
|
int framesInCommon = trace.length - 1 - m;
|
|
|
|
if (!skipHeader) sb.append(stringify.apply(t)).append('\n');
|
|
for (int i = 0; i <= m; i++) sb.append(prefix).append("\tat ").append(trace[i]).append('\n');
|
|
if (framesInCommon != 0) sb.append(prefix).append("\t... ").append(framesInCommon).append(" more").append('\n');
|
|
for (Throwable se : t.getSuppressed()) {
|
|
getStackTrace(sb, se, trace, "Suppressed: ", prefix + "\t", stringify, dejaVu, false);
|
|
}
|
|
Throwable cause = t.getCause();
|
|
if (cause != null) getStackTrace(sb, cause, trace, "Caused by: ", prefix, stringify, dejaVu, false);
|
|
}
|
|
|
|
private static String arrayToString(Object array) {
|
|
if (array instanceof boolean[] o) return Arrays.toString(o);
|
|
else if (array instanceof byte[] o) return Arrays.toString(o);
|
|
else if (array instanceof char[] o) return Arrays.toString(o);
|
|
else if (array instanceof short[] o) return Arrays.toString(o);
|
|
else if (array instanceof int[] o) return Arrays.toString(o);
|
|
else if (array instanceof long[] o) return Arrays.toString(o);
|
|
else if (array instanceof float[] o) return Arrays.toString(o);
|
|
else if (array instanceof double[] o) return Arrays.toString(o);
|
|
else if (array instanceof Object[] o) return Arrays.toString(o);
|
|
else return array.toString(); // unknown array type
|
|
}
|
|
}
|