java-commons/commons/src/main/java/io/gitlab/jfronny/commons/StringFormatter.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
}
}