From d99fa113977a59523339ceda5d0da0d04f5aaef4 Mon Sep 17 00:00:00 2001 From: Colin Alworth Date: Fri, 19 Jul 2024 16:01:50 -0500 Subject: [PATCH] refactor!: Rearrange TypeUtils and ArrayTypeUtils so they can be shared with JS API (#5780) Removed some unused methods, rewrote some implementations to avoid reflection where unnecessary, removed ObjectInputStream/ObjectOutputStream usage. BREAKING CHANGES: Moved isBoxedNumeric, isNumeric, isBigNumeric to NumericTypeUtils, removed @IsDateTime, removed other reflective methods from TypeUtils and ArrayTypeUtils. Partial #188 --- .../java/io/deephaven/gen/JavaFunction.java | 99 +++++- .../plot/util/ArgumentValidations.java | 48 +-- .../deephaven/util/type/ArrayTypeUtils.java | 236 ++++---------- .../deephaven/util/type/NumericTypeUtils.java | 54 ++++ .../io/deephaven/util/type/TypeUtils.java | 292 +----------------- .../table/impl/by/AggregationProcessor.java | 2 +- .../impl/preview/ColumnPreviewManager.java | 8 +- .../engine/util/TestNumericTypeUtils.java | 34 ++ .../deephaven/engine/util/TestTypeUtils.java | 21 -- .../extensions/barrage/util/BarrageUtil.java | 2 +- .../table/ops/ColumnStatisticsGrpcImpl.java | 21 +- 11 files changed, 280 insertions(+), 537 deletions(-) create mode 100644 Util/src/main/java/io/deephaven/util/type/NumericTypeUtils.java create mode 100644 engine/table/src/test/java/io/deephaven/engine/util/TestNumericTypeUtils.java diff --git a/Generators/src/main/java/io/deephaven/gen/JavaFunction.java b/Generators/src/main/java/io/deephaven/gen/JavaFunction.java index c8b10db53cf..2f4639f0a80 100644 --- a/Generators/src/main/java/io/deephaven/gen/JavaFunction.java +++ b/Generators/src/main/java/io/deephaven/gen/JavaFunction.java @@ -3,20 +3,24 @@ // package io.deephaven.gen; -import io.deephaven.util.type.TypeUtils; import org.jetbrains.annotations.NotNull; import java.lang.reflect.Method; import java.lang.reflect.Parameter; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; import java.util.logging.Logger; /** * A Java function description for use in code generation. - * + *

* JavaFunctions are equal if they have the same method names and parameter types. */ public class JavaFunction implements Comparable { @@ -147,13 +151,102 @@ public Class getReturnClass() { } try { - return TypeUtils.getErasedType(returnType); + return getErasedType(returnType); } catch (UnsupportedOperationException e) { log.warning("Unable to determine Class from returnType=" + returnType.getTypeName()); return null; } } + /** + * Determine the Class from the Type. + */ + private static Class getErasedType(Type paramType) { + if (paramType instanceof Class) { + return (Class) paramType; + } else if (paramType instanceof ParameterizedType) { + return (Class) // We are asking the parameterized type for its raw type, which is always Class + ((ParameterizedType) paramType).getRawType(); + } else if (paramType instanceof WildcardType) { + final Type[] upper = ((WildcardType) paramType).getUpperBounds(); + return getErasedType(upper[0]); + } else if (paramType instanceof java.lang.reflect.TypeVariable) { + final Type[] bounds = ((TypeVariable) paramType).getBounds(); + if (bounds.length > 1) { + Class[] erasedBounds = new Class[bounds.length]; + Class weakest = null; + for (int i = 0; i < erasedBounds.length; i++) { + erasedBounds[i] = getErasedType(bounds[i]); + if (i == 0) { + weakest = erasedBounds[i]; + } else { + weakest = getWeakest(weakest, erasedBounds[i]); + } + // If we are erased to object, stop erasing... + if (weakest == Object.class) { + break; + } + } + return weakest; + } + return getErasedType(bounds[0]); + } else { + throw new UnsupportedOperationException(); + } + } + + /** + * Determine the weakest parent of the two provided Classes. + * + * @param one one class to compare + * @param two the other class to compare + * @return the weakest parent Class + */ + private static Class getWeakest(Class one, Class two) { + if (one.isAssignableFrom(two)) { + return one; + } else if (two.isAssignableFrom(one)) { + return two; + } + // No luck on quick check... Look in interfaces. + Set> oneInterfaces = getFlattenedInterfaces(one); + Set> twoInterfaces = getFlattenedInterfaces(two); + // Keep only shared interfaces + oneInterfaces.retainAll(twoInterfaces); + Class strongest = Object.class; + for (Class cls : oneInterfaces) { + // There is a winning type... + if (strongest.isAssignableFrom(cls)) { + strongest = cls; + } else if (!cls.isAssignableFrom(strongest)) { + return Object.class; + } + } + // Will be Object.class if there were no shared interfaces (or shared interfaces were not compatible). + return strongest; + } + + private static Set> getFlattenedInterfaces(Class cls) { + final Set> set = new HashSet<>(); + while (cls != null && cls != Object.class) { + for (Class iface : cls.getInterfaces()) { + collectInterfaces(set, iface); + } + cls = cls.getSuperclass(); + } + return set; + } + + private static void collectInterfaces(final Collection> into, final Class cls) { + if (into.add(cls)) { + for (final Class iface : cls.getInterfaces()) { + if (into.add(iface)) { + collectInterfaces(into, iface); + } + } + } + } + public Type[] getParameterTypes() { return parameterTypes; } diff --git a/Plot/src/main/java/io/deephaven/plot/util/ArgumentValidations.java b/Plot/src/main/java/io/deephaven/plot/util/ArgumentValidations.java index f23c4c28920..c1fe62ead63 100644 --- a/Plot/src/main/java/io/deephaven/plot/util/ArgumentValidations.java +++ b/Plot/src/main/java/io/deephaven/plot/util/ArgumentValidations.java @@ -4,7 +4,6 @@ package io.deephaven.plot.util; import io.deephaven.base.verify.Require; -import io.deephaven.base.verify.RequirementFailure; import io.deephaven.configuration.Configuration; import io.deephaven.engine.table.ColumnDefinition; import io.deephaven.plot.datasets.data.IndexableNumericData; @@ -13,6 +12,7 @@ import io.deephaven.plot.util.tables.TableHandle; import io.deephaven.engine.table.Table; import io.deephaven.engine.table.TableDefinition; +import io.deephaven.util.type.NumericTypeUtils; import io.deephaven.util.type.TypeUtils; import org.apache.commons.lang3.ClassUtils; @@ -362,24 +362,24 @@ public static boolean isTime(final Class c, final PlotInfo plotInfo) { } /** - * Whether the class is {@link TypeUtils#isNumeric(Class)} or {@link #isTime(Class, PlotInfo)} + * Whether the class is {@link NumericTypeUtils#isNumeric(Class)} or {@link #isTime(Class, PlotInfo)} * * @param c class * @return true if {@code c} is a numeric or time class, false otherwise */ public static boolean isNumericOrTime(final Class c) { - return TypeUtils.isNumeric(c) || isTime(c, null); + return NumericTypeUtils.isNumeric(c) || isTime(c, null); } /** - * Whether the class is {@link TypeUtils#isNumeric(Class)} or {@link #isTime(Class, PlotInfo)} + * Whether the class is {@link NumericTypeUtils#isNumeric(Class)} or {@link #isTime(Class, PlotInfo)} * * @param c class * @param plotInfo source of the exception * @return true if {@code c} is a numeric or time class, false otherwise */ public static boolean isNumericOrTime(final Class c, final PlotInfo plotInfo) { - return TypeUtils.isNumeric(c) || isTime(c, plotInfo); + return NumericTypeUtils.isNumeric(c) || isTime(c, plotInfo); } /** @@ -419,7 +419,7 @@ public static boolean isTime(final SelectableDataSet sds, final String column, f } /** - * Whether the column's data type {@link TypeUtils#isPrimitiveNumeric(Class)}. + * Whether the column's data type {@link NumericTypeUtils#isPrimitiveNumeric(Class)}. * * @param t table * @param column column @@ -428,11 +428,11 @@ public static boolean isTime(final SelectableDataSet sds, final String column, f */ public static boolean isPrimitiveNumeric(final Table t, final String column, final PlotInfo plotInfo) { assertNotNull(t, "t", plotInfo); - return TypeUtils.isPrimitiveNumeric(getColumnType(t, column, plotInfo)); + return NumericTypeUtils.isPrimitiveNumeric(getColumnType(t, column, plotInfo)); } /** - * Whether the column's data type {@link TypeUtils#isBoxedNumeric(Class)}. + * Whether the column's data type {@link NumericTypeUtils#isBoxedNumeric(Class)}. * * @param t table * @param column column @@ -441,11 +441,11 @@ public static boolean isPrimitiveNumeric(final Table t, final String column, fin */ public static boolean isBoxedNumeric(final Table t, final String column, final PlotInfo plotInfo) { assertNotNull(t, "t", plotInfo); - return TypeUtils.isBoxedNumeric(getColumnType(t, column, plotInfo)); + return NumericTypeUtils.isBoxedNumeric(getColumnType(t, column, plotInfo)); } /** - * Whether the column's data type {@link TypeUtils#isNumeric(Class)}. + * Whether the column's data type {@link NumericTypeUtils#isNumeric(Class)}. * * @param t table * @param column column @@ -454,11 +454,11 @@ public static boolean isBoxedNumeric(final Table t, final String column, final P */ public static boolean isNumeric(final Table t, final String column, final PlotInfo plotInfo) { assertNotNull(t, "t", plotInfo); - return TypeUtils.isNumeric(getColumnType(t, column, plotInfo)); + return NumericTypeUtils.isNumeric(getColumnType(t, column, plotInfo)); } /** - * Whether the column's data type {@link TypeUtils#isNumeric(Class)}. + * Whether the column's data type {@link NumericTypeUtils#isNumeric(Class)}. * * @param t table * @param column column @@ -467,11 +467,11 @@ public static boolean isNumeric(final Table t, final String column, final PlotIn */ public static boolean isNumeric(final TableDefinition t, final String column, final PlotInfo plotInfo) { assertNotNull(t, "t", plotInfo); - return TypeUtils.isNumeric(getColumnType(t, column, plotInfo)); + return NumericTypeUtils.isNumeric(getColumnType(t, column, plotInfo)); } /** - * Whether the column's data type {@link TypeUtils#isNumeric(Class)}. + * Whether the column's data type {@link NumericTypeUtils#isNumeric(Class)}. * * @param sds selectable dataset * @param column column @@ -480,7 +480,7 @@ public static boolean isNumeric(final TableDefinition t, final String column, fi */ public static boolean isNumeric(final SelectableDataSet sds, final String column, final PlotInfo plotInfo) { assertNotNull(sds, "t", plotInfo); - return TypeUtils.isNumeric(getColumnType(sds, column, plotInfo)); + return NumericTypeUtils.isNumeric(getColumnType(sds, column, plotInfo)); } /** @@ -583,7 +583,7 @@ public static void assertIsTime(final TableDefinition t, final String column, fi /** * Requires the column's data type to be a numeric primitive as defined in - * {@link TypeUtils#isPrimitiveNumeric(Class)} + * {@link NumericTypeUtils#isPrimitiveNumeric(Class)} * * @throws RuntimeException if the column's data type isn't a numeric primitive * @param t table @@ -598,7 +598,7 @@ public static void assertIsPrimitiveNumeric(final Table t, final String column, /** * Requires the column's data type to be a numeric primitive as defined in - * {@link TypeUtils#isPrimitiveNumeric(Class)} + * {@link NumericTypeUtils#isPrimitiveNumeric(Class)} * * @throws RuntimeException if the column's data type isn't a numeric primitive * @param t table @@ -616,7 +616,7 @@ public static void assertIsPrimitiveNumeric(final Table t, final String column, /** * Requires the column's data type to be an instance of {@link Number} as defined in - * {@link TypeUtils#isBoxedNumeric(Class)} + * {@link NumericTypeUtils#isBoxedNumeric(Class)} * * @throws RuntimeException if the column's data type isn't an instance of {@link Number} * @param t table @@ -631,7 +631,7 @@ public static void assertIsBoxedNumeric(final Table t, final String column, fina /** * Requires the column's data type to be an instance of {@link Number} as defined in - * {@link TypeUtils#isBoxedNumeric(Class)} + * {@link NumericTypeUtils#isBoxedNumeric(Class)} * * @throws RuntimeException if the column's data type isn't an instance of {@link Number} * @param t table @@ -649,7 +649,7 @@ public static void assertIsBoxedNumeric(final Table t, final String column, fina /** - * Requires the column's data type to be a numeric instance as defined in {@link TypeUtils#isNumeric(Class)} + * Requires the column's data type to be a numeric instance as defined in {@link NumericTypeUtils#isNumeric(Class)} * * @throws PlotRuntimeException if the column's data type isn't a numeric instance * @param t table @@ -663,7 +663,7 @@ public static void assertIsNumeric(final Table t, final String column, final Plo /** - * Requires the column's data type to be a numeric instance as defined in {@link TypeUtils#isNumeric(Class)} + * Requires the column's data type to be a numeric instance as defined in {@link NumericTypeUtils#isNumeric(Class)} * * @throws PlotRuntimeException if the column's data type isn't a numeric instance * @param t table @@ -677,7 +677,7 @@ public static void assertIsNumeric(final TableDefinition t, final String column, /** - * Requires the column's data type to be a numeric instance as defined in {@link TypeUtils#isNumeric(Class)} + * Requires the column's data type to be a numeric instance as defined in {@link NumericTypeUtils#isNumeric(Class)} * * @throws PlotRuntimeException if the column's data type isn't a numeric instance * @param t table @@ -695,7 +695,7 @@ public static void assertIsNumeric(final Table t, final String column, final Str /** - * Requires the column's data type to be a numeric instance as defined in {@link TypeUtils#isNumeric(Class)} + * Requires the column's data type to be a numeric instance as defined in {@link NumericTypeUtils#isNumeric(Class)} * * @throws PlotRuntimeException if the column's data type isn't a numeric instance * @param t table @@ -713,7 +713,7 @@ public static void assertIsNumeric(final TableDefinition t, final String column, /** - * Requires the column's data type to be a numeric instance as defined in {@link TypeUtils#isNumeric(Class)} + * Requires the column's data type to be a numeric instance as defined in {@link NumericTypeUtils#isNumeric(Class)} * * @throws PlotRuntimeException if the column's data type isn't a numeric instance * @param sds selectable dataset diff --git a/Util/src/main/java/io/deephaven/util/type/ArrayTypeUtils.java b/Util/src/main/java/io/deephaven/util/type/ArrayTypeUtils.java index cacf6adc239..748032914ae 100644 --- a/Util/src/main/java/io/deephaven/util/type/ArrayTypeUtils.java +++ b/Util/src/main/java/io/deephaven/util/type/ArrayTypeUtils.java @@ -5,11 +5,7 @@ import io.deephaven.base.verify.Require; -import java.lang.reflect.Array; import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; import static io.deephaven.util.QueryConstants.*; @@ -31,52 +27,25 @@ public class ArrayTypeUtils { public static final String[][] EMPTY_STRING_ARRAY_ARRAY = new String[0][]; public static final Boolean[] EMPTY_BOOLEANBOXED_ARRAY = new Boolean[0]; - public static ArrayAccessor getArrayAccessor(Object array) { - final Class c = array.getClass(); - if (c.equals(Boolean[].class)) { + public static ArrayAccessor getArrayAccessor(Object array) { + if (array instanceof Boolean[]) { return new BooleanArrayAccessor((Boolean[]) array); - } else if (c.equals(byte[].class)) { + } else if (array instanceof byte[]) { return new ByteArrayAccessor((byte[]) array); - } else if (c.equals(char[].class)) { + } else if (array instanceof char[]) { return new CharArrayAccessor((char[]) array); - } else if (c.equals(double[].class)) { + } else if (array instanceof double[]) { return new DoubleArrayAccessor((double[]) array); - } else if (c.equals(float[].class)) { + } else if (array instanceof float[]) { return new FloatArrayAccessor((float[]) array); - } else if (c.equals(int[].class)) { + } else if (array instanceof int[]) { return new IntArrayAccessor((int[]) array); - } else if (c.equals(long[].class)) { + } else if (array instanceof long[]) { return new LongArrayAccessor((long[]) array); - } else if (c.equals(short[].class)) { + } else if (array instanceof short[]) { return new ShortArrayAccessor((short[]) array); } else { - return new ObjectArrayAccessor((Object[]) array); - } - } - - public static ArrayAccessor createArrayAccessor(Object element, int size) { - if (element == null) { - return new ObjectArrayAccessor(new Object[size]); - } - final Class c = element.getClass(); - if (c.equals(boolean.class) || c.equals(Boolean.class)) { - return new BooleanArrayAccessor(booleanNullArray(size)); - } else if (c.equals(byte.class) || c.equals(Byte.class)) { - return new ByteArrayAccessor(byteNullArray(size)); - } else if (c.equals(char.class) || c.equals(Character.class)) { - return new CharArrayAccessor(charNullArray(size)); - } else if (c.equals(double.class) || c.equals(Double.class)) { - return new DoubleArrayAccessor(doubleNullArray(size)); - } else if (c.equals(float.class) || c.equals(Float.class)) { - return new FloatArrayAccessor(floatNullArray(size)); - } else if (c.equals(int.class) || c.equals(Integer.class)) { - return new IntArrayAccessor(intNullArray(size)); - } else if (c.equals(long.class) || c.equals(Long.class)) { - return new LongArrayAccessor(longNullArray(size)); - } else if (c.equals(short.class) || c.equals(Short.class)) { - return new ShortArrayAccessor(shortNullArray(size)); - } else { - return new ObjectArrayAccessor((Object[]) Array.newInstance(c, size)); + return new ObjectArrayAccessor<>((Object[]) array); } } @@ -128,99 +97,6 @@ public static short[] shortNullArray(int size) { return result; } - public static Object toArray(Collection objects, Class elementType) { - if (elementType == boolean.class) { - elementType = Boolean.class; - } - Object result = Array.newInstance(elementType, objects.size()); - ArrayAccessor accessor = getArrayAccessor(result); - int i = 0; - for (Object object : objects) { - accessor.set(i++, object); - } - return result; - } - - public static Object boxedToPrimitive(Set objects, Class type) { - Iterator it = objects.iterator(); - if (objects.isEmpty()) { - Class primitiveType = io.deephaven.util.type.TypeUtils.getUnboxedType(type); - if (primitiveType == null) { - return Array.newInstance(type, 0); - } else { - return Array.newInstance(primitiveType, 0); - } - } - Object current = it.next(); - ArrayAccessor resultAccessor = createArrayAccessor(current, objects.size()); - int i = 0; - resultAccessor.set(i++, current); - while (it.hasNext()) { - current = it.next(); - resultAccessor.set(i++, current); - } - return resultAccessor.getArray(); - } - - public static ArrayAccessor getArrayAccessorFromArray(Object arrayPrototype, int size) { - final Class c = arrayPrototype.getClass(); - if (c.equals(boolean[].class)) { - return new BooleanArrayAccessor(booleanNullArray(size)); - } else if (c.equals(byte[].class)) { - return new ByteArrayAccessor(byteNullArray(size)); - } else if (c.equals(char[].class)) { - return new CharArrayAccessor(charNullArray(size)); - } else if (c.equals(double[].class)) { - return new DoubleArrayAccessor(doubleNullArray(size)); - } else if (c.equals(float[].class)) { - return new FloatArrayAccessor(floatNullArray(size)); - } else if (c.equals(int[].class)) { - return new IntArrayAccessor(intNullArray(size)); - } else if (c.equals(long[].class)) { - return new LongArrayAccessor(longNullArray(size)); - } else if (c.equals(short[].class)) { - return new ShortArrayAccessor(shortNullArray(size)); - } else { - return new ObjectArrayAccessor((Object[]) Array.newInstance(c.getComponentType(), size)); - } - } - - public static Object toArray(Collection objects) { - if (objects.size() == 0) { - return toArray(objects, Object.class); - } - Object prototype = objects.iterator().next(); - if (prototype == null) { - return toArray(objects, Object.class); - } - Class ubType = TypeUtils.getUnboxedType(prototype.getClass()); - - return toArray(objects, (ubType == null ? prototype.getClass() : ubType)); - } - - public static ArrayAccessor getAccessorForElementType(Class componentType, int size) { - if (componentType.equals(boolean.class) || componentType.equals(Boolean.class)) { - return new BooleanArrayAccessor(booleanNullArray(size)); - } else if (componentType.equals(byte.class) || componentType.equals(Byte.class)) { - return new ByteArrayAccessor(byteNullArray(size)); - } else if (componentType.equals(char.class) || componentType.equals(Character.class)) { - return new CharArrayAccessor(charNullArray(size)); - } else if (componentType.equals(double.class) || componentType.equals(Double.class)) { - return new DoubleArrayAccessor(doubleNullArray(size)); - } else if (componentType.equals(float.class) || componentType.equals(Float.class)) { - return new FloatArrayAccessor(floatNullArray(size)); - } else if (componentType.equals(int.class) || componentType.equals(Integer.class)) { - return new IntArrayAccessor(intNullArray(size)); - } else if (componentType.equals(long.class) || componentType.equals(Long.class)) { - return new LongArrayAccessor(longNullArray(size)); - } else if (componentType.equals(short.class) || componentType.equals(Short.class)) { - return new ShortArrayAccessor(shortNullArray(size)); - } else { - return new ObjectArrayAccessor((Object[]) Array.newInstance(componentType, size)); - } - - } - public static Character[] getBoxedArray(char[] referenceData) { Character[] result = new Character[referenceData.length]; for (int i = 0; i < result.length; i++) { @@ -426,22 +302,21 @@ public static Object[] getBoxedArray(Object value) { return null; } - final Class c = value.getClass(); - if (c.equals(boolean[].class)) { + if (value instanceof boolean[]) { return getBoxedArray((boolean[]) value); - } else if (c.equals(byte[].class)) { + } else if (value instanceof byte[]) { return getBoxedArray((byte[]) value); - } else if (c.equals(char[].class)) { + } else if (value instanceof char[]) { return getBoxedArray((char[]) value); - } else if (c.equals(double[].class)) { + } else if (value instanceof double[]) { return getBoxedArray((double[]) value); - } else if (c.equals(float[].class)) { + } else if (value instanceof float[]) { return getBoxedArray((float[]) value); - } else if (c.equals(int[].class)) { + } else if (value instanceof int[]) { return getBoxedArray((int[]) value); - } else if (c.equals(long[].class)) { + } else if (value instanceof long[]) { return getBoxedArray((long[]) value); - } else if (c.equals(short[].class)) { + } else if (value instanceof short[]) { return getBoxedArray((short[]) value); } else { return (Object[]) value; @@ -449,47 +324,42 @@ public static Object[] getBoxedArray(Object value) { } public static boolean equals(Object actualValue, Object expectedValue) { - final Class ct = actualValue.getClass().getComponentType(); - if (Object.class.isAssignableFrom(ct)) { - return Arrays.equals((Object[]) actualValue, (Object[]) expectedValue); - } else if (byte.class.isAssignableFrom(ct)) { + if (actualValue instanceof byte[] && expectedValue instanceof byte[]) { return Arrays.equals((byte[]) actualValue, (byte[]) expectedValue); - } else if (char.class.isAssignableFrom(ct)) { + } else if (actualValue instanceof char[] && expectedValue instanceof char[]) { return Arrays.equals((char[]) actualValue, (char[]) expectedValue); - } else if (double.class.isAssignableFrom(ct)) { + } else if (actualValue instanceof double[] && expectedValue instanceof double[]) { return Arrays.equals((double[]) actualValue, (double[]) expectedValue); - } else if (float.class.isAssignableFrom(ct)) { + } else if (actualValue instanceof float[] && expectedValue instanceof float[]) { return Arrays.equals((float[]) actualValue, (float[]) expectedValue); - } else if (int.class.isAssignableFrom(ct)) { + } else if (actualValue instanceof int[] && expectedValue instanceof int[]) { return Arrays.equals((int[]) actualValue, (int[]) expectedValue); - } else if (long.class.isAssignableFrom(ct)) { + } else if (actualValue instanceof long[] && expectedValue instanceof long[]) { return Arrays.equals((long[]) actualValue, (long[]) expectedValue); - } else if (short.class.isAssignableFrom(ct)) { + } else if (actualValue instanceof short[] && expectedValue instanceof short[]) { return Arrays.equals((short[]) actualValue, (short[]) expectedValue); + } else { + return Arrays.equals((Object[]) actualValue, (Object[]) expectedValue); } - return false; } public static String toString(Object actualValue) { - final Class ct = actualValue.getClass().getComponentType(); - if (Object.class.isAssignableFrom(ct)) { - return Arrays.toString((Object[]) actualValue); - } else if (byte.class.isAssignableFrom(ct)) { + if (actualValue instanceof byte[]) { return Arrays.toString((byte[]) actualValue); - } else if (char.class.isAssignableFrom(ct)) { + } else if (actualValue instanceof char[]) { return Arrays.toString((char[]) actualValue); - } else if (double.class.isAssignableFrom(ct)) { + } else if (actualValue instanceof double[]) { return Arrays.toString((double[]) actualValue); - } else if (float.class.isAssignableFrom(ct)) { + } else if (actualValue instanceof float[]) { return Arrays.toString((float[]) actualValue); - } else if (int.class.isAssignableFrom(ct)) { + } else if (actualValue instanceof int[]) { return Arrays.toString((int[]) actualValue); - } else if (long.class.isAssignableFrom(ct)) { + } else if (actualValue instanceof long[]) { return Arrays.toString((long[]) actualValue); - } else if (short.class.isAssignableFrom(ct)) { + } else if (actualValue instanceof short[]) { return Arrays.toString((short[]) actualValue); } - return null; + return Arrays.toString((Object[]) actualValue); } public static String toString(boolean[] a, int offset, int length) { @@ -674,10 +544,10 @@ public interface ArrayAccessor { public static class ObjectArrayAccessor implements ArrayAccessor { - private T array[]; + private final T[] array; - public ObjectArrayAccessor(T array[]) { + public ObjectArrayAccessor(T[] array) { this.array = array; } @@ -717,9 +587,9 @@ public void copyArray(Object sourceArray, int pos, int length) { public static class BooleanArrayAccessor implements ArrayAccessor { - private Boolean array[]; + private final Boolean[] array; - public BooleanArrayAccessor(Boolean array[]) { + public BooleanArrayAccessor(Boolean[] array) { this.array = array; } @@ -761,9 +631,9 @@ public void copyArray(Object sourceArray, int pos, int length) { public static class ByteArrayAccessor implements ArrayAccessor { - private byte array[]; + private final byte[] array; - public ByteArrayAccessor(byte array[]) { + public ByteArrayAccessor(byte[] array) { this.array = array; } @@ -804,9 +674,9 @@ public void copyArray(Object sourceArray, int pos, int length) { } public static class CharArrayAccessor implements ArrayAccessor { - private char array[]; + private final char[] array; - public CharArrayAccessor(char array[]) { + public CharArrayAccessor(char[] array) { this.array = array; } @@ -847,9 +717,9 @@ public void copyArray(Object sourceArray, int pos, int length) { } public static class DoubleArrayAccessor implements ArrayAccessor { - private double array[]; + private final double[] array; - public DoubleArrayAccessor(double array[]) { + public DoubleArrayAccessor(double[] array) { this.array = array; } @@ -890,9 +760,9 @@ public void copyArray(Object sourceArray, int pos, int length) { } public static class FloatArrayAccessor implements ArrayAccessor { - private float array[]; + private final float[] array; - public FloatArrayAccessor(float array[]) { + public FloatArrayAccessor(float[] array) { this.array = array; } @@ -933,9 +803,9 @@ public void copyArray(Object sourceArray, int pos, int length) { } public static class IntArrayAccessor implements ArrayAccessor { - private int array[]; + private final int[] array; - public IntArrayAccessor(int array[]) { + public IntArrayAccessor(int[] array) { this.array = array; } @@ -981,9 +851,9 @@ public void copyArray(Object sourceArray, int pos, int length) { } public static class LongArrayAccessor implements ArrayAccessor { - private long array[]; + private final long[] array; - public LongArrayAccessor(long array[]) { + public LongArrayAccessor(long[] array) { this.array = array; } @@ -1025,9 +895,9 @@ public void copyArray(Object sourceArray, int pos, int length) { } public static class ShortArrayAccessor implements ArrayAccessor { - private short array[]; + private final short[] array; - public ShortArrayAccessor(short array[]) { + public ShortArrayAccessor(short[] array) { this.array = array; } diff --git a/Util/src/main/java/io/deephaven/util/type/NumericTypeUtils.java b/Util/src/main/java/io/deephaven/util/type/NumericTypeUtils.java new file mode 100644 index 00000000000..95b300e12fd --- /dev/null +++ b/Util/src/main/java/io/deephaven/util/type/NumericTypeUtils.java @@ -0,0 +1,54 @@ +// +// Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending +// +package io.deephaven.util.type; + +import org.jetbrains.annotations.NotNull; + +import java.math.BigDecimal; +import java.math.BigInteger; + +public class NumericTypeUtils { + private NumericTypeUtils() {} + + /** + * Whether the class is an instance of {@link Number}. + * + * @param c class + * @return true if Number.class is assignable from {@code c}, false otherwise + */ + public static boolean isBoxedNumeric(@NotNull final Class c) { + return Number.class.isAssignableFrom(c); + } + + /** + * Whether the class is {@link NumericTypeUtils#isPrimitiveNumeric(Class)} or {@link #isBoxedNumeric(Class)} + * + * @param c class + * @return true if {@code c} is numeric, false otherwise + */ + public static boolean isNumeric(@NotNull final Class c) { + return isPrimitiveNumeric(c) || isBoxedNumeric(c); + } + + /** + * Whether the class is a {@link BigInteger} or {@link BigDecimal} + * + * @param type the class + * @return true if the type is BigInteger or BigDecimal, false otherwise + */ + public static boolean isBigNumeric(Class type) { + return BigInteger.class.isAssignableFrom(type) || BigDecimal.class.isAssignableFrom(type); + } + + /** + * Whether the class is equal to one of the six numeric primitives: float, double, int, long, short, or byte. + * + * @param c class + * @return true if {@code c} is a numeric primitive, false otherwise + */ + public static boolean isPrimitiveNumeric(@NotNull final Class c) { + return c == double.class || c == float.class + || c == int.class || c == long.class || c == short.class || c == byte.class; + } +} diff --git a/Util/src/main/java/io/deephaven/util/type/TypeUtils.java b/Util/src/main/java/io/deephaven/util/type/TypeUtils.java index 856d4f01e05..e3ae220a4d4 100644 --- a/Util/src/main/java/io/deephaven/util/type/TypeUtils.java +++ b/Util/src/main/java/io/deephaven/util/type/TypeUtils.java @@ -5,18 +5,11 @@ import org.jetbrains.annotations.NotNull; -import java.io.*; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.time.Instant; -import java.time.ZonedDateTime; import java.util.*; import java.util.stream.Collectors; -import java.lang.reflect.*; - import static io.deephaven.util.QueryConstants.*; /** @@ -58,6 +51,10 @@ public class TypeUtils { .unmodifiableMap(PRIMITIVE_TYPES.stream().collect(Collectors.toMap(Class::getName, type -> type))); } + /** + * Deprecated with no replacement. + */ + @Deprecated @Retention(RetentionPolicy.RUNTIME) public @interface IsDateTime { boolean value() default true; @@ -372,27 +369,6 @@ public static String nullConstantForType(Class type) { } } - /** - * Whether the class is equal to one of the six numeric primitives: float, double, int, long, short, or byte. - * - * @param c class - * @return true if {@code c} is a numeric primitive, false otherwise - */ - public static boolean isPrimitiveNumeric(@NotNull final Class c) { - return c == double.class || c == float.class - || c == int.class || c == long.class || c == short.class || c == byte.class; - } - - /** - * Whether the class is an instance of {@link Number}. - * - * @param c class - * @return true if Number.class is assignable from {@code c}, false otherwise - */ - public static boolean isBoxedNumeric(@NotNull final Class c) { - return Number.class.isAssignableFrom(c); - } - /** * Whether the class is equal to char.class. * @@ -493,16 +469,6 @@ public static boolean isBoxedBoolean(@NotNull final Class c) { return Boolean.class == c; } - /** - * Whether the class is {@link #isPrimitiveNumeric(Class)} or {@link #isBoxedNumeric(Class)} - * - * @param c class - * @return true if {@code c} is numeric, false otherwise - */ - public static boolean isNumeric(@NotNull final Class c) { - return isPrimitiveNumeric(c) || isBoxedNumeric(c); - } - /** * Whether the class equals char.class or Character.class is assignable from it. * @@ -513,18 +479,6 @@ public static boolean isCharacter(@NotNull final Class c) { return isPrimitiveChar(c) || isBoxedChar(c); } - /** - * Whether the class is an {@link Instant}, a {@link ZonedDateTime}, or annotated as {@link IsDateTime}. - * - * @param type The class. - * @return true if the type is a DateTime, {@link java.time.ZonedDateTime} or {@link Instant}. - */ - public static boolean isDateTime(Class type) { - return Instant.class.isAssignableFrom(type) - || ZonedDateTime.class.isAssignableFrom(type) - || (type.getAnnotation(IsDateTime.class) != null && type.getAnnotation(IsDateTime.class).value()); - } - /** * Whether the class is a {@link String} * @@ -535,16 +489,6 @@ public static boolean isString(Class type) { return String.class == type; } - /** - * Whether the class is a {@link BigInteger} or {@link BigDecimal} - * - * @param type the class - * @return true if the type is BigInteger or BigDecimal, false otherwise - */ - public static boolean isBigNumeric(Class type) { - return BigInteger.class.isAssignableFrom(type) || BigDecimal.class.isAssignableFrom(type); - } - /** * Checks if the type is a primitive or Boxed floate type (double or float). * @@ -555,232 +499,6 @@ public static boolean isFloatType(Class type) { return type.equals(double.class) || type.equals(float.class) || isBoxedDouble(type) || isBoxedFloat(type); } - /** - * Converts an Object to a String for writing to a workspace. This is meant to be used in conjunction with - * {@code TypeUtils.fromString}. Strings, Numbers, and primitives will all convert using {@code Obect.toString}. - * Serializable objects will be encoded in base64. All others will return null. - * - * @param o the object to convert - * @return a String representation of the object, null if it cannot be converted - * @throws IOException if an IO error occurs during conversion - */ - public static String objectToString(Object o) throws IOException { - if (o == null) { - return null; - } - - final Class type = o.getClass(); - // isNumeric gets BigInteger and BigDecimal in addition to everything gotten by isConvertibleToPrimitive - if (type == String.class || isConvertibleToPrimitive(type) || isNumeric(type)) { - return o.toString(); - } else if (o instanceof Serializable) { - return encode64Serializable((Serializable) o); - } - - throw new RuntimeException( - "Failed to convert object of type " + type.getCanonicalName() + ". Type not supported"); - } - - /** - * Creates an Object from a String. This is meant to be used in conjunction with {@code TypeUtils.objectToString} - * Strings, Numbers, and primitives will all parse using their boxed type parsing methods. Serializable types will - * be decoded from base64. Returns null if the String fails to parse. - * - * @param string the String to parse - * @param typeString the Canonical Name of the class type - * @return an object parsed from the String - * @throws RuntimeException if the string fails to parse - * @throws IOException if an IO error occurs during conversion - */ - public static Optional fromString(String string, String typeString) throws IOException { - final Class type; - try { - type = Class.forName(typeString); - return Optional.ofNullable(fromString(string, type)); - } catch (ClassNotFoundException e) { - return Optional.empty(); - } - } - - /** - * Creates an Object from a String. This is meant to be used in conjunction with {@code TypeUtils.objectToString} - * Strings, Numbers, and primitives will all parse using their boxed type parsing methods. Serializable types will - * be decoded from base64. Returns null if the String fails to parse. - * - * @param string the String to parse - * @param type the type of the object - * @return an object parsed from the String - * @throws RuntimeException if the string fails to parse - * @throws IOException if an IO error occurs during conversion - */ - public static Object fromString(String string, Class type) throws IOException { - final Class boxedType = getBoxedType(type); - try { - if (boxedType == String.class) { - return string; - } else if (boxedType == Boolean.class) { - return Boolean.parseBoolean(string); - } else if (boxedType == Integer.class) { - return Integer.parseInt(string); - } else if (boxedType == Double.class) { - return Double.parseDouble(string); - } else if (boxedType == Short.class) { - return Short.parseShort(string); - } else if (boxedType == Long.class) { - return Long.parseLong(string); - } else if (boxedType == Float.class) { - return Float.parseFloat(string); - } else if (boxedType == BigInteger.class) { - return new BigInteger(string); - } else if (boxedType == BigDecimal.class) { - return new BigDecimal(string); - } else if (boxedType == Byte.class) { - return Byte.parseByte(string); - } else if (boxedType == Character.class) { - return string.charAt(0); - } else if (Serializable.class.isAssignableFrom(boxedType)) { - return decode64Serializable(string); - } - } catch (IOException ioe) { - throw ioe; - } catch (Exception e) { - throw new RuntimeException("Failed to parse " + string + "into type " + type.getCanonicalName(), e); - } - - throw new RuntimeException( - "Failed to parse " + string + "into type " + type.getCanonicalName() + ". Type not supported"); - } - - /** - * Encodes a Serializable Object into base64 String. - * - * @param serializable the object to encode - * @return the base64 encoded string - * @throws IOException if the string cannot be encoded - */ - public static String encode64Serializable(Serializable serializable) throws IOException { - try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ObjectOutputStream os = new ObjectOutputStream(bos)) { - os.writeObject(serializable); - return Base64.getEncoder().encodeToString(bos.toByteArray()); - } - } - - /** - * Decodes a Serializable Object from a base64 encoded String. - * - * @param string the base64 encoded String - * @return the encoded Object - * @throws IOException if the string cannot be decoded - * @throws ClassNotFoundException if the Object type is unknown - */ - public static Object decode64Serializable(String string) throws IOException, ClassNotFoundException { - try (ObjectInputStream is = - new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(string)))) { - return is.readObject(); - } - } - - /** - * Determine the Class from the Type. - */ - public static Class getErasedType(Type paramType) { - if (paramType instanceof Class) { - return (Class) paramType; - } else if (paramType instanceof ParameterizedType) { - return (Class) // We are asking the parameterized type for it's raw type, which is always Class - ((ParameterizedType) paramType).getRawType(); - } else if (paramType instanceof WildcardType) { - final Type[] upper = ((WildcardType) paramType).getUpperBounds(); - return getErasedType(upper[0]); - } else if (paramType instanceof java.lang.reflect.TypeVariable) { - final Type[] bounds = ((TypeVariable) paramType).getBounds(); - if (bounds.length > 1) { - Class[] erasedBounds = new Class[bounds.length]; - Class weakest = null; - for (int i = 0; i < erasedBounds.length; i++) { - erasedBounds[i] = getErasedType(bounds[i]); - if (i == 0) { - weakest = erasedBounds[i]; - } else { - weakest = getWeakest(weakest, erasedBounds[i]); - } - // If we are erased to object, stop erasing... - if (weakest == Object.class) { - break; - } - } - return weakest; - } - return getErasedType(bounds[0]); - } else { - throw new UnsupportedOperationException(); - } - } - - /** - * Determine the weakest parent of the two provided Classes. - * - * @param one one class to compare - * @param two the other class to compare - * @return the weakest parent Class - */ - private static Class getWeakest(Class one, Class two) { - if (one.isAssignableFrom(two)) { - return one; - } else if (two.isAssignableFrom(one)) { - return two; - } - // No luck on quick check... Look in interfaces. - Set> oneInterfaces = getFlattenedInterfaces(one); - Set> twoInterfaces = getFlattenedInterfaces(two); - // Keep only shared interfaces - oneInterfaces.retainAll(twoInterfaces); - Class strongest = Object.class; - for (Class cls : oneInterfaces) { - // There is a winning type... - if (strongest.isAssignableFrom(cls)) { - strongest = cls; - } else if (!cls.isAssignableFrom(strongest)) { - return Object.class; - } - } - // Will be Object.class if there were no shared interfaces (or shared interfaces were not compatible). - return strongest; - } - - private static Set> getFlattenedInterfaces(Class cls) { - final Set> set = new HashSet<>(); - while (cls != null && cls != Object.class) { - for (Class iface : cls.getInterfaces()) { - collectInterfaces(set, iface); - } - cls = cls.getSuperclass(); - } - return set; - } - - private static void collectInterfaces(final Collection> into, final Class cls) { - if (into.add(cls)) { - for (final Class iface : cls.getInterfaces()) { - if (into.add(iface)) { - collectInterfaces(into, iface); - } - } - } - } - - - public static Class classForName(String className) throws ClassNotFoundException { - Class result = primitiveClassNameToClass.get(className); - if (result == null) { - return Class.forName(className); - } else { - return result; - } - - } - public static abstract class TypeBoxer { public abstract T get(T result); } @@ -837,7 +555,7 @@ public Short get(Short result) { } }; } else { - return (TypeBoxer) new TypeBoxer() { + return new TypeBoxer<>() { @Override public Object get(Object result) { return result; diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/AggregationProcessor.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/AggregationProcessor.java index f57ac5dae87..ab1d7e83929 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/by/AggregationProcessor.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/by/AggregationProcessor.java @@ -125,7 +125,7 @@ import static io.deephaven.engine.table.impl.by.RollupConstants.*; import static io.deephaven.util.QueryConstants.*; import static io.deephaven.util.type.TypeUtils.getBoxedType; -import static io.deephaven.util.type.TypeUtils.isNumeric; +import static io.deephaven.util.type.NumericTypeUtils.isNumeric; /** * Conversion tool to generate an {@link AggregationContextFactory} for a collection of {@link Aggregation diff --git a/engine/table/src/main/java/io/deephaven/engine/table/impl/preview/ColumnPreviewManager.java b/engine/table/src/main/java/io/deephaven/engine/table/impl/preview/ColumnPreviewManager.java index 3a12528b431..a8e82e2a9e2 100644 --- a/engine/table/src/main/java/io/deephaven/engine/table/impl/preview/ColumnPreviewManager.java +++ b/engine/table/src/main/java/io/deephaven/engine/table/impl/preview/ColumnPreviewManager.java @@ -6,14 +6,16 @@ import io.deephaven.configuration.Configuration; import io.deephaven.engine.table.ColumnDefinition; import io.deephaven.engine.table.Table; +import io.deephaven.util.type.NumericTypeUtils; import io.deephaven.vector.Vector; import io.deephaven.engine.table.impl.BaseTable; import io.deephaven.engine.table.impl.select.FunctionalColumn; import io.deephaven.engine.table.impl.select.SelectColumn; -import io.deephaven.util.type.TypeUtils; import org.apache.commons.lang3.StringUtils; import org.jpy.PyListWrapper; +import java.time.Instant; +import java.time.ZonedDateTime; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -155,8 +157,8 @@ public static boolean isColumnTypeDisplayable(Class type) { return type.isPrimitive() || io.deephaven.util.type.TypeUtils.isBoxedType(type) || io.deephaven.util.type.TypeUtils.isString(type) - || io.deephaven.util.type.TypeUtils.isBigNumeric(type) - || TypeUtils.isDateTime(type) + || NumericTypeUtils.isBigNumeric(type) + || Instant.class == type || ZonedDateTime.class == type || isOnWhiteList(type); } diff --git a/engine/table/src/test/java/io/deephaven/engine/util/TestNumericTypeUtils.java b/engine/table/src/test/java/io/deephaven/engine/util/TestNumericTypeUtils.java new file mode 100644 index 00000000000..795405becba --- /dev/null +++ b/engine/table/src/test/java/io/deephaven/engine/util/TestNumericTypeUtils.java @@ -0,0 +1,34 @@ +// +// Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending +// +package io.deephaven.engine.util; + +import io.deephaven.util.type.NumericTypeUtils; +import org.junit.Test; + +import java.time.Instant; +import java.util.Date; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class TestNumericTypeUtils { + + @Test + public void testIsType() { + assertFalse(NumericTypeUtils.isPrimitiveNumeric(Instant.class)); + assertFalse(NumericTypeUtils.isPrimitiveNumeric(Date.class)); + assertTrue(NumericTypeUtils.isPrimitiveNumeric(int.class)); + assertFalse(NumericTypeUtils.isPrimitiveNumeric(Double.class)); + + assertFalse(NumericTypeUtils.isBoxedNumeric(Instant.class)); + assertFalse(NumericTypeUtils.isBoxedNumeric(Date.class)); + assertFalse(NumericTypeUtils.isBoxedNumeric(int.class)); + assertTrue(NumericTypeUtils.isBoxedNumeric(Double.class)); + + assertFalse(NumericTypeUtils.isNumeric(Instant.class)); + assertFalse(NumericTypeUtils.isNumeric(Date.class)); + assertTrue(NumericTypeUtils.isNumeric(int.class)); + assertTrue(NumericTypeUtils.isNumeric(Double.class)); + } +} diff --git a/engine/table/src/test/java/io/deephaven/engine/util/TestTypeUtils.java b/engine/table/src/test/java/io/deephaven/engine/util/TestTypeUtils.java index 46bad50b275..3becd9e27b8 100644 --- a/engine/table/src/test/java/io/deephaven/engine/util/TestTypeUtils.java +++ b/engine/table/src/test/java/io/deephaven/engine/util/TestTypeUtils.java @@ -7,7 +7,6 @@ import junit.framework.TestCase; import org.apache.commons.lang3.ArrayUtils; -import java.io.IOException; import java.time.Instant; import java.util.Arrays; import java.util.Date; @@ -129,21 +128,6 @@ public void testTypesSetOrdering() { } public void testIsType() { - assertFalse(io.deephaven.util.type.TypeUtils.isPrimitiveNumeric(Instant.class)); - assertFalse(io.deephaven.util.type.TypeUtils.isPrimitiveNumeric(Date.class)); - assertTrue(io.deephaven.util.type.TypeUtils.isPrimitiveNumeric(int.class)); - assertFalse(io.deephaven.util.type.TypeUtils.isPrimitiveNumeric(Double.class)); - - assertFalse(io.deephaven.util.type.TypeUtils.isBoxedNumeric(Instant.class)); - assertFalse(io.deephaven.util.type.TypeUtils.isBoxedNumeric(Date.class)); - assertFalse(io.deephaven.util.type.TypeUtils.isBoxedNumeric(int.class)); - assertTrue(io.deephaven.util.type.TypeUtils.isBoxedNumeric(Double.class)); - - assertFalse(io.deephaven.util.type.TypeUtils.isNumeric(Instant.class)); - assertFalse(io.deephaven.util.type.TypeUtils.isNumeric(Date.class)); - assertTrue(io.deephaven.util.type.TypeUtils.isNumeric(int.class)); - assertTrue(io.deephaven.util.type.TypeUtils.isNumeric(Double.class)); - assertFalse(io.deephaven.util.type.TypeUtils.isCharacter(Instant.class)); assertFalse(io.deephaven.util.type.TypeUtils.isCharacter(Date.class)); assertFalse(io.deephaven.util.type.TypeUtils.isCharacter(int.class)); @@ -162,9 +146,4 @@ public void testIsType() { assertFalse(io.deephaven.util.type.TypeUtils.isBoxedChar(char.class)); assertTrue(io.deephaven.util.type.TypeUtils.isBoxedChar(Character.class)); } - - public void testObjectToString() throws IOException { - assertNull(io.deephaven.util.type.TypeUtils.objectToString(null)); // null input - assertEquals("STRING", io.deephaven.util.type.TypeUtils.objectToString("STRING")); // non null input - } } diff --git a/extensions/barrage/src/main/java/io/deephaven/extensions/barrage/util/BarrageUtil.java b/extensions/barrage/src/main/java/io/deephaven/extensions/barrage/util/BarrageUtil.java index f8933e6aee0..b11cc5f2a08 100755 --- a/extensions/barrage/src/main/java/io/deephaven/extensions/barrage/util/BarrageUtil.java +++ b/extensions/barrage/src/main/java/io/deephaven/extensions/barrage/util/BarrageUtil.java @@ -682,7 +682,7 @@ private static ConvertedArrowSchema convertArrowSchema( private static boolean isTypeNativelySupported(final Class typ) { if (typ.isPrimitive() || TypeUtils.isBoxedType(typ) || supportedTypes.contains(typ) - || Vector.class.isAssignableFrom(typ) || TypeUtils.isDateTime(typ)) { + || Vector.class.isAssignableFrom(typ) || Instant.class == typ || ZonedDateTime.class == typ) { return true; } if (typ.isArray()) { diff --git a/server/src/main/java/io/deephaven/server/table/ops/ColumnStatisticsGrpcImpl.java b/server/src/main/java/io/deephaven/server/table/ops/ColumnStatisticsGrpcImpl.java index 6418219308f..f74bae1614d 100644 --- a/server/src/main/java/io/deephaven/server/table/ops/ColumnStatisticsGrpcImpl.java +++ b/server/src/main/java/io/deephaven/server/table/ops/ColumnStatisticsGrpcImpl.java @@ -22,7 +22,7 @@ import io.deephaven.server.table.stats.ChunkedStatsKernel; import io.deephaven.server.table.stats.DateTimeChunkedStats; import io.deephaven.server.table.stats.ObjectChunkedStats; -import io.deephaven.util.type.TypeUtils; +import io.deephaven.util.type.NumericTypeUtils; import org.apache.commons.lang3.mutable.Mutable; import org.apache.commons.lang3.mutable.MutableObject; @@ -67,20 +67,13 @@ public Table create(ColumnStatisticsRequest request, List columnSource; - if (TypeUtils.isDateTime(type)) { - // Instant/ZonedDateTime only look at max/min and count + if (type == Instant.class) { statsFunc = new DateTimeChunkedStats(); - - // Reinterpret the column to read only long values - if (Instant.class.isAssignableFrom(type)) { - columnSource = ReinterpretUtils.instantToLongSource(table.getColumnSource(columnName)); - } else if (ZonedDateTime.class.isAssignableFrom(type)) { - columnSource = ReinterpretUtils.zonedDateTimeToLongSource(table.getColumnSource(columnName)); - } else { - throw Exceptions.statusRuntimeException(Code.INVALID_ARGUMENT, - "DateTime columns must be Instant or ZonedDateTime"); - } - } else if (TypeUtils.isNumeric(type)) { + columnSource = ReinterpretUtils.instantToLongSource(table.getColumnSource(columnName)); + } else if (type == ZonedDateTime.class) { + statsFunc = new DateTimeChunkedStats(); + columnSource = ReinterpretUtils.zonedDateTimeToLongSource(table.getColumnSource(columnName)); + } else if (NumericTypeUtils.isNumeric(type)) { // Numeric types have a variety of statistics recorded statsFunc = ChunkedNumericalStatsKernel.makeChunkedNumericalStats(type); columnSource = table.getColumnSource(columnName);