diff --git a/Generators/Generators.gradle b/Generators/Generators.gradle index 224df2ecba5..7c6dc49da93 100644 --- a/Generators/Generators.gradle +++ b/Generators/Generators.gradle @@ -56,7 +56,25 @@ task groovyStaticImportGeneratorAssert(type: JavaExec, dependsOn: 'classes') { classpath = sourceSets.main.runtimeClasspath workingDir = workDir onlyIf { System.getenv('NO_ASSERT') != 'true' } +} + +task generateStaticCalendarMethods(type: JavaExec, dependsOn: 'classes') { + description 'Run StaticCalendarMethodsGenerator' + + main = 'io.deephaven.libs.StaticCalendarMethodsGenerator' + args devRoot, 'false' + classpath = sourceSets.main.runtimeClasspath + workingDir = workDir +} + +task generateStaticCalendarMethodsAssert(type: JavaExec, dependsOn: 'classes') { + description 'Run StaticCalendarMethodsGenerator to assert that the generated code has not changed' + main = 'io.deephaven.libs.StaticCalendarMethodsGenerator' + args devRoot, 'true' + classpath = sourceSets.main.runtimeClasspath + workingDir = workDir + onlyIf { System.getenv('NO_ASSERT') != 'true' } } task generateAxesPlotMethods(type: JavaExec, dependsOn: 'classes') { @@ -190,6 +208,7 @@ tasks.register 'generateAllPythonAssert', { tasks.register 'generateAll', { Task t -> t.dependsOn ':Generators:groovyStaticImportGenerator', + ':Generators:generateStaticCalendarMethods', ':Generators:generateAxesPlotMethods', ':Generators:generateMultiSeries', ':Generators:generateFigureImmutable', @@ -201,6 +220,7 @@ tasks.register 'generateAll', { } project.tasks.getByName('quick').dependsOn groovyStaticImportGeneratorAssert, + generateStaticCalendarMethodsAssert, generateAxesPlotMethodsAssert, generateMultiSeriesAssert, generateFigureImmutableAssert, diff --git a/Generators/src/main/java/io/deephaven/gen/AbstractBasicJavaGenerator.java b/Generators/src/main/java/io/deephaven/gen/AbstractBasicJavaGenerator.java new file mode 100644 index 00000000000..bc599770847 --- /dev/null +++ b/Generators/src/main/java/io/deephaven/gen/AbstractBasicJavaGenerator.java @@ -0,0 +1,183 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ +package io.deephaven.gen; + +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.function.Predicate; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Abstract class for generating Java code from methods of one or more classes. + * + * {@link #generateCode()} must be called to generate the code. + */ +public abstract class AbstractBasicJavaGenerator { + private static final Logger log = Logger.getLogger(AbstractBasicJavaGenerator.class.toString()); + + private final String gradleTask; + private final String packageName; + private final String className; + private final Map functions = new TreeMap<>(); + private final Collection> skipsGen; + + /** + * Constructor. + * + * @param gradleTask Gradle task to generate the code. + * @param packageName Package name for the generated class. + * @param className Class name for the generated class. + * @param imports Array of fully qualified class names to process. + * @param includeMethod a predicate to determine if a method should be considered for code generation. + * @param skipsGen Collection of predicates to determine if a function should be skipped when generating code. + * @throws ClassNotFoundException If a class in the imports array cannot be found. + */ + public AbstractBasicJavaGenerator(final String gradleTask, final String packageName, final String className, + final String[] imports, Predicate includeMethod, Collection> skipsGen) + throws ClassNotFoundException { + this.gradleTask = gradleTask; + this.packageName = packageName; + this.className = className; + this.skipsGen = skipsGen; + + for (String imp : imports) { + Class c = Class.forName(imp, false, Thread.currentThread().getContextClassLoader()); + log.info("Processing class: " + c); + + for (Method m : c.getMethods()) { + log.info("Processing method (" + c + "): " + m); + if (includeMethod.test(m)) { + addMethod(m); + } + } + } + } + + private void addMethod(Method m) { + log.info("Processing public static method: " + m); + + JavaFunction f = new JavaFunction(m); + // System.out.println(f); + + if (functions.containsKey(f)) { + JavaFunction fAlready = functions.get(f); + final String message = "Signature Already Present: " + fAlready + "\t" + f; + log.severe(message); + throw new RuntimeException(message); + } else { + log.info("Added method: " + f); + functions.put(f, f); + } + } + + /** + * Generate Javadoc for the output class. + * + * @return The Javadoc. + */ + abstract public String generateClassJavadoc(); + + /** + * Generate the Java code for a function. + * + * @param f The function. + * @return The Java code. + */ + abstract public String generateFunction(JavaFunction f); + + /** + * Generate the code. + * + * @return The generated code. + */ + @SuppressWarnings("StringConcatenationInLoop") + public String generateCode() { + + String code = GenUtils.javaHeader(this.getClass(), gradleTask); + code += "package " + packageName + ";\n\n"; + + Set imports = GenUtils.typesToImport(functions.keySet()); + + for (String imp : imports) { + code += "import " + imp + ";\n"; + } + + code += "\n"; + code += generateClassJavadoc(); + code += "public class " + className + " {\n"; + + for (JavaFunction f : functions.keySet()) { + boolean skip = false; + for (Predicate skipCheck : skipsGen) { + skip = skip || skipCheck.test(f); + } + + if (skip) { + log.warning("*** Skipping function: " + f); + continue; + } + + code += generateFunction(f); + code += "\n"; + } + + code += "}\n\n"; + + return code; + } + + /** + * Run a generator from the command line. + * + * @param gen The generator to run. + * @param relativeFilePath The relative file path to write the generated code to. + * @param args The command line arguments. + * @throws IOException If there is an IO error. + */ + public static void runCommandLine(final AbstractBasicJavaGenerator gen, final String relativeFilePath, + final String[] args) throws IOException { + + String devroot = null; + boolean assertNoChange = false; + if (args.length == 1) { + devroot = args[0]; + } else if (args.length == 2) { + devroot = args[0]; + assertNoChange = Boolean.parseBoolean(args[1]); + } else { + System.out.println("Usage: [assertNoChange]"); + System.exit(-1); + } + + log.setLevel(Level.WARNING); + log.warning("Running " + gen.getClass().getSimpleName() + " assertNoChange=" + assertNoChange); + + final String code = gen.generateCode(); + log.info("\n\n**************************************\n\n"); + log.info(code); + + String file = devroot + relativeFilePath; + + if (assertNoChange) { + String oldCode = new String(Files.readAllBytes(Paths.get(file))); + GenUtils.assertGeneratedCodeSame(AbstractBasicJavaGenerator.class, gen.gradleTask, oldCode, code); + } else { + + PrintWriter out = new PrintWriter(file); + out.print(code); + out.close(); + + log.warning("Class file written to: " + file); + } + } + +} diff --git a/Generators/src/main/java/io/deephaven/gen/GenUtils.java b/Generators/src/main/java/io/deephaven/gen/GenUtils.java new file mode 100644 index 00000000000..b4ec61df602 --- /dev/null +++ b/Generators/src/main/java/io/deephaven/gen/GenUtils.java @@ -0,0 +1,248 @@ +package io.deephaven.gen; + +import gnu.trove.map.TIntObjectMap; +import gnu.trove.map.hash.TIntObjectHashMap; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.*; +import java.util.*; +import java.util.logging.Logger; + +@SuppressWarnings("StringConcatenationInLoop") +public class GenUtils { + private GenUtils() {} + + private static final Logger log = Logger.getLogger(GenUtils.class.toString()); + + private static final TIntObjectMap cachedIndents = new TIntObjectHashMap<>(); + + /** + * Get a String of spaces for indenting code. + * + * @param n The number of indents + * @return The String for indenting code with spaces + */ + public static String indent(final int n) { + String cached = cachedIndents.get(n); + if (cached == null) { + cachedIndents.put(n, cached = String.join("", Collections.nCopies(4 * n, " "))); + } + return cached; + } + + /** + * Creates the header for a generated java file. + * + * @param generatorClass class used to generate the code. + * @param gradleTask gradle task to generate the code. + * @return The header for a generated java file + */ + public static String javaHeader(final Class generatorClass, final String gradleTask) { + return "/**\n" + + " * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending\n" + + " */\n" + + "/****************************************************************************************************************************\n" + + + " ****** AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - Run " + generatorClass.getSimpleName() + + " or \"./gradlew " + gradleTask + "\" to regenerate\n" + + + " ****************************************************************************************************************************/\n\n"; + + } + + /** + * Assert that the generated code is the same as the old code. + * + * @param generatorClass class used to generate the code. + * @param gradleTask gradle task to generate the code. + * @param oldCode old code + * @param newCode new code + */ + public static void assertGeneratedCodeSame(final Class generatorClass, final String gradleTask, + final String oldCode, final String newCode) { + if (!newCode.equals(oldCode)) { + throw new RuntimeException( + "Change in generated code. Run " + generatorClass + " or \"./gradlew " + gradleTask + + "\" to regenerate\n"); + } + } + + /** + * Generates a set of Java imports needed for the given type. + * + * @param t type. + * @return set of imports. + */ + public static Set typesToImport(Type t) { + Set result = new LinkedHashSet<>(); + + if (t instanceof Class) { + final Class c = (Class) t; + final boolean isArray = c.isArray(); + final boolean isPrimitive = c.isPrimitive(); + + if (isPrimitive) { + return result; + } else if (isArray) { + return typesToImport(c.getComponentType()); + } else { + result.add(t.getTypeName()); + } + } else if (t instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) t; + result.add(pt.getRawType().getTypeName()); + + for (Type a : pt.getActualTypeArguments()) { + result.addAll(typesToImport(a)); + } + } else if (t instanceof TypeVariable) { + // type variables are generic so they don't need importing + return result; + } else if (t instanceof WildcardType) { + // type variables are generic so they don't need importing + return result; + } else if (t instanceof GenericArrayType) { + GenericArrayType at = (GenericArrayType) t; + return typesToImport(at.getGenericComponentType()); + } else { + throw new UnsupportedOperationException("Unsupported Type type: " + t.getClass()); + } + + return result; + } + + /** + * Generates a set of Java imports needed for the given functions. + * + * @param functions functions. + * @return set of imports. + */ + public static Set typesToImport(final Set functions) { + Set imports = new TreeSet<>(); + + for (JavaFunction f : functions) { + imports.add(f.getClassName()); + + imports.addAll(typesToImport(f.getReturnType())); + + for (Type t : f.getParameterTypes()) { + imports.addAll(typesToImport(t)); + } + } + + return imports; + } + + /** + * Helper to transform method parameter types to a form that can be used in a javadoc link, including removing + * generics and finding the upper bound of typevars. + */ + @NotNull + public static String javadocLinkParamTypeString(Type t) { + if (t instanceof ParameterizedType) { + return ((ParameterizedType) t).getRawType().getTypeName(); + } else if (t instanceof TypeVariable) { + return javadocLinkParamTypeString(((TypeVariable) t).getBounds()[0]); + } else if (t instanceof WildcardType) { + return javadocLinkParamTypeString(((WildcardType) t).getUpperBounds()[0]); + } else if (t instanceof GenericArrayType) { + return javadocLinkParamTypeString(((GenericArrayType) t).getGenericComponentType()) + "[]"; + } + return t.getTypeName(); + } + + /** + * Creates an argument string for a Java function. + * + * @param f function. + * @param includeTypes true to include types of the argument parameters; false to just include the parameter names. + * @return argument string. + */ + public static String javaArgString(final JavaFunction f, boolean includeTypes) { + String callArgs = ""; + + for (int i = 0; i < f.getParameterTypes().length; i++) { + if (i != 0) { + callArgs += ","; + } + + Type t = f.getParameterTypes()[i]; + + String typeString = t.getTypeName().replace("$", "."); + + if (f.isVarArgs() && i == f.getParameterTypes().length - 1) { + final int index = typeString.lastIndexOf("[]"); + typeString = typeString.substring(0, index) + "..." + typeString.substring(index + 2); + } + + if (includeTypes) { + callArgs += " " + typeString; + } + + callArgs += " " + f.getParameterNames()[i]; + } + + return callArgs; + } + + /** + * Create code for a Java function signature. + * + * @param f function signature. + * @param sigPrefix sigPrefix to add to the function signature (e.g. "public static"). + * @return code for the function signature. + */ + public static String javaFunctionSignature(final JavaFunction f, final String sigPrefix) { + String returnType = f.getReturnType().getTypeName().replace("$", "."); + String s = indent(1) + (sigPrefix == null || sigPrefix.equals("") ? "" : (sigPrefix + " ")); + + if (f.getTypeParameters().length > 0) { + s += "<"; + + for (int i = 0; i < f.getTypeParameters().length; i++) { + if (i != 0) { + s += ","; + } + + TypeVariable t = f.getTypeParameters()[i]; + log.fine("BOUNDS: " + Arrays.toString(t.getBounds())); + s += t; + + Type[] bounds = t.getBounds(); + + if (bounds.length != 1) { + throw new RuntimeException("Unsupported bounds: " + Arrays.toString(bounds)); + } + + Type bound = bounds[0]; + + if (!bound.equals(Object.class)) { + s += " extends " + bound.getTypeName(); + } + + } + + s += ">"; + } + + s += " " + returnType + " " + f.getMethodName() + "(" + javaArgString(f, true) + " )"; + return s; + } + + /** + * Create a Java function with the given javadoc and body. + * + * @param f function signature. + * @param sigPrefix sigPrefix to add to the function signature (e.g. "public static"). + * @param javadoc javadoc. + * @param funcBody function body. + * @return code for the function. + */ + public static String javaFunction(final JavaFunction f, final String sigPrefix, final String javadoc, + final String funcBody) { + String s = javadoc == null || javadoc.equals("") ? "" : (javadoc + "\n"); + s += javaFunctionSignature(f, sigPrefix); + s += funcBody; + return s; + } +} diff --git a/Generators/src/main/java/io/deephaven/gen/JavaFunction.java b/Generators/src/main/java/io/deephaven/gen/JavaFunction.java new file mode 100644 index 00000000000..54c29ac5227 --- /dev/null +++ b/Generators/src/main/java/io/deephaven/gen/JavaFunction.java @@ -0,0 +1,187 @@ +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.Type; +import java.lang.reflect.TypeVariable; +import java.util.Arrays; +import java.util.Objects; +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 { + private static final Logger log = Logger.getLogger(JavaFunction.class.toString()); + + private final String className; + private final String classNameShort; + private final String methodName; + private final TypeVariable[] typeParameters; + private final Type returnType; + private final Type[] parameterTypes; + private final String[] parameterNames; + private final boolean isVarArgs; + + public JavaFunction(final String className, final String classNameShort, final String methodName, + final TypeVariable[] typeParameters, final Type returnType, final Type[] parameterTypes, + final String[] parameterNames, final boolean isVarArgs) { + this.className = className; + this.classNameShort = classNameShort; + this.methodName = methodName; + this.typeParameters = typeParameters; + this.returnType = returnType; + this.parameterTypes = parameterTypes; + this.parameterNames = parameterNames; + this.isVarArgs = isVarArgs; + } + + public JavaFunction(final Method m) { + this( + m.getDeclaringClass().getCanonicalName(), + m.getDeclaringClass().getSimpleName(), + m.getName(), + m.getTypeParameters(), + m.getGenericReturnType(), + m.getGenericParameterTypes(), + Arrays.stream(m.getParameters()).map(Parameter::getName).toArray(String[]::new), + m.isVarArgs()); + + for (Parameter parameter : m.getParameters()) { + if (!parameter.isNamePresent()) { + throw new IllegalArgumentException( + "Parameter names are not present in the code! Was the code compiled with \"-parameters\": " + + this); + } + } + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + JavaFunction that = (JavaFunction) o; + + if (!Objects.equals(methodName, that.methodName)) + return false; + // Probably incorrect - comparing Object[] arrays with Arrays.equals + return Arrays.equals(parameterTypes, that.parameterTypes); + + } + + @Override + public int hashCode() { + int result = methodName != null ? methodName.hashCode() : 0; + result = 31 * result + Arrays.hashCode(parameterTypes); + return result; + } + + @Override + public String toString() { + return "JavaFunction{" + + "className='" + className + '\'' + + ", methodName='" + methodName + '\'' + + ", typeParameters=" + Arrays.toString(typeParameters) + + ", returnType=" + returnType + + ", parameterTypes=" + Arrays.toString(parameterTypes) + + ", parameterNames=" + Arrays.toString(parameterNames) + + '}'; + } + + @Override + public int compareTo(@NotNull JavaFunction o) { + int cm = methodName.compareTo(o.methodName); + if (cm != 0) { + return cm; + } + if (parameterTypes.length != o.parameterTypes.length) { + return parameterTypes.length - o.parameterTypes.length; + } + + for (int i = 0; i < parameterTypes.length; i++) { + Type t1 = parameterTypes[i]; + Type t2 = o.parameterTypes[i]; + int ct = t1.toString().compareTo(t2.toString()); + if (ct != 0) { + return ct; + } + } + + return 0; + } + + public String getClassName() { + return className; + } + + public String getClassNameShort() { + return classNameShort; + } + + public String getMethodName() { + return methodName; + } + + public TypeVariable[] getTypeParameters() { + return typeParameters; + } + + public Type getReturnType() { + return returnType; + } + + public Class getReturnClass() { + if (returnType == null) { + return null; + } + + try { + return TypeUtils.getErasedType(returnType); + } catch (UnsupportedOperationException e) { + log.warning("Unable to determine Class from returnType=" + returnType.getTypeName()); + return null; + } + } + + public Type[] getParameterTypes() { + return parameterTypes; + } + + public String[] getParameterNames() { + return parameterNames; + } + + public boolean isVarArgs() { + return isVarArgs; + } + + /** + * Creates a new JavaFunction with the same signature, but with new class and method names. + * + * @param className class name or null if the current name should be used. + * @param classNameShort short class name or null if the current short name should be used. + * @param methodName method name or null if the current name should be used. + * @param returnType return type or null if the current return type should be used. + * @return a new JavaFunction with the same signature, but with new class and method names. + */ + public JavaFunction transform(final String className, final String classNameShort, final String methodName, + Type returnType) { + return new JavaFunction( + className == null ? this.className : className, + classNameShort == null ? this.classNameShort : classNameShort, + methodName == null ? this.methodName : methodName, + getTypeParameters(), + returnType == null ? getReturnType() : returnType, + getParameterTypes(), + getParameterNames(), + isVarArgs()); + } +} diff --git a/Generators/src/main/java/io/deephaven/libs/GroovyStaticImportGenerator.java b/Generators/src/main/java/io/deephaven/libs/GroovyStaticImportGenerator.java index 668447631b0..6af9734b7b0 100644 --- a/Generators/src/main/java/io/deephaven/libs/GroovyStaticImportGenerator.java +++ b/Generators/src/main/java/io/deephaven/libs/GroovyStaticImportGenerator.java @@ -3,18 +3,17 @@ */ package io.deephaven.libs; -import io.deephaven.util.type.TypeUtils; -import org.jetbrains.annotations.NotNull; +import io.deephaven.gen.AbstractBasicJavaGenerator; +import io.deephaven.gen.GenUtils; +import io.deephaven.gen.JavaFunction; import java.io.IOException; -import java.io.PrintWriter; -import java.lang.reflect.*; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.*; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.function.Predicate; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.stream.Collectors; @@ -23,385 +22,45 @@ * causes some of the functions to not be present in the namespace. This class combines static imports from multiple * sources into a single class that can be imported. */ -public class GroovyStaticImportGenerator { - private static Logger log = Logger.getLogger(GroovyStaticImportGenerator.class.toString()); +public class GroovyStaticImportGenerator extends AbstractBasicJavaGenerator { - public static class JavaFunction implements Comparable { - private final String className; - private final String classNameShort; - private final String methodName; - private final TypeVariable[] typeParameters; - private final Type returnType; - private final Type[] parameterTypes; - private final String[] parameterNames; - private final boolean isVarArgs; - - public JavaFunction(final String className, final String classNameShort, final String methodName, - final TypeVariable[] typeParameters, final Type returnType, final Type[] parameterTypes, - final String[] parameterNames, final boolean isVarArgs) { - this.className = className; - this.classNameShort = classNameShort; - this.methodName = methodName; - this.typeParameters = typeParameters; - this.returnType = returnType; - this.parameterTypes = parameterTypes; - this.parameterNames = parameterNames; - this.isVarArgs = isVarArgs; - } - - public JavaFunction(final Method m) { - this( - m.getDeclaringClass().getCanonicalName(), - m.getDeclaringClass().getSimpleName(), - m.getName(), - m.getTypeParameters(), - m.getGenericReturnType(), - m.getGenericParameterTypes(), - Arrays.stream(m.getParameters()).map(Parameter::getName).toArray(String[]::new), - m.isVarArgs()); - - for (Parameter parameter : m.getParameters()) { - if (!parameter.isNamePresent()) { - throw new IllegalArgumentException( - "Parameter names are not present in the code! Was the code compiled with \"-parameters\": " - + toString()); - } - } - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - JavaFunction that = (JavaFunction) o; - - if (methodName != null ? !methodName.equals(that.methodName) : that.methodName != null) - return false; - // Probably incorrect - comparing Object[] arrays with Arrays.equals - return Arrays.equals(parameterTypes, that.parameterTypes); - - } - - @Override - public int hashCode() { - int result = methodName != null ? methodName.hashCode() : 0; - result = 31 * result + Arrays.hashCode(parameterTypes); - return result; - } - - @Override - public String toString() { - return "JavaFunction{" + - "className='" + className + '\'' + - ", methodName='" + methodName + '\'' + - ", typeParameters=" + Arrays.toString(typeParameters) + - ", returnType=" + returnType + - ", parameterTypes=" + Arrays.toString(parameterTypes) + - ", parameterNames=" + Arrays.toString(parameterNames) + - '}'; - } - - @Override - public int compareTo(@NotNull JavaFunction o) { - int cm = methodName.compareTo(o.methodName); - if (cm != 0) { - return cm; - } - if (parameterTypes.length != o.parameterTypes.length) { - return parameterTypes.length - o.parameterTypes.length; - } - - for (int i = 0; i < parameterTypes.length; i++) { - Type t1 = parameterTypes[i]; - Type t2 = o.parameterTypes[i]; - int ct = t1.toString().compareTo(t2.toString()); - if (ct != 0) { - return ct; - } - } - - return 0; - } - - public String getClassName() { - return className; - } - - public String getClassNameShort() { - return classNameShort; - } - - public String getMethodName() { - return methodName; - } - - public TypeVariable[] getTypeParameters() { - return typeParameters; - } - - public Type getReturnType() { - return returnType; - } - - public Class getReturnClass() { - if (returnType == null) { - return null; - } - - try { - return TypeUtils.getErasedType(returnType); - } catch (UnsupportedOperationException e) { - log.warning("Unable to determine Class from returnType=" + returnType.getTypeName()); - return null; - } - } - - public Type[] getParameterTypes() { - return parameterTypes; - } - - public String[] getParameterNames() { - return parameterNames; - } - - public boolean isVarArgs() { - return isVarArgs; - } - } - - - private final Map staticFunctions = new TreeMap<>(); - private final Collection> skips; - - private GroovyStaticImportGenerator(final String[] imports, Collection> skips) + public GroovyStaticImportGenerator(String gradleTask, String packageName, String className, String[] imports, + Predicate includeMethod, Collection> skipsGen) throws ClassNotFoundException { - this.skips = skips; - - for (String imp : imports) { - Class c = Class.forName(imp, false, Thread.currentThread().getContextClassLoader()); - log.info("Processing class: " + c); - - for (Method m : c.getMethods()) { - log.info("Processing method (" + c + "): " + m); - boolean isStatic = Modifier.isStatic(m.getModifiers()); - boolean isPublic = Modifier.isPublic(m.getModifiers()); - - if (isStatic && isPublic) { - addPublicStatic(m); - } - } - } - } - - private void addPublicStatic(Method m) { - log.info("Processing public static method: " + m); - - JavaFunction f = new JavaFunction(m); - // System.out.println(f); - - if (staticFunctions.containsKey(f)) { - JavaFunction fAlready = staticFunctions.get(f); - final String message = "Signature Already Present: " + fAlready + "\t" + f; - log.severe(message); - throw new RuntimeException(message); - } else { - log.info("Added public static method: " + f); - staticFunctions.put(f, f); - } - } - - private Set generateImports() { - Set imports = new TreeSet<>(); - - for (JavaFunction f : staticFunctions.keySet()) { - imports.add(f.className); - - imports.addAll(typesToImport(f.returnType)); - - for (Type t : f.parameterTypes) { - imports.addAll(typesToImport(t)); - } - } - - return imports; + super(gradleTask, packageName, className, imports, includeMethod, skipsGen); } - private static Set typesToImport(Type t) { - Set result = new LinkedHashSet<>(); - - if (t instanceof Class) { - final Class c = (Class) t; - final boolean isArray = c.isArray(); - final boolean isPrimitive = c.isPrimitive(); - - if (isPrimitive) { - return result; - } else if (isArray) { - return typesToImport(c.getComponentType()); - } else { - result.add(t.getTypeName()); - } - } else if (t instanceof ParameterizedType) { - final ParameterizedType pt = (ParameterizedType) t; - result.add(pt.getRawType().getTypeName()); - - for (Type a : pt.getActualTypeArguments()) { - result.addAll(typesToImport(a)); - } - } else if (t instanceof TypeVariable) { - // type variables are generic so they don't need importing - return result; - } else if (t instanceof GenericArrayType) { - GenericArrayType at = (GenericArrayType) t; - return typesToImport(at.getGenericComponentType()); - } else { - throw new UnsupportedOperationException("Unsupported Type type: " + t.getClass()); - } - - return result; - } - - private String generateCode() { - - String code = "/**\n" + - " * Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending\n" + - " */\n" + - "/****************************************************************************************************************************\n" - + - " ****** AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - Run GroovyStaticImportGenerator or \"./gradlew :Generators:groovyStaticImportGenerator\" to regenerate\n" - + - " ****************************************************************************************************************************/\n\n"; - - code += "package io.deephaven.libs;\n\n"; - - Set imports = generateImports(); - - for (String imp : imports) { - code += "import " + imp + ";\n"; - } - - code += "\n"; + @Override + public String generateClassJavadoc() { + String code = ""; code += "/**\n"; code += " * Functions statically imported into Groovy.\n"; code += " *\n"; code += " * @see io.deephaven.function\n"; code += " */\n"; - code += "public class GroovyStaticImports {\n"; - - for (JavaFunction f : staticFunctions.keySet()) { - boolean skip = false; - for (Predicate skipCheck : skips) { - skip = skip || skipCheck.test(f); - } - - if (skip) { - log.warning("*** Skipping function: " + f); - continue; - } - - String returnType = f.returnType.getTypeName(); - String s = - " /** @see " + f.getClassName() + "#" + f.getMethodName() + "(" + - Arrays.stream(f.parameterTypes).map(t -> getParamTypeString(t)) - .collect(Collectors.joining(",")) - + - ") */\n" + - " public static "; - - if (f.typeParameters.length > 0) { - s += "<"; - - for (int i = 0; i < f.typeParameters.length; i++) { - if (i != 0) { - s += ","; - } - - TypeVariable t = f.typeParameters[i]; - log.info("BOUNDS: " + Arrays.toString(t.getBounds())); - s += t; - - Type[] bounds = t.getBounds(); - - if (bounds.length != 1) { - throw new RuntimeException("Unsupported bounds: " + Arrays.toString(bounds)); - } - - Type bound = bounds[0]; - - if (!bound.equals(Object.class)) { - s += " extends " + bound.getTypeName(); - } - - } - - s += ">"; - } - - s += " " + returnType + " " + f.methodName + "("; - String callArgs = ""; - - for (int i = 0; i < f.parameterTypes.length; i++) { - if (i != 0) { - s += ","; - callArgs += ","; - } - - Type t = f.parameterTypes[i]; - - s += " " + t.getTypeName() + " " + f.parameterNames[i]; - callArgs += " " + f.parameterNames[i]; - } - - s += " ) {"; - s += "return " + f.classNameShort + "." + f.methodName + "(" + callArgs + " );"; - s += "}"; - - code += s; - code += "\n"; - } - - code += "}\n\n"; - return code; } - /** - * Helper to transform method parameter types to a form that can be used in a javadoc link, including removing - * generics and finding the upper bound of typevars. - */ - @NotNull - private String getParamTypeString(Type t) { - if (t instanceof ParameterizedType) { - return ((ParameterizedType) t).getRawType().getTypeName(); - } else if (t instanceof TypeVariable) { - return getParamTypeString(((TypeVariable) t).getBounds()[0]); - } else if (t instanceof WildcardType) { - return getParamTypeString(((WildcardType) t).getUpperBounds()[0]); - } else if (t instanceof GenericArrayType) { - return getParamTypeString(((GenericArrayType) t).getGenericComponentType()) + "[]"; - } - return t.getTypeName(); + @Override + public String generateFunction(JavaFunction f) { + final String javadoc = " /** @see " + f.getClassName() + "#" + f.getMethodName() + "(" + + Arrays.stream(f.getParameterTypes()).map(GenUtils::javadocLinkParamTypeString) + .collect(Collectors.joining(",")) + + + ") */"; + final String sigPrefix = "public static"; + final String callArgs = GenUtils.javaArgString(f, false); + final String funcBody = + " {return " + f.getClassNameShort() + "." + f.getMethodName() + "(" + callArgs + " );}\n"; + return GenUtils.javaFunction(f, sigPrefix, javadoc, funcBody); } public static void main(String[] args) throws ClassNotFoundException, IOException { + final String gradleTask = ":Generators:groovyStaticImportGenerator"; + final String packageName = "io.deephaven.libs"; + final String className = "GroovyStaticImports"; - String devroot = null; - boolean assertNoChange = false; - if (args.length == 1) { - devroot = args[0]; - } else if (args.length == 2) { - devroot = args[0]; - assertNoChange = Boolean.parseBoolean(args[1]); - } else { - System.out.println("Usage: [assertNoChange]"); - System.exit(-1); - } - - log.setLevel(Level.WARNING); - log.warning("Running GroovyStaticImportGenerator assertNoChange=" + assertNoChange); + final String relativeFilePath = "/engine/table/src/main/java/io/deephaven/libs/GroovyStaticImports.java"; final String[] imports = { "io.deephaven.function.Basic", @@ -415,33 +74,14 @@ public static void main(String[] args) throws ClassNotFoundException, IOExceptio "io.deephaven.function.Sort", }; - @SuppressWarnings("unchecked") - GroovyStaticImportGenerator gen = new GroovyStaticImportGenerator(imports, + GroovyStaticImportGenerator gen = new GroovyStaticImportGenerator(gradleTask, packageName, className, imports, + (m) -> Modifier.isStatic(m.getModifiers()) && Modifier.isPublic(m.getModifiers()), // skipping common erasure "sum" - Collections.singletonList((f) -> f.methodName.equals("sum") && f.parameterTypes.length == 1 - && f.parameterTypes[0].getTypeName() + Collections.singletonList((f) -> f.getMethodName().equals("sum") && f.getParameterTypes().length == 1 + && f.getParameterTypes()[0].getTypeName() .contains("ObjectVector<"))); - final String code = gen.generateCode(); - log.info("\n\n**************************************\n\n"); - log.info(code); - - String file = devroot + "/engine/table/src/main/java/io/deephaven/libs/GroovyStaticImports.java"; - - if (assertNoChange) { - String oldCode = new String(Files.readAllBytes(Paths.get(file))); - if (!code.equals(oldCode)) { - throw new RuntimeException( - "Change in generated code. Run GroovyStaticImportGenerator or \"./gradlew :Generators:groovyStaticImportGenerator\" to regenerate\n"); - } - } else { - - PrintWriter out = new PrintWriter(file); - out.print(code); - out.close(); - - log.warning("io.deephaven.libs.GroovyStaticImports.java written to: " + file); - } + runCommandLine(gen, relativeFilePath, args); } } diff --git a/Generators/src/main/java/io/deephaven/libs/StaticCalendarMethodsGenerator.java b/Generators/src/main/java/io/deephaven/libs/StaticCalendarMethodsGenerator.java new file mode 100644 index 00000000000..75c3c6183d0 --- /dev/null +++ b/Generators/src/main/java/io/deephaven/libs/StaticCalendarMethodsGenerator.java @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ +package io.deephaven.libs; + +import io.deephaven.gen.AbstractBasicJavaGenerator; +import io.deephaven.gen.GenUtils; +import io.deephaven.gen.JavaFunction; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * Generate a static library containing methods that use the default business calendar. + */ +public class StaticCalendarMethodsGenerator extends AbstractBasicJavaGenerator { + + final Function renamer; + + public StaticCalendarMethodsGenerator(String gradleTask, String packageName, String className, String[] imports, + Predicate includeMethod, Collection> skipsGen, + Function renamer) throws ClassNotFoundException { + super(gradleTask, packageName, className, imports, includeMethod, skipsGen); + this.renamer = renamer; + } + + @Override + public String generateClassJavadoc() { + String code = ""; + code += "/**\n"; + code += " * Static versions of business calendar methods that use the default business calendar.\n"; + code += " *\n"; + code += " * @see io.deephaven.time.calendar\n"; + code += " * @see io.deephaven.time.calendar.Calendar\n"; + code += " * @see io.deephaven.time.calendar.BusinessCalendar\n"; + code += " * @see io.deephaven.time.calendar.Calendars\n"; + code += " */\n"; + return code; + } + + @Override + public String generateFunction(JavaFunction f) { + + final String rename = renamer.apply(f.getMethodName()); + final JavaFunction f2 = f.transform(null, null, rename, null); + + final String javadoc = " /** @see " + f.getClassName() + "#" + f.getMethodName() + "(" + + Arrays.stream(f.getParameterTypes()).map(GenUtils::javadocLinkParamTypeString) + .collect(Collectors.joining(",")) + + + ") */"; + final String sigPrefix = "public static"; + final String callArgs = GenUtils.javaArgString(f2, false); + final String funcBody = " {return Calendars.calendar()." + f.getMethodName() + "(" + callArgs + " );}\n"; + return GenUtils.javaFunction(f2, sigPrefix, javadoc, funcBody); + } + + public static void main(String[] args) throws ClassNotFoundException, IOException { + final String gradleTask = ":Generators:generateStaticCalendarMethods"; + final String packageName = "io.deephaven.time.calendar"; + final String className = "StaticCalendarMethods"; + + final String relativeFilePath = + "/engine/time/src/main/java/io/deephaven/time/calendar/StaticCalendarMethods.java"; + + final String[] imports = { + "io.deephaven.time.calendar.BusinessCalendar", + }; + + final Set excludes = new HashSet<>(); + excludes.add("toString"); + excludes.add("name"); + excludes.add("description"); + excludes.add("firstValidDate"); + excludes.add("lastValidDate"); + + StaticCalendarMethodsGenerator gen = + new StaticCalendarMethodsGenerator(gradleTask, packageName, className, imports, + (m) -> Modifier.isPublic(m.getModifiers()) && !m.getDeclaringClass().equals(Object.class), + Collections.singletonList((f) -> excludes.contains(f.getMethodName())), + (s) -> { + if (s.equals("dayOfWeek")) { + return "calendarDayOfWeek"; + } else if (s.equals("dayOfWeekValue")) { + return "calendarDayOfWeekValue"; + } else if (s.equals("timeZone")) { + return "calendarTimeZone"; + } else { + return s; + } + }); + + runCommandLine(gen, relativeFilePath, args); + } + +} diff --git a/Generators/src/main/java/io/deephaven/plot/util/GenerateAxesPlotMethods.java b/Generators/src/main/java/io/deephaven/plot/util/GenerateAxesPlotMethods.java index f648b10d95a..c2bbba7739f 100644 --- a/Generators/src/main/java/io/deephaven/plot/util/GenerateAxesPlotMethods.java +++ b/Generators/src/main/java/io/deephaven/plot/util/GenerateAxesPlotMethods.java @@ -4,6 +4,7 @@ package io.deephaven.plot.util; import io.deephaven.base.verify.Require; +import io.deephaven.gen.GenUtils; import java.io.IOException; import java.io.PrintWriter; @@ -20,6 +21,7 @@ public class GenerateAxesPlotMethods { private static final Logger log = Logger.getLogger(GenerateAxesPlotMethods.class.toString()); + private static final String GRADLE_TASK = ":Generators:generateAxesPlotMethods"; private static final String PLOT_INFO_ID = "new PlotInfo(this, seriesName)"; @@ -863,10 +865,7 @@ private static void generate(final boolean assertNoChange, final String file, fi if (assertNoChange) { String oldCode = new String(Files.readAllBytes(Paths.get(file))); - if (!newcode.equals(oldCode)) { - throw new RuntimeException( - "Change in generated code. Run GenerateAxesPlotMethods or \"./gradlew :Generators:generateAxesPlotMethods\" to regenerate\n"); - } + GenUtils.assertGeneratedCodeSame(GenerateAxesPlotMethods.class, GRADLE_TASK, oldCode, newcode); } else { PrintWriter out = new PrintWriter(file); diff --git a/Generators/src/main/java/io/deephaven/plot/util/GenerateFigureImmutable.java b/Generators/src/main/java/io/deephaven/plot/util/GenerateFigureImmutable.java index f144fed8f1c..89acf744da8 100644 --- a/Generators/src/main/java/io/deephaven/plot/util/GenerateFigureImmutable.java +++ b/Generators/src/main/java/io/deephaven/plot/util/GenerateFigureImmutable.java @@ -3,12 +3,12 @@ */ package io.deephaven.plot.util; +import io.deephaven.gen.GenUtils; import io.deephaven.plot.*; import io.deephaven.plot.datasets.DataSeries; import io.deephaven.plot.datasets.multiseries.MultiSeries; import io.deephaven.plot.errors.PlotExceptionCause; -import io.deephaven.libs.GroovyStaticImportGenerator; -import io.deephaven.libs.GroovyStaticImportGenerator.JavaFunction; +import io.deephaven.gen.JavaFunction; import java.io.IOException; import java.io.PrintWriter; @@ -23,7 +23,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static io.deephaven.plot.util.PlotGeneratorUtils.indent; +import static io.deephaven.gen.GenUtils.indent; +import static io.deephaven.gen.GenUtils.typesToImport; /** * Creates a functional interface for plotting. @@ -33,6 +34,7 @@ public class GenerateFigureImmutable { // See also GroovyStaticImportGenerator private static final Logger log = Logger.getLogger(GenerateFigureImmutable.class.toString()); + private static final String GRADLE_TASK = ":Generators:generateFigureImmutable"; private static final String CLASS_NAME_INTERFACE = "io.deephaven.plot.Figure"; private static final String CLASS_NAME_IMPLEMENTATION = "io.deephaven.plot.FigureImpl"; @@ -91,15 +93,14 @@ private boolean skip(final JavaFunction f) { private JavaFunction signature(final JavaFunction f) { - return new JavaFunction( - outputClass, - outputClassNameShort, - functionNamer.apply(f), - f.getTypeParameters(), - f.getReturnType(), - f.getParameterTypes(), - f.getParameterNames(), - f.isVarArgs()); + final Type returnType = new Type() { + @Override + public String getTypeName() { + return isInterface ? "Figure" : "FigureImpl"; + } + }; + + return f.transform(outputClass, outputClassNameShort, functionNamer.apply(f), returnType); } private void addPublicNonStatic(Method m) { @@ -157,41 +158,6 @@ private Set generateImports() { return imports; } - private static Set typesToImport(Type t) { - Set result = new LinkedHashSet<>(); - - if (t instanceof Class) { - final Class c = (Class) t; - final boolean isArray = c.isArray(); - final boolean isPrimitive = c.isPrimitive(); - - if (isPrimitive) { - return result; - } else if (isArray) { - return typesToImport(c.getComponentType()); - } else { - result.add(t.getTypeName()); - } - } else if (t instanceof ParameterizedType) { - final ParameterizedType pt = (ParameterizedType) t; - result.add(pt.getRawType().getTypeName()); - - for (Type a : pt.getActualTypeArguments()) { - result.addAll(typesToImport(a)); - } - } else if (t instanceof TypeVariable) { - // type variables are generic so they don't need importing - return result; - } else if (t instanceof GenericArrayType) { - GenericArrayType at = (GenericArrayType) t; - return typesToImport(at.getGenericComponentType()); - } else { - throw new UnsupportedOperationException("Unsupported Type type: " + t.getClass()); - } - - return result; - } - private String generateImplements() { final StringBuilder sb = new StringBuilder(); @@ -209,15 +175,7 @@ private String generateImplements() { private String generateCode() { - String code = "/**\n" + - " * Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending\n" + - " */\n" + - "/****************************************************************************************************************************\n" - + - " ****** AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - Run GenerateFigureImmutable or \"./gradlew :Generators:generateFigureImmutable\" to regenerate\n" - + - " ****************************************************************************************************************************/\n\n"; - + String code = GenUtils.javaHeader(GenerateFigureImmutable.class, GRADLE_TASK); code += "package io.deephaven.plot;\n\n"; Set imports = generateImports(); @@ -229,7 +187,7 @@ private String generateCode() { code += "\n"; code += "/** An interface for constructing plots. A Figure is immutable, and all function calls return a new immutable Figure instance."; code += "*/\n"; - code += "@SuppressWarnings({\"unused\", \"RedundantCast\", \"SameParameterValue\"})\n"; + code += "@SuppressWarnings({\"unused\", \"RedundantCast\", \"SameParameterValue\", \"rawtypes\"})\n"; code += "public" + (isInterface ? " interface " : " class ") + outputClassNameShort + generateImplements() + " {\n"; @@ -659,6 +617,7 @@ private String createFigureFuncs() { + "\n"); } + @SuppressWarnings("DuplicateBranchesInSwitch") private static String createInstanceGetter(final JavaFunction f) { switch (f.getClassName()) { case "io.deephaven.plot.BaseFigure": @@ -680,136 +639,80 @@ private static String createInstanceGetter(final JavaFunction f) { } private String createFunctionSignature(final JavaFunction f) { - String s = " " + (isInterface ? "@Override " : "@Override public "); - - if (f.getTypeParameters().length > 0) { - s += "<"; - - for (int i = 0; i < f.getTypeParameters().length; i++) { - if (i != 0) { - s += ","; - } - - TypeVariable t = f.getTypeParameters()[i]; - log.info("BOUNDS: " + Arrays.toString(t.getBounds())); - s += t; - - Type[] bounds = t.getBounds(); - - if (bounds.length != 1) { - throw new RuntimeException("Unsupported bounds: " + Arrays.toString(bounds)); - } - - Type bound = bounds[0]; - - if (!bound.equals(Object.class)) { - s += " extends " + bound.getTypeName(); - } - - } - - s += ">"; - } - - s += " " + outputClassNameShort + " " + f.getMethodName() + "("; - - for (int i = 0; i < f.getParameterTypes().length; i++) { - if (i != 0) { - s += ","; - } - - Type t = f.getParameterTypes()[i]; - - String typeString = t.getTypeName().replace("$", "."); - - if (f.isVarArgs() && i == f.getParameterTypes().length - 1) { - final int index = typeString.lastIndexOf("[]"); - typeString = typeString.substring(0, index) + "..." + typeString.substring(index + 2); - } - - s += " " + typeString + " " + f.getParameterNames()[i]; - } - - s += " )"; - - return s; - } - - private static String createCallArgs(final JavaFunction f) { - String callArgs = ""; - - for (int i = 0; i < f.getParameterTypes().length; i++) { - if (i != 0) { - callArgs += ","; - } - - callArgs += " " + f.getParameterNames()[i]; - } - - return callArgs; + return GenUtils.javaFunctionSignature(f, (isInterface ? "@Override" : "@Override public")); } private String createFunction(final JavaFunction f) { - final String returnType = f.getReturnType().getTypeName().replace("$", "."); - final Class returnClass = f.getReturnClass(); + final Class returnClass = f.getReturnClass(); final JavaFunction signature = signature(f); - String s = createFunctionSignature(f); + String sigPrefix; + String javadoc = null; + String funcBody; if (isInterface) { - return s + ";\n"; - } - - final String callArgs = createCallArgs(f); - - s += " {\n" + indent(2) + "final BaseFigureImpl fc = this.figure.copy();\n"; - - if (returnClass != null && BaseFigure.class.isAssignableFrom(returnClass)) { - s += indent(2) + createInstanceGetter(f) + "." + signature.getMethodName() + "(" + callArgs + ");\n" + - indent(2) + "return make(fc);\n"; - } else if (returnClass != null && Chart.class.isAssignableFrom(returnClass)) { - s += indent(2) + "final ChartImpl chart = (ChartImpl) " + createInstanceGetter(f) + "." - + signature.getMethodName() + "(" + callArgs + ");\n" + - indent(2) + "return make(chart);\n"; - } else if (returnClass != null && Axes.class.isAssignableFrom(returnClass)) { - s += indent(2) + "final AxesImpl axes = (AxesImpl) " + createInstanceGetter(f) + "." - + signature.getMethodName() + "(" + callArgs + ");\n" + - indent(2) + "return make(axes);\n"; - } else if (returnClass != null && Axis.class.isAssignableFrom(returnClass) - && f.getClassName().equals("io.deephaven.plot.Axes")) { - s += indent(2) + "final AxesImpl axes = " + createInstanceGetter(f) + ";\n"; - s += indent(2) + "final AxisImpl axis = (AxisImpl) axes." + signature.getMethodName() + "(" + callArgs - + ");\n" + - indent(2) + "return make(axes, axis);\n"; - } else if (returnClass != null && Axis.class.isAssignableFrom(returnClass)) { - s += indent(2) + "final AxisImpl axis = (AxisImpl) " + createInstanceGetter(f) + "." - + signature.getMethodName() + "(" + callArgs + ");\n" + - indent(2) + "return make(null, axis);\n"; - } else if (returnClass != null && DataSeries.class.isAssignableFrom(returnClass)) { - s += indent(2) + "final DataSeriesInternal series = (DataSeriesInternal) " + createInstanceGetter(f) + "." - + signature.getMethodName() + "(" + callArgs + ");\n" + - indent(2) + "return make(series);\n"; - } else if (returnClass != null && Series.class.isAssignableFrom(returnClass)) { - s += indent(2) + "final SeriesInternal series = (SeriesInternal) " + createInstanceGetter(f) + "." - + signature.getMethodName() + "(" + callArgs + ");\n" + - indent(2) + "return make(series);\n"; - } else if (returnClass != null && MultiSeries.class.isAssignableFrom(returnClass)) { - s += indent(2) + "final " + returnClass.getSimpleName() + " mseries = " + createInstanceGetter(f) + "." - + signature.getMethodName() + "(" + callArgs + ");\n" + - indent(2) + "return make((SeriesInternal) mseries);\n"; - } else if (returnClass != null && void.class.equals(returnClass)) { - s += indent(2) + createInstanceGetter(f) + "." + signature.getMethodName() + "(" + callArgs + ");\n" + - indent(2) + "return make(fc);\n"; + sigPrefix = "@Override"; + funcBody = ";\n"; } else { - System.out.println("WARN: UnsupportedReturnType: " + returnType + " " + f); + final String callArgs = GenUtils.javaArgString(f, false); + sigPrefix = "@Override public"; + funcBody = " {\n" + indent(2) + "final BaseFigureImpl fc = this.figure.copy();\n"; + + if (returnClass != null && BaseFigure.class.isAssignableFrom(returnClass)) { + funcBody += indent(2) + createInstanceGetter(f) + "." + signature.getMethodName() + "(" + callArgs + + ");\n" + + indent(2) + "return make(fc);\n"; + } else if (returnClass != null && Chart.class.isAssignableFrom(returnClass)) { + funcBody += indent(2) + "final ChartImpl chart = (ChartImpl) " + createInstanceGetter(f) + "." + + signature.getMethodName() + "(" + callArgs + ");\n" + + indent(2) + "return make(chart);\n"; + } else if (returnClass != null && Axes.class.isAssignableFrom(returnClass)) { + funcBody += indent(2) + "final AxesImpl axes = (AxesImpl) " + createInstanceGetter(f) + "." + + signature.getMethodName() + "(" + callArgs + ");\n" + + indent(2) + "return make(axes);\n"; + } else if (returnClass != null && Axis.class.isAssignableFrom(returnClass) + && f.getClassName().equals("io.deephaven.plot.Axes")) { + funcBody += indent(2) + "final AxesImpl axes = " + createInstanceGetter(f) + ";\n"; + funcBody += indent(2) + "final AxisImpl axis = (AxisImpl) axes." + signature.getMethodName() + "(" + + callArgs + + ");\n" + + indent(2) + "return make(axes, axis);\n"; + } else if (returnClass != null && Axis.class.isAssignableFrom(returnClass)) { + funcBody += indent(2) + "final AxisImpl axis = (AxisImpl) " + createInstanceGetter(f) + "." + + signature.getMethodName() + "(" + callArgs + ");\n" + + indent(2) + "return make(null, axis);\n"; + } else if (returnClass != null && DataSeries.class.isAssignableFrom(returnClass)) { + funcBody += indent(2) + "final DataSeriesInternal series = (DataSeriesInternal) " + + createInstanceGetter(f) + "." + + signature.getMethodName() + "(" + callArgs + ");\n" + + indent(2) + "return make(series);\n"; + } else if (returnClass != null && Series.class.isAssignableFrom(returnClass)) { + funcBody += + indent(2) + "final SeriesInternal series = (SeriesInternal) " + createInstanceGetter(f) + "." + + signature.getMethodName() + "(" + callArgs + ");\n" + + indent(2) + "return make(series);\n"; + } else if (returnClass != null && MultiSeries.class.isAssignableFrom(returnClass)) { + funcBody += indent(2) + "final " + returnClass.getSimpleName() + " mseries = " + createInstanceGetter(f) + + "." + + signature.getMethodName() + "(" + callArgs + ");\n" + + indent(2) + "return make((SeriesInternal) mseries);\n"; + } else if (void.class.equals(returnClass)) { + funcBody += indent(2) + createInstanceGetter(f) + "." + signature.getMethodName() + "(" + callArgs + + ");\n" + + indent(2) + "return make(fc);\n"; + } else { + final String returnType = f.getReturnType().getTypeName().replace("$", "."); + System.out.println("WARN: UnsupportedReturnType: " + returnType + " " + f); - s += indent(2) + createInstanceGetter(f) + "." + signature.getMethodName() + "(" + callArgs + ");\n" + - indent(2) + "return make(fc);\n"; - } + funcBody += indent(2) + createInstanceGetter(f) + "." + signature.getMethodName() + "(" + callArgs + + ");\n" + + indent(2) + "return make(fc);\n"; + } - s += indent(1) + "}\n"; + funcBody += indent(1) + "}\n"; + } - return s; + return GenUtils.javaFunction(signature, sigPrefix, javadoc, funcBody); } private String createSignatureGroupFunction(final TreeSet fs) { @@ -821,72 +724,77 @@ private String createSignatureGroupFunction(final TreeSet fs) { final JavaFunction f0 = fs.first(); final JavaFunction s0 = signature(f0); - - final String signature = createFunctionSignature(s0); + String sigPrefix; + String javadoc = null; + String funcBody; if (isInterface) { - return signature + ";\n"; - } - - final String callArgs = createCallArgs(f0); - - String s = signature; - s += " {\n" + - indent(2) + "final BaseFigureImpl fc = this.figure.copy();\n" + - indent(2) + "Series series = series(fc);\n"; + sigPrefix = "@Override"; + funcBody = ";\n"; + } else { + final String callArgs = GenUtils.javaArgString(f0, false); + sigPrefix = "@Override public"; + final String signature = GenUtils.javaFunctionSignature(s0, sigPrefix); + funcBody = " {\n" + + indent(2) + "final BaseFigureImpl fc = this.figure.copy();\n" + + indent(2) + "Series series = series(fc);\n"; - boolean firstFunc = true; + boolean firstFunc = true; - for (final JavaFunction f : fs) { - final String returnType = f.getReturnType().getTypeName().replace("$", "."); - Class returnClass = f.getReturnClass(); + for (final JavaFunction f : fs) { + final String returnType = f.getReturnType().getTypeName().replace("$", "."); + Class returnClass = f.getReturnClass(); - if (returnClass == null) { - throw new UnsupportedOperationException("Null return class. f=" + f); - } + if (returnClass == null) { + throw new UnsupportedOperationException("Null return class. f=" + f); + } - if (firstFunc) { - s += indent(2) + "if( series instanceof " + f.getClassNameShort() + "){\n"; - } else { - s += indent(2) + "} else if( series instanceof " + f.getClassNameShort() + "){\n"; - } + if (firstFunc) { + funcBody += indent(2) + "if( series instanceof " + f.getClassNameShort() + "){\n"; + } else { + funcBody += indent(2) + "} else if( series instanceof " + f.getClassNameShort() + "){\n"; + } - s += indent(3) + returnClass.getSimpleName() + " result = ((" + f.getClassNameShort() + ") series)." - + f.getMethodName() + "(" + callArgs + ");\n"; + funcBody += + indent(3) + returnClass.getSimpleName() + " result = ((" + f.getClassNameShort() + ") series)." + + f.getMethodName() + "(" + callArgs + ");\n"; + + if (DataSeries.class.isAssignableFrom(returnClass)) { + funcBody += indent(3) + "return make((DataSeriesInternal)result);\n"; + } else if (MultiSeries.class.isAssignableFrom(returnClass) + || Series.class.isAssignableFrom(returnClass)) { + funcBody += indent(3) + "return make((SeriesInternal)result);\n"; + } else { + throw new IllegalStateException("UnsupportedReturnType: " + returnType + " " + f); + // System.out.println("WARN: UnsupportedReturnType: " + returnType + " " + f); + // funcBody += indent(3) + "return make(fc);"; + } - if (DataSeries.class.isAssignableFrom(returnClass)) { - s += indent(3) + "return make((DataSeriesInternal)result);\n"; - } else if (MultiSeries.class.isAssignableFrom(returnClass) || Series.class.isAssignableFrom(returnClass)) { - s += indent(3) + "return make((SeriesInternal)result);\n"; - } else { - throw new IllegalStateException("UnsupportedReturnType: " + returnType + " " + f); - // System.out.println("WARN: UnsupportedReturnType: " + returnType + " " + f); - // s += indent(3) + "return make(fc);"; - } + funcBody += indent(2) + "} "; - s += indent(2) + "} "; + if (!f.getClassNameShort().equals("MultiSeries") + && !f.getClassNameShort().equals("XYDataSeriesFunction")) { + funcBody += makeMultiSeriesGetter(f); + } - if (!f.getClassNameShort().equals("MultiSeries") && !f.getClassNameShort().equals("XYDataSeriesFunction")) { - s += makeMultiSeriesGetter(f); + firstFunc = false; } - - firstFunc = false; + funcBody += "else {\n" + + indent(3) + + "throw new PlotUnsupportedOperationException(\"Series type does not support this method. seriesType=\" + series.getClass() + \" method='" + + signature.trim() + "'\", figure);\n" + + indent(2) + "}\n"; + funcBody += indent(1) + "}\n"; } - s += "else {\n" + - indent(3) - + "throw new PlotUnsupportedOperationException(\"Series type does not support this method. seriesType=\" + series.getClass() + \" method='" - + signature.trim() + "'\", figure);\n" + - indent(2) + "}\n"; - s += indent(1) + "}\n"; - - return s; + + return GenUtils.javaFunction(s0, sigPrefix, javadoc, funcBody); } - private Map> commonSignatureGroups( + private Map> commonSignatureGroups( final String[] interfaces) throws ClassNotFoundException { - final Map> methods = new TreeMap<>(); + final Map> methods = new TreeMap<>(); - final Set functionSet = new HashSet<>(); + final Set functionSet = new HashSet<>(); for (String iface : interfaces) { final Class c = Class.forName(iface, false, Thread.currentThread().getContextClassLoader()); log.info("Processing class: " + c); @@ -898,11 +806,11 @@ private Map> commonSig boolean isObject = m.getDeclaringClass().equals(Object.class); if (!isStatic && isPublic && !isObject) { - final GroovyStaticImportGenerator.JavaFunction f = new GroovyStaticImportGenerator.JavaFunction(m); + final JavaFunction f = new JavaFunction(m); if (functionSet.add(f)) { // avoids repeating methods that have the same parameter types but // different parameter names final String key = createFunctionSignature(f); - final TreeSet mm = + final TreeSet mm = methods.computeIfAbsent(key, k -> new TreeSet<>()); mm.add(f); } @@ -923,7 +831,6 @@ private static String makeMultiSeriesGetter(final JavaFunction f) { } private static String createMultiSeriesArgs(JavaFunction f) { - final Type[] types = f.getParameterTypes(); final String[] names = f.getParameterNames(); String args = String.join(", ", names); if (!names[names.length - 1].equals("keys")) { @@ -993,7 +900,6 @@ private static void generateFile(final String devroot, final boolean assertNoCha }); - @SuppressWarnings("unchecked") GenerateFigureImmutable gen = new GenerateFigureImmutable(isInterface, imports, interfaces, seriesInterfaces, skips, JavaFunction::getMethodName); @@ -1005,10 +911,7 @@ private static void generateFile(final String devroot, final boolean assertNoCha if (assertNoChange) { String oldCode = new String(Files.readAllBytes(Paths.get(file))); - if (!code.equals(oldCode)) { - throw new RuntimeException( - "Change in generated code. Run GenerateFigureImmutable or \"./gradlew :Generators:generateFigureImmutable\" to regenerate\n"); - } + GenUtils.assertGeneratedCodeSame(GenerateFigureImmutable.class, GRADLE_TASK, oldCode, code); } else { PrintWriter out = new PrintWriter(file); diff --git a/Generators/src/main/java/io/deephaven/plot/util/GenerateMultiSeries.java b/Generators/src/main/java/io/deephaven/plot/util/GenerateMultiSeries.java index 25f3210aa99..fb2d5fea436 100644 --- a/Generators/src/main/java/io/deephaven/plot/util/GenerateMultiSeries.java +++ b/Generators/src/main/java/io/deephaven/plot/util/GenerateMultiSeries.java @@ -5,9 +5,10 @@ import io.deephaven.base.ClassUtil; import io.deephaven.base.Pair; +import io.deephaven.gen.GenUtils; +import io.deephaven.gen.JavaFunction; import io.deephaven.plot.util.functions.ClosureFunction; import io.deephaven.engine.table.Table; -import io.deephaven.libs.GroovyStaticImportGenerator; import io.deephaven.util.type.TypeUtils; import groovy.lang.Closure; @@ -23,13 +24,15 @@ import java.util.function.Function; import java.util.logging.Logger; -import static io.deephaven.plot.util.PlotGeneratorUtils.indent; +import static io.deephaven.gen.GenUtils.indent; + /** * Generates methods for the MultiSeries datasets. */ public class GenerateMultiSeries { private static final Logger log = Logger.getLogger(GenerateMultiSeries.class.toString()); + private static final String GRADLE_TASK = ":Generators:generateMultiSeries"; public static void main(String[] args) throws ClassNotFoundException, IOException, NoSuchMethodException { @@ -220,10 +223,7 @@ private void generateCode(final String devroot, final boolean assertNoChange, fi if (assertNoChange) { String oldCode = new String(Files.readAllBytes(Paths.get(outputFile))); - if (!newcode.equals(oldCode)) { - throw new RuntimeException("Change in generated code for " + outputFile - + ". Run GenerateMultiSeries or \"./gradlew :Generators:generateMultiSeries\" to regenerate\n"); - } + GenUtils.assertGeneratedCodeSame(GenerateMultiSeries.class, GRADLE_TASK, oldCode, newcode); } else { PrintWriter out = new PrintWriter(outputFile); out.print(newcode); @@ -240,25 +240,25 @@ private String generateClasses(final Set skip) throws ClassNotFoundExcep .append(" series) {\n").append(indent(2)).append("$$initializeSeries$$(series);\n") .append(indent(1)).append("}\n\n"); } - final List sortedMethods = new ArrayList<>(); - final List methodsWithFunctionParameter = new ArrayList<>(); + final List sortedMethods = new ArrayList<>(); + final List methodsWithFunctionParameter = new ArrayList<>(); for (final String clazz : interfaces) { final Class dataseries = Class.forName(clazz, false, Thread.currentThread().getContextClassLoader()); final Method[] methods = Arrays.stream(dataseries.getMethods()) .filter(m -> !skip.contains(m)) .toArray(Method[]::new); - final GroovyStaticImportGenerator.JavaFunction[] functionalMethods = + final JavaFunction[] functionalMethods = filterBadMethods(Arrays.stream(methods) .filter(m -> hasFunction(m.getParameterTypes())) - .map(GroovyStaticImportGenerator.JavaFunction::new) - .toArray(GroovyStaticImportGenerator.JavaFunction[]::new)); + .map(JavaFunction::new) + .toArray(JavaFunction[]::new)); - final GroovyStaticImportGenerator.JavaFunction[] nonFunctionalMethods = + final JavaFunction[] nonFunctionalMethods = Arrays.stream(methods) .filter(m -> !hasFunction(m.getParameterTypes())) - .map(GroovyStaticImportGenerator.JavaFunction::new) - .toArray(GroovyStaticImportGenerator.JavaFunction[]::new); + .map(JavaFunction::new) + .toArray(JavaFunction[]::new); Arrays.sort(functionalMethods); Arrays.sort(nonFunctionalMethods); Collections.addAll(methodsWithFunctionParameter, functionalMethods); @@ -266,7 +266,7 @@ private String generateClasses(final Set skip) throws ClassNotFoundExcep } final Set methodsDone = new HashSet<>(); // used to avoid duplicates - for (final GroovyStaticImportGenerator.JavaFunction function : methodsWithFunctionParameter) { + for (final JavaFunction function : methodsWithFunctionParameter) { final String mapName = createMapName(function); if (!methodsDone.add(mapName)) { continue; @@ -276,8 +276,8 @@ private String generateClasses(final Set skip) throws ClassNotFoundExcep code.append("\n\n"); } - final Map mapToFunction = new HashMap<>(); - for (final GroovyStaticImportGenerator.JavaFunction function : sortedMethods) { + final Map mapToFunction = new HashMap<>(); + for (final JavaFunction function : sortedMethods) { final String mapName = createMapName(function); if (mapToFunction.get(mapName) != null) { continue; @@ -331,9 +331,9 @@ private String createCopyConstructor(final Set strings) { } private String createInitializeFunction( - final Map mapToFunction) { + final Map mapToFunction) { final StringBuilder code = new StringBuilder(); - final Map> functionToGenerics = + final Map> functionToGenerics = createFunctionToGenerics(mapToFunction.values()); code.append(indent(1)).append("@SuppressWarnings(\"unchecked\") \n").append(indent(1)).append("private ") @@ -350,9 +350,9 @@ private String createInitializeFunction( boolean objectArrayInitialized = false; int numConsumers = 0; - for (final Map.Entry entry : mapToFunction.entrySet()) { + for (final Map.Entry entry : mapToFunction.entrySet()) { final String map = entry.getKey(); - final GroovyStaticImportGenerator.JavaFunction function = entry.getValue(); + final JavaFunction function = entry.getValue(); final boolean oneArg = function.getParameterNames().length == 1; if (oneArg) { @@ -429,12 +429,12 @@ private String createInitializeFunctionTransform() { return indent(2) + "this.series.initializeSeries((SERIES2) series);\n" + indent(1) + "}\n"; } - private Map> createFunctionToGenerics( - Collection functionSet) { - final Map> map = new HashMap<>(); + private Map> createFunctionToGenerics( + Collection functionSet) { + final Map> map = new HashMap<>(); final Map generics = new HashMap<>(); final Map counter = new HashMap<>(); - for (final GroovyStaticImportGenerator.JavaFunction function : functionSet) { + for (final JavaFunction function : functionSet) { for (TypeVariable typeVariable : function.getTypeParameters()) { final String typeName = typeVariable.getTypeName(); final Type[] bounds = typeVariable.getBounds(); @@ -466,11 +466,11 @@ private Map> } private String createGenericInitializeSeries( - final Map mapToFunction, - final Map> functionToGenerics) { + final Map mapToFunction, + final Map> functionToGenerics) { final List args = new ArrayList<>(); final Set variableNames = new HashSet<>(); - for (final GroovyStaticImportGenerator.JavaFunction function : mapToFunction.values()) { + for (final JavaFunction function : mapToFunction.values()) { for (final TypeVariable typeVariable : function.getTypeParameters()) { String genericTypes = getGenericTypes(typeVariable); if (!genericTypes.isEmpty()) { @@ -487,7 +487,7 @@ private String createGenericInitializeSeries( return args.isEmpty() ? "" : "<" + String.join(", ", args) + "> "; } - private String createMapName(final GroovyStaticImportGenerator.JavaFunction function) { + private String createMapName(final JavaFunction function) { return "%METHOD%SeriesNameTo%TYPES%Map".replaceAll("%TYPES%", createArgsString(function)) .replaceAll("%METHOD%", function.getMethodName()); } @@ -497,7 +497,7 @@ private String createMap(String mapType, final String mapName) { ".HashMapWithDefault<>();\n"; } - private String createMethod(final String returnClass, final GroovyStaticImportGenerator.JavaFunction function, + private String createMethod(final String returnClass, final JavaFunction function, final String mapName) { final StringBuilder code = new StringBuilder(); code.append(createMethodHeader(returnClass, function)); @@ -519,7 +519,7 @@ private String createGetter(String mapType, String mapName) { } private String createMethodWithFunctionParameter(String returnClass, - GroovyStaticImportGenerator.JavaFunction function) throws ClassNotFoundException { + JavaFunction function) throws ClassNotFoundException { final StringBuilder code = new StringBuilder(); code.append(createMethodHeader(returnClass, function)); if (isTransform) { @@ -533,7 +533,7 @@ private String createMethodWithFunctionParameter(String returnClass, return code.toString(); } - private String createFunctionalBody(final String returnClass, GroovyStaticImportGenerator.JavaFunction function) + private String createFunctionalBody(final String returnClass, JavaFunction function) throws ClassNotFoundException { if (function.getParameterTypes()[0].getTypeName().startsWith("groovy.lang.Closure")) { return indent(2) + "return " + function.getMethodName() @@ -556,7 +556,7 @@ private String createFunctionalBody(final String returnClass, GroovyStaticImport } private String getFigureFunctionInput(final String returnClass, - final GroovyStaticImportGenerator.JavaFunction function, final String tableMethodName) + final JavaFunction function, final String tableMethodName) throws ClassNotFoundException { final StringBuilder code = new StringBuilder(); code.append(isSwappable ? "new SelectableDataSetSwappableTable(getSwappableTable()), " @@ -626,17 +626,17 @@ private String getFigureFunctionInput(final String returnClass, return code.toString(); } - private static GroovyStaticImportGenerator.JavaFunction[] filterBadMethods( - final GroovyStaticImportGenerator.JavaFunction[] functions) { - final List retList = new ArrayList<>(); + private static JavaFunction[] filterBadMethods( + final JavaFunction[] functions) { + final List retList = new ArrayList<>(); - final Map, GroovyStaticImportGenerator.JavaFunction> functionMap = new HashMap<>(); + final Map, JavaFunction> functionMap = new HashMap<>(); - for (final GroovyStaticImportGenerator.JavaFunction function : functions) { + for (final JavaFunction function : functions) { if (function.getParameterTypes()[0].getTypeName().contains("Function")) { final Pair methodPair = new Pair<>(function.getMethodName(), function.getParameterNames().length); - final GroovyStaticImportGenerator.JavaFunction oldFunction = functionMap.get(methodPair); + final JavaFunction oldFunction = functionMap.get(methodPair); if (oldFunction != null) { if (oldFunction.getTypeParameters().length < 1 && function.getTypeParameters().length > 0) { @@ -652,10 +652,10 @@ private static GroovyStaticImportGenerator.JavaFunction[] filterBadMethods( } retList.addAll(functionMap.values()); - return retList.toArray(new GroovyStaticImportGenerator.JavaFunction[0]); + return retList.toArray(new JavaFunction[0]); } - private String getFunctionInput(GroovyStaticImportGenerator.JavaFunction function) { + private String getFunctionInput(JavaFunction function) { if (function.getMethodName().endsWith("ByX")) { return "getX()"; } else if (function.getMethodName().endsWith("ByY")) { @@ -668,7 +668,7 @@ private String getFunctionInput(GroovyStaticImportGenerator.JavaFunction functio + function.getMethodName() + " param class " + function.getParameterTypes()[0].getClass()); } - private String getReturnTypeName(final GroovyStaticImportGenerator.JavaFunction function) { + private String getReturnTypeName(final JavaFunction function) { if (function.getTypeParameters().length < 1) { // non generics final String[] params = function.getParameterTypes()[0].getTypeName().split(","); final String returnType = params[params.length - 1]; @@ -709,7 +709,7 @@ private String getColumnNameConstant(String methodName) { throw new IllegalStateException("No column name constant corresponds to method name " + methodName); } - private String createTransformBody(final GroovyStaticImportGenerator.JavaFunction function) { + private String createTransformBody(final JavaFunction function) { final List args = new ArrayList<>(); Collections.addAll(args, function.getParameterNames()); args.add("multiSeriesKey"); @@ -717,7 +717,7 @@ private String createTransformBody(final GroovyStaticImportGenerator.JavaFunctio + function.getMethodName() + "(" + String.join(", ", args) + ");\n" + indent(1) + "}\n\n"; } - private String createExceptionMethodBody(final GroovyStaticImportGenerator.JavaFunction function) { + private String createExceptionMethodBody(final JavaFunction function) { return indent(2) + "throw new PlotUnsupportedOperationException(\"DataSeries \" + this.getClass() + \" does not support method " + function.getMethodName() + " for arguments " + Arrays.toString(function.getParameterTypes()) @@ -726,7 +726,7 @@ private String createExceptionMethodBody(final GroovyStaticImportGenerator.JavaF } private String createMethodHeader(final String returnClass, - final GroovyStaticImportGenerator.JavaFunction function) { + final JavaFunction function) { String methodHeader = indent(1) + (!isInterface ? "@Override public " : "") + getGenericTypes(function) + returnClass + (isGeneric ? "" : "") + " " + function.getMethodName() + "("; @@ -746,7 +746,7 @@ private String createMethodHeader(final String returnClass, + (!isInterface ? " {\n" : ";\n"); } - private String getGenericTypes(final GroovyStaticImportGenerator.JavaFunction function) { + private String getGenericTypes(final JavaFunction function) { final TypeVariable[] typeParameters = function.getTypeParameters(); if (typeParameters.length == 0) { return ""; @@ -770,7 +770,7 @@ private String getGenericTypes(TypeVariable typeVariable) { return typeVariable.getName() + (bounds.isEmpty() ? "" : " extends " + String.join(" & ", bounds)); } - private String createMapCode(final GroovyStaticImportGenerator.JavaFunction function, final String mapName) { + private String createMapCode(final JavaFunction function, final String mapName) { final Type[] vars = function.getParameterTypes(); final String[] names = function.getParameterNames(); final StringBuilder code = new StringBuilder(); @@ -832,7 +832,7 @@ private String createMapCode(final GroovyStaticImportGenerator.JavaFunction func .toString(); } - private String createSmartKeyArgs(final GroovyStaticImportGenerator.JavaFunction function, + private String createSmartKeyArgs(final JavaFunction function, final Map tableToTableHandleVarMap) { List args = new ArrayList<>(); final Type[] vars = function.getParameterTypes(); @@ -852,7 +852,7 @@ private String createSmartKeyArgs(final GroovyStaticImportGenerator.JavaFunction return String.join(", ", args); } - private String createArgsString(final GroovyStaticImportGenerator.JavaFunction function) { + private String createArgsString(final JavaFunction function) { StringBuilder args = new StringBuilder(); for (final Type type : function.getParameterTypes()) { String typeName = type.getTypeName(); @@ -865,7 +865,7 @@ private String createArgsString(final GroovyStaticImportGenerator.JavaFunction f } } - private static String getMapType(GroovyStaticImportGenerator.JavaFunction function) { + private static String getMapType(JavaFunction function) { final String className; final Type[] types = function.getParameterTypes(); if (types.length == 1) { diff --git a/Generators/src/main/java/io/deephaven/plot/util/GeneratePlottingConvenience.java b/Generators/src/main/java/io/deephaven/plot/util/GeneratePlottingConvenience.java index 99c7feabac0..4c6f5cea056 100644 --- a/Generators/src/main/java/io/deephaven/plot/util/GeneratePlottingConvenience.java +++ b/Generators/src/main/java/io/deephaven/plot/util/GeneratePlottingConvenience.java @@ -3,10 +3,10 @@ */ package io.deephaven.plot.util; +import io.deephaven.gen.GenUtils; import io.deephaven.plot.BaseFigureImpl; import io.deephaven.plot.FigureImpl; -import io.deephaven.libs.GroovyStaticImportGenerator.JavaFunction; -import java.lang.reflect.WildcardType; +import io.deephaven.gen.JavaFunction; import java.io.IOException; import java.io.PrintWriter; @@ -19,16 +19,19 @@ import java.util.logging.Level; import java.util.logging.Logger; -import static io.deephaven.plot.util.PlotGeneratorUtils.indent; +import static io.deephaven.gen.GenUtils.indent; +import static io.deephaven.gen.GenUtils.typesToImport; /** * Create static functions that resolve against the last created instance of a plotting figure class. This is to make a * cleaner plotting interface */ +@SuppressWarnings("StringConcatenationInLoop") public class GeneratePlottingConvenience { // See also GroovyStaticImportGenerator private static final Logger log = Logger.getLogger(GeneratePlottingConvenience.class.toString()); + private static final String GRADLE_TASK = ":Generators:generatePlottingConvenience"; private static final String OUTPUT_CLASS = "io.deephaven.plot.PlottingConvenience"; private static final String OUTPUT_CLASS_NAME_SHORT = OUTPUT_CLASS.substring(OUTPUT_CLASS.lastIndexOf('.') + 1); @@ -102,15 +105,7 @@ private void addPublicMethod(Method m, Map functions log.info("Processing public method: " + m); final JavaFunction f = new JavaFunction(m); - final JavaFunction signature = new JavaFunction( - OUTPUT_CLASS, - OUTPUT_CLASS_NAME_SHORT, - functionNamer.apply(f), - f.getTypeParameters(), - f.getReturnType(), - f.getParameterTypes(), - f.getParameterNames(), - f.isVarArgs()); + final JavaFunction signature = f.transform(OUTPUT_CLASS, OUTPUT_CLASS_NAME_SHORT, functionNamer.apply(f), null); boolean skip = skip(f, ignoreSkips); @@ -150,55 +145,9 @@ private Set generateImports() { return imports; } - private static Set typesToImport(Type t) { - Set result = new LinkedHashSet<>(); - - if (t instanceof Class) { - final Class c = (Class) t; - final boolean isArray = c.isArray(); - final boolean isPrimitive = c.isPrimitive(); - - if (isPrimitive) { - return result; - } else if (isArray) { - return typesToImport(c.getComponentType()); - } else { - result.add(t.getTypeName()); - } - } else if (t instanceof ParameterizedType) { - final ParameterizedType pt = (ParameterizedType) t; - result.add(pt.getRawType().getTypeName()); - - for (Type a : pt.getActualTypeArguments()) { - result.addAll(typesToImport(a)); - } - } else if (t instanceof TypeVariable) { - // type variables are generic so they don't need importing - return result; - } else if (t instanceof WildcardType) { - // type variables are generic so they don't need importing - return result; - } else if (t instanceof GenericArrayType) { - GenericArrayType at = (GenericArrayType) t; - return typesToImport(at.getGenericComponentType()); - } else { - throw new UnsupportedOperationException("Unsupported Type type: " + t.getClass()); - } - - return result; - } - private String generateCode() { - String code = "/**\n" + - " * Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending\n" + - " */\n" + - "/****************************************************************************************************************************\n" - + - " ****** AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - Run GeneratePlottingConvenience or \"./gradlew :Generators:generatePlottingConvenience\" to regenerate\n" - + - " ****************************************************************************************************************************/\n\n"; - + String code = GenUtils.javaHeader(GeneratePlottingConvenience.class, GRADLE_TASK); code += "package io.deephaven.plot;\n\n"; Set imports = generateImports(); @@ -250,72 +199,19 @@ private String generateCode() { } private static String createFunction(final JavaFunction f, final JavaFunction signature, final boolean isStatic) { - String returnType = f.getReturnType().getTypeName().replace("$", "."); - String s = createJavadoc(f, signature); - s += " public static "; - - if (f.getTypeParameters().length > 0) { - s += "<"; - - for (int i = 0; i < f.getTypeParameters().length; i++) { - if (i != 0) { - s += ","; - } - - TypeVariable t = f.getTypeParameters()[i]; - log.info("BOUNDS: " + Arrays.toString(t.getBounds())); - s += t; - - Type[] bounds = t.getBounds(); - - if (bounds.length != 1) { - throw new RuntimeException("Unsupported bounds: " + Arrays.toString(bounds)); - } - - Type bound = bounds[0]; - - if (!bound.equals(Object.class)) { - s += " extends " + bound.getTypeName(); - } - - } - - s += ">"; - } - - s += " " + returnType + " " + signature.getMethodName() + "("; - String callArgs = ""; - - for (int i = 0; i < f.getParameterTypes().length; i++) { - if (i != 0) { - s += ","; - callArgs += ","; - } - - Type t = f.getParameterTypes()[i]; - - String typeString = t.getTypeName().replace("$", "."); - - if (f.isVarArgs() && i == f.getParameterTypes().length - 1) { - final int index = typeString.lastIndexOf("[]"); - typeString = typeString.substring(0, index) + "..." + typeString.substring(index + 2); - } - - s += " " + typeString + " " + f.getParameterNames()[i]; - callArgs += " " + f.getParameterNames()[i]; - } - - s += " ) {\n"; - s += indent(2) + (f.getReturnType().equals(void.class) ? "" : "return ") + final String javadoc = createJavadoc(f, signature); + final String sigPrefix = "public static"; + final String callArgs = GenUtils.javaArgString(signature, false); + String funcBody = " {\n"; + funcBody += indent(2) + (f.getReturnType().equals(void.class) ? "" : "return ") + (isStatic ? (f.getClassNameShort() + ".") : "FigureFactory.figure().") + f.getMethodName() + "(" + callArgs + " );\n"; - s += indent(1) + "}\n"; - - return s; + funcBody += indent(1) + "}\n"; + return GenUtils.javaFunction(signature, sigPrefix, javadoc, funcBody); } private static String createJavadoc(final JavaFunction f, final JavaFunction signature) { - return " /**\n * See {@link " + f.getClassName() + "#" + signature.getMethodName() + "} \n **/\n"; + return " /**\n * See {@link " + f.getClassName() + "#" + signature.getMethodName() + "} \n **/"; } public static void main(String[] args) throws ClassNotFoundException, IOException { @@ -392,9 +288,8 @@ public static void main(String[] args) throws ClassNotFoundException, IOExceptio "catErrorBarBy", "treemapPlot")); - @SuppressWarnings("unchecked") GeneratePlottingConvenience gen = new GeneratePlottingConvenience(staticImports, imports, - Arrays.asList(javaFunction -> !keepers.contains(javaFunction.getMethodName())), + List.of(javaFunction -> !keepers.contains(javaFunction.getMethodName())), JavaFunction::getMethodName); final String code = gen.generateCode() @@ -406,10 +301,7 @@ public static void main(String[] args) throws ClassNotFoundException, IOExceptio if (assertNoChange) { String oldCode = new String(Files.readAllBytes(Paths.get(file))); - if (!code.equals(oldCode)) { - throw new RuntimeException( - "Change in generated code. Run GeneratePlottingConvenience or \"./gradlew :Generators:generatePlottingConvenience\" to regenerate\n"); - } + GenUtils.assertGeneratedCodeSame(GeneratePlottingConvenience.class, GRADLE_TASK, oldCode, code); } else { PrintWriter out = new PrintWriter(file); diff --git a/Generators/src/main/java/io/deephaven/plot/util/GeneratePyV2FigureAPI.java b/Generators/src/main/java/io/deephaven/plot/util/GeneratePyV2FigureAPI.java index f13655cd750..7616cf47ef4 100644 --- a/Generators/src/main/java/io/deephaven/plot/util/GeneratePyV2FigureAPI.java +++ b/Generators/src/main/java/io/deephaven/plot/util/GeneratePyV2FigureAPI.java @@ -4,7 +4,8 @@ package io.deephaven.plot.util; import io.deephaven.base.Pair; -import io.deephaven.libs.GroovyStaticImportGenerator.JavaFunction; +import io.deephaven.gen.GenUtils; +import io.deephaven.gen.JavaFunction; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -73,10 +74,8 @@ public static void main(String[] args) throws ClassNotFoundException, IOExceptio if (assertNoChange) { String oldCode = new String(Files.readAllBytes(Paths.get(figureWrapperOutput))); - if (!pyCode.equals(oldCode)) { - throw new RuntimeException( - "Change in generated code. Run GeneratePyV2FigureAPI or \"./gradlew :Generators:generatePythonFigureWrapper\" to regenerate\n"); - } + GenUtils.assertGeneratedCodeSame(GeneratePyV2FigureAPI.class, ":Generators:generatePythonFigureWrapper", + oldCode, pyCode); } else { try (final PrintWriter out = new PrintWriter(pythonFile)) { out.print(pyCode); diff --git a/Generators/src/main/java/io/deephaven/plot/util/PlotGeneratorUtils.java b/Generators/src/main/java/io/deephaven/plot/util/PlotGeneratorUtils.java deleted file mode 100644 index 9b872de6c19..00000000000 --- a/Generators/src/main/java/io/deephaven/plot/util/PlotGeneratorUtils.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending - */ -package io.deephaven.plot.util; - -import gnu.trove.map.TIntObjectMap; -import gnu.trove.map.hash.TIntObjectHashMap; - -import java.util.Collections; - -/** - * Repository of general utilities for plot code generation. - */ -public class PlotGeneratorUtils { - - private static final TIntObjectMap cachedIndents = new TIntObjectHashMap<>(); - - /** - * Get a String of spaces for indenting code. - * - * @param n The number of indents - * @return The String for indenting code with spaces - */ - static String indent(final int n) { - String cached = cachedIndents.get(n); - if (cached == null) { - cachedIndents.put(n, cached = String.join("", Collections.nCopies(4 * n, " "))); - } - return cached; - } -} diff --git a/Generators/src/main/java/io/deephaven/pythonPreambles/plotV2.py b/Generators/src/main/java/io/deephaven/pythonPreambles/plotV2.py index e789f5c9a6f..d0acd29c87a 100644 --- a/Generators/src/main/java/io/deephaven/pythonPreambles/plotV2.py +++ b/Generators/src/main/java/io/deephaven/pythonPreambles/plotV2.py @@ -19,11 +19,10 @@ from deephaven import DHError, dtypes from deephaven._wrapper import JObjectWrapper -from deephaven.dtypes import Instant, PyObject +from deephaven.dtypes import Instant, PyObject, BusinessCalendar from deephaven.plot import LineStyle, PlotStyle, Color, Font, AxisFormat, Shape, AxisTransform, \ SelectableDataSet from deephaven.table import Table -from deephaven.calendar import BusinessCalendar from deephaven.jcompat import j_function _JPlottingConvenience = jpy.get_type("io.deephaven.plot.PlottingConvenience") @@ -71,6 +70,8 @@ def _convert_j(name: str, obj: Any, types: List) -> Any: if obj is None: return None + elif isinstance(obj, jpy.JType): + return obj _assert_type(name, obj, types) diff --git a/Integrations/build.gradle b/Integrations/build.gradle index 6e3b48dfb5c..ec27eb8e7c7 100644 --- a/Integrations/build.gradle +++ b/Integrations/build.gradle @@ -29,6 +29,8 @@ dependencies { testRuntimeOnly project(':Plot') testRuntimeOnly project(':extensions-kafka') testRuntimeOnly project(':extensions-parquet-table') + testRuntimeOnly project(':log-to-slf4j') + testRuntimeOnly project(':engine-time') } sourceSets { diff --git a/Integrations/src/test/resources/EMPTY.calendar b/Integrations/src/test/resources/EMPTY.calendar new file mode 100644 index 00000000000..fbb0ecbe94e --- /dev/null +++ b/Integrations/src/test/resources/EMPTY.calendar @@ -0,0 +1,20 @@ + + + + EMPTY + UTC + Calendar with no business time. + 1900-01-01 + 2100-12-25 + + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + \ No newline at end of file diff --git a/Integrations/src/test/resources/NUMPY_TEST.calendar b/Integrations/src/test/resources/NUMPY_TEST.calendar new file mode 100644 index 00000000000..78b030502d1 --- /dev/null +++ b/Integrations/src/test/resources/NUMPY_TEST.calendar @@ -0,0 +1,27 @@ + + + + NUMPY_TEST + Calendar for testing numpy calendar creation + Europe/Berlin + 1990-01-01 + 2050-12-31 + + 09:0020:00 + Wednesday + Saturday + Sunday + + + 2015-01-01 + + + 2015-04-06 + + + 2015-05-25 + 11:0021:00 + + diff --git a/Integrations/src/test/resources/TEST1.calendar b/Integrations/src/test/resources/TEST1.calendar new file mode 100644 index 00000000000..e6954708bd0 --- /dev/null +++ b/Integrations/src/test/resources/TEST1.calendar @@ -0,0 +1,14 @@ + + + + TEST1 + UTC + Test 1 + 1900-01-01 + 2100-12-25 + + 00:0023:59:59.999999999 + + \ No newline at end of file diff --git a/Integrations/src/test/resources/TEST2.calendar b/Integrations/src/test/resources/TEST2.calendar new file mode 100644 index 00000000000..e48611f5844 --- /dev/null +++ b/Integrations/src/test/resources/TEST2.calendar @@ -0,0 +1,14 @@ + + + + TEST2 + UTC + Test 2 + 1900-01-01 + 2100-12-25 + + 00:0023:59:59.999999999 + + \ No newline at end of file diff --git a/Plot/src/main/java/io/deephaven/plot/Figure.java b/Plot/src/main/java/io/deephaven/plot/Figure.java index b25614c53f9..45f921b320e 100644 --- a/Plot/src/main/java/io/deephaven/plot/Figure.java +++ b/Plot/src/main/java/io/deephaven/plot/Figure.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending */ /**************************************************************************************************************************** ****** AUTO-GENERATED CLASS - DO NOT EDIT MANUALLY - Run GenerateFigureImmutable or "./gradlew :Generators:generateFigureImmutable" to regenerate @@ -9,7 +9,7 @@ /** An interface for constructing plots. A Figure is immutable, and all function calls return a new immutable Figure instance.*/ -@SuppressWarnings({"unused", "RedundantCast", "SameParameterValue"}) +@SuppressWarnings({"unused", "RedundantCast", "SameParameterValue", "rawtypes"}) public interface Figure extends io.deephaven.plot.BaseFigure, io.deephaven.plot.Chart, io.deephaven.plot.Axes, io.deephaven.plot.Axis, io.deephaven.plot.datasets.DataSeries, io.deephaven.plot.datasets.category.CategoryDataSeries, io.deephaven.plot.datasets.interval.IntervalXYDataSeries, io.deephaven.plot.datasets.ohlc.OHLCDataSeries, io.deephaven.plot.datasets.xy.XYDataSeries, io.deephaven.plot.datasets.multiseries.MultiSeries, io.deephaven.plot.datasets.xy.XYDataSeriesFunction, io.deephaven.plot.datasets.xyerrorbar.XYErrorBarDataSeries, io.deephaven.plot.datasets.categoryerrorbar.CategoryErrorBarDataSeries { @@ -963,291 +963,291 @@ public interface Figure extends io.deephaven.plot.BaseFigure, io.deephaven.plot. @Override Figure errorBarColor( int errorBarColor ); - @Override Figure errorBarColor( int errorBarColor, java.lang.Object... multiSeriesKey ); - @Override Figure errorBarColor( io.deephaven.gui.color.Paint errorBarColor ); - @Override Figure errorBarColor( io.deephaven.gui.color.Paint errorBarColor, java.lang.Object... multiSeriesKey ); - @Override Figure errorBarColor( java.lang.String errorBarColor ); - @Override Figure errorBarColor( java.lang.String errorBarColor, java.lang.Object... multiSeriesKey ); + @Override Figure gradientVisible( boolean gradientVisible ); - @Override Figure funcNPoints( int npoints ); + @Override Figure lineColor( int color ); - @Override Figure funcRange( double xmin, double xmax ); + @Override Figure lineColor( io.deephaven.gui.color.Paint color ); - @Override Figure funcRange( double xmin, double xmax, int npoints ); + @Override Figure lineColor( java.lang.String color ); - @Override Figure gradientVisible( boolean gradientVisible ); + @Override Figure lineStyle( io.deephaven.plot.LineStyle lineStyle ); - @Override Figure gradientVisible( boolean gradientVisible, java.lang.Object... multiSeriesKey ); + @Override Figure linesVisible( java.lang.Boolean visible ); - @Override Figure group( int group ); + @Override Figure pointColor( int pointColor ); - @Override Figure group( int group, java.lang.Object... multiSeriesKey ); + @Override Figure pointColor( io.deephaven.gui.color.Paint pointColor ); - @Override Figure lineColor( int color ); + @Override Figure pointColor( java.lang.String pointColor ); - @Override Figure lineColor( int color, java.lang.Object... multiSeriesKey ); + @Override Figure pointLabel( java.lang.Object pointLabel ); - @Override Figure lineColor( io.deephaven.gui.color.Paint color ); + @Override Figure pointLabelFormat( java.lang.String pointLabelFormat ); - @Override Figure lineColor( io.deephaven.gui.color.Paint color, java.lang.Object... multiSeriesKey ); + @Override Figure pointShape( io.deephaven.gui.shape.Shape pointShape ); - @Override Figure lineColor( java.lang.String color ); + @Override Figure pointShape( java.lang.String pointShape ); - @Override Figure lineColor( java.lang.String color, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( double pointSize ); - @Override Figure lineStyle( io.deephaven.plot.LineStyle lineStyle ); + @Override Figure pointSize( int pointSize ); - @Override Figure lineStyle( io.deephaven.plot.LineStyle lineStyle, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( java.lang.Number pointSize ); - @Override Figure linesVisible( java.lang.Boolean visible ); + @Override Figure pointSize( long pointSize ); - @Override Figure linesVisible( java.lang.Boolean visible, java.lang.Object... multiSeriesKey ); + @Override Figure pointsVisible( java.lang.Boolean visible ); - @Override Figure piePercentLabelFormat( java.lang.String pieLabelFormat ); + @Override Figure seriesColor( int color ); - @Override Figure piePercentLabelFormat( java.lang.String pieLabelFormat, java.lang.Object... multiSeriesKey ); + @Override Figure seriesColor( io.deephaven.gui.color.Paint color ); - @Override Figure pointColor( int pointColor ); + @Override Figure seriesColor( java.lang.String color ); - @Override Figure pointColor( int pointColor, java.lang.Object... multiSeriesKey ); + @Override Figure toolTipPattern( java.lang.String toolTipPattern ); - @Override Figure pointColor( int... pointColors ); + @Override Figure xToolTipPattern( java.lang.String xToolTipPattern ); - @Override Figure pointColor( int[] pointColors, java.lang.Object... multiSeriesKey ); + @Override Figure yToolTipPattern( java.lang.String yToolTipPattern ); + + @Override Figure group( int group ); + + @Override Figure piePercentLabelFormat( java.lang.String pieLabelFormat ); @Override Figure pointColor( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointColor ); - @Override Figure pointColor( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointColor, java.lang.Object... multiSeriesKey ); + @Override Figure pointColor( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointColor ); - @Override Figure pointColor( io.deephaven.engine.table.Table t, java.lang.String pointColors ); + @Override Figure pointColor( java.lang.Comparable category, int pointColor ); - @Override Figure pointColor( io.deephaven.engine.table.Table t, java.lang.String pointColors, java.lang.Object... multiSeriesKey ); + @Override Figure pointColor( java.lang.Comparable category, io.deephaven.gui.color.Paint pointColor ); - @Override Figure pointColor( io.deephaven.gui.color.Paint pointColor ); + @Override Figure pointColor( java.lang.Comparable category, java.lang.String pointColor ); - @Override Figure pointColor( io.deephaven.gui.color.Paint pointColor, java.lang.Object... multiSeriesKey ); + @Override Figure pointLabel( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointLabel ); - @Override Figure pointColor( io.deephaven.gui.color.Paint... pointColor ); + @Override Figure pointLabel( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointLabel ); - @Override Figure pointColor( io.deephaven.gui.color.Paint[] pointColor, java.lang.Object... multiSeriesKey ); + @Override Figure pointLabel( java.lang.Comparable category, java.lang.Object pointLabel ); - @Override Figure pointColor( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointColor ); + @Override Figure pointShape( groovy.lang.Closure pointShapes ); - @Override Figure pointColor( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointColor, java.lang.Object... multiSeriesKey ); + @Override Figure pointShape( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointShape ); - @Override Figure pointColor( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointColors ); + @Override Figure pointShape( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointShape ); - @Override Figure pointColor( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointColors, java.lang.Object... multiSeriesKey ); + @Override Figure pointShape( java.lang.Comparable category, io.deephaven.gui.shape.Shape pointShape ); - @Override Figure pointColor( java.lang.Comparable category, int pointColor ); + @Override Figure pointShape( java.lang.Comparable category, java.lang.String pointShape ); - @Override Figure pointColor( java.lang.Comparable category, int pointColor, java.lang.Object... multiSeriesKey ); + @Override Figure pointShape( java.util.function.Function pointShapes ); - @Override Figure pointColor( java.lang.Comparable category, io.deephaven.gui.color.Paint pointColor ); + @Override Figure pointSize( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointSize ); - @Override Figure pointColor( java.lang.Comparable category, io.deephaven.gui.color.Paint pointColor, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointSize ); - @Override Figure pointColor( java.lang.Comparable category, java.lang.String pointColor ); + @Override Figure pointSize( java.lang.Comparable category, double pointSize ); - @Override Figure pointColor( java.lang.Comparable category, java.lang.String pointColor, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( java.lang.Comparable category, int pointSize ); - @Override Figure pointColor( java.lang.Integer... pointColors ); + @Override Figure pointSize( java.lang.Comparable category, java.lang.Number pointSize ); - @Override Figure pointColor( java.lang.Integer[] pointColors, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( java.lang.Comparable category, long pointSize ); - @Override Figure pointColor( java.lang.String pointColor ); + @Override Figure errorBarColor( int errorBarColor, java.lang.Object... multiSeriesKey ); - @Override Figure pointColor( java.lang.String pointColor, java.lang.Object... multiSeriesKey ); + @Override Figure errorBarColor( io.deephaven.gui.color.Paint errorBarColor, java.lang.Object... multiSeriesKey ); - @Override Figure pointColor( java.lang.String... pointColors ); + @Override Figure errorBarColor( java.lang.String errorBarColor, java.lang.Object... multiSeriesKey ); - @Override Figure pointColor( java.lang.String[] pointColors, java.lang.Object... multiSeriesKey ); + @Override Figure gradientVisible( boolean gradientVisible, java.lang.Object... multiSeriesKey ); - @Override Figure pointColorInteger( io.deephaven.plot.datasets.data.IndexableData colors ); + @Override Figure group( int group, java.lang.Object... multiSeriesKey ); - @Override Figure pointColorInteger( io.deephaven.plot.datasets.data.IndexableData colors, java.lang.Object... multiSeriesKey ); + @Override Figure lineColor( int color, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointLabel ); + @Override Figure lineColor( io.deephaven.gui.color.Paint color, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointLabel, java.lang.Object... multiSeriesKey ); + @Override Figure lineColor( java.lang.String color, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( io.deephaven.engine.table.Table t, java.lang.String pointLabel ); + @Override Figure lineStyle( io.deephaven.plot.LineStyle lineStyle, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( io.deephaven.engine.table.Table t, java.lang.String pointLabel, java.lang.Object... multiSeriesKey ); + @Override Figure linesVisible( java.lang.Boolean visible, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( io.deephaven.plot.datasets.data.IndexableData pointLabels ); + @Override Figure piePercentLabelFormat( java.lang.String pieLabelFormat, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( io.deephaven.plot.datasets.data.IndexableData pointLabels, java.lang.Object... multiSeriesKey ); + @Override Figure pointColor( int pointColor, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointLabel ); + @Override Figure pointColor( int[] pointColors, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointLabel, java.lang.Object... multiSeriesKey ); + @Override Figure pointColor( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointColor, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointLabel ); + @Override Figure pointColor( io.deephaven.engine.table.Table t, java.lang.String pointColors, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointLabel, java.lang.Object... multiSeriesKey ); + @Override Figure pointColor( io.deephaven.gui.color.Paint pointColor, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( java.lang.Comparable category, java.lang.Object pointLabel ); + @Override Figure pointColor( io.deephaven.gui.color.Paint[] pointColor, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( java.lang.Comparable category, java.lang.Object pointLabel, java.lang.Object... multiSeriesKey ); + @Override Figure pointColor( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointColor, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( java.lang.Object pointLabel ); + @Override Figure pointColor( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointColors, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( java.lang.Object pointLabel, java.lang.Object... multiSeriesKey ); + @Override Figure pointColor( java.lang.Comparable category, int pointColor, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( java.lang.Object... pointLabels ); + @Override Figure pointColor( java.lang.Comparable category, io.deephaven.gui.color.Paint pointColor, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabel( java.lang.Object[] pointLabels, java.lang.Object... multiSeriesKey ); + @Override Figure pointColor( java.lang.Comparable category, java.lang.String pointColor, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabelFormat( java.lang.String pointLabelFormat ); + @Override Figure pointColor( java.lang.Integer[] pointColors, java.lang.Object... multiSeriesKey ); - @Override Figure pointLabelFormat( java.lang.String pointLabelFormat, java.lang.Object... multiSeriesKey ); + @Override Figure pointColor( java.lang.String pointColor, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( groovy.lang.Closure pointShapes ); + @Override Figure pointColor( java.lang.String[] pointColors, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( groovy.lang.Closure pointShapes, java.lang.Object... multiSeriesKey ); + @Override Figure pointColorInteger( io.deephaven.plot.datasets.data.IndexableData colors, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointShape ); + @Override Figure pointLabel( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointLabel, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointShape, java.lang.Object... multiSeriesKey ); + @Override Figure pointLabel( io.deephaven.engine.table.Table t, java.lang.String pointLabel, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.engine.table.Table t, java.lang.String pointShape ); + @Override Figure pointLabel( io.deephaven.plot.datasets.data.IndexableData pointLabels, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.engine.table.Table t, java.lang.String pointShape, java.lang.Object... multiSeriesKey ); + @Override Figure pointLabel( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointLabel, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.gui.shape.Shape pointShape ); + @Override Figure pointLabel( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointLabel, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.gui.shape.Shape pointShape, java.lang.Object... multiSeriesKey ); + @Override Figure pointLabel( java.lang.Comparable category, java.lang.Object pointLabel, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.gui.shape.Shape... pointShapes ); + @Override Figure pointLabel( java.lang.Object pointLabel, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.gui.shape.Shape[] pointShapes, java.lang.Object... multiSeriesKey ); + @Override Figure pointLabel( java.lang.Object[] pointLabels, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.plot.datasets.data.IndexableData pointShapes ); + @Override Figure pointLabelFormat( java.lang.String pointLabelFormat, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.plot.datasets.data.IndexableData pointShapes, java.lang.Object... multiSeriesKey ); + @Override Figure pointShape( groovy.lang.Closure pointShapes, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointShape ); + @Override Figure pointShape( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointShape, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointShape, java.lang.Object... multiSeriesKey ); + @Override Figure pointShape( io.deephaven.engine.table.Table t, java.lang.String pointShape, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointShape ); + @Override Figure pointShape( io.deephaven.gui.shape.Shape pointShape, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointShape, java.lang.Object... multiSeriesKey ); + @Override Figure pointShape( io.deephaven.gui.shape.Shape[] pointShapes, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( java.lang.Comparable category, io.deephaven.gui.shape.Shape pointShape ); + @Override Figure pointShape( io.deephaven.plot.datasets.data.IndexableData pointShapes, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( java.lang.Comparable category, io.deephaven.gui.shape.Shape pointShape, java.lang.Object... multiSeriesKey ); + @Override Figure pointShape( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointShape, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( java.lang.Comparable category, java.lang.String pointShape ); + @Override Figure pointShape( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointShape, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( java.lang.Comparable category, java.lang.String pointShape, java.lang.Object... multiSeriesKey ); + @Override Figure pointShape( java.lang.Comparable category, io.deephaven.gui.shape.Shape pointShape, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( java.lang.String pointShape ); + @Override Figure pointShape( java.lang.Comparable category, java.lang.String pointShape, java.lang.Object... multiSeriesKey ); @Override Figure pointShape( java.lang.String pointShape, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( java.lang.String... pointShapes ); - @Override Figure pointShape( java.lang.String[] pointShapes, java.lang.Object... multiSeriesKey ); - @Override Figure pointShape( java.util.function.Function pointShapes ); - @Override Figure pointShape( java.util.function.Function pointShapes, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( double pointSize ); + @Override Figure pointSize( double[] pointSizes, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( double... pointSizes ); + @Override Figure pointSize( int[] pointSizes, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( double[] pointSizes, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointSize, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( int pointSize ); + @Override Figure pointSize( io.deephaven.engine.table.Table t, java.lang.String pointSizes, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( int... pointSizes ); + @Override Figure pointSize( io.deephaven.plot.datasets.data.IndexableData pointSizes, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( int[] pointSizes, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointSize, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointSize ); + @Override Figure pointSize( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointSize, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( io.deephaven.engine.table.Table t, java.lang.String category, java.lang.String pointSize, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( java.lang.Comparable category, double pointSize, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( io.deephaven.engine.table.Table t, java.lang.String pointSizes ); + @Override Figure pointSize( java.lang.Comparable category, int pointSize, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( io.deephaven.engine.table.Table t, java.lang.String pointSizes, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( java.lang.Comparable category, java.lang.Number pointSize, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( io.deephaven.plot.datasets.data.IndexableData pointSizes ); + @Override Figure pointSize( java.lang.Comparable category, long pointSize, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( io.deephaven.plot.datasets.data.IndexableData pointSizes, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( java.lang.Number pointSize, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointSize ); + @Override Figure pointSize( long[] pointSizes, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String category, java.lang.String pointSize, java.lang.Object... multiSeriesKey ); + @Override Figure pointsVisible( java.lang.Boolean visible, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointSize ); + @Override Figure seriesColor( int color, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointSize, java.lang.Object... multiSeriesKey ); + @Override Figure seriesColor( io.deephaven.gui.color.Paint color, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( java.lang.Comparable category, double pointSize ); + @Override Figure seriesColor( java.lang.String color, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( java.lang.Comparable category, double pointSize, java.lang.Object... multiSeriesKey ); + @Override Figure seriesNamingFunction( groovy.lang.Closure namingFunction ); - @Override Figure pointSize( java.lang.Comparable category, int pointSize ); + @Override Figure seriesNamingFunction( java.util.function.Function namingFunction ); - @Override Figure pointSize( java.lang.Comparable category, int pointSize, java.lang.Object... multiSeriesKey ); + @Override Figure toolTipPattern( java.lang.String toolTipPattern, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( java.lang.Comparable category, java.lang.Number pointSize ); + @Override Figure xToolTipPattern( java.lang.String xToolTipPattern, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( java.lang.Comparable category, java.lang.Number pointSize, java.lang.Object... multiSeriesKey ); + @Override Figure yToolTipPattern( java.lang.String yToolTipPattern, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( java.lang.Comparable category, long pointSize ); + @Override Figure pointColor( int... pointColors ); - @Override Figure pointSize( java.lang.Comparable category, long pointSize, java.lang.Object... multiSeriesKey ); + @Override Figure pointColor( io.deephaven.engine.table.Table t, java.lang.String pointColors ); - @Override Figure pointSize( java.lang.Number pointSize ); + @Override Figure pointColor( io.deephaven.gui.color.Paint... pointColor ); - @Override Figure pointSize( java.lang.Number pointSize, java.lang.Object... multiSeriesKey ); + @Override Figure pointColor( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointColors ); - @Override Figure pointSize( long pointSize ); + @Override Figure pointColor( java.lang.Integer... pointColors ); - @Override Figure pointSize( long... pointSizes ); + @Override Figure pointColor( java.lang.String... pointColors ); - @Override Figure pointSize( long[] pointSizes, java.lang.Object... multiSeriesKey ); + @Override Figure pointColorInteger( io.deephaven.plot.datasets.data.IndexableData colors ); - @Override Figure pointsVisible( java.lang.Boolean visible ); + @Override Figure pointLabel( io.deephaven.engine.table.Table t, java.lang.String pointLabel ); - @Override Figure pointsVisible( java.lang.Boolean visible, java.lang.Object... multiSeriesKey ); + @Override Figure pointLabel( io.deephaven.plot.datasets.data.IndexableData pointLabels ); - @Override Figure seriesColor( int color ); + @Override Figure pointLabel( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointLabel ); - @Override Figure seriesColor( int color, java.lang.Object... multiSeriesKey ); + @Override Figure pointLabel( java.lang.Object... pointLabels ); - @Override Figure seriesColor( io.deephaven.gui.color.Paint color ); + @Override Figure pointShape( io.deephaven.engine.table.Table t, java.lang.String pointShape ); - @Override Figure seriesColor( io.deephaven.gui.color.Paint color, java.lang.Object... multiSeriesKey ); + @Override Figure pointShape( io.deephaven.gui.shape.Shape... pointShapes ); - @Override Figure seriesColor( java.lang.String color ); + @Override Figure pointShape( io.deephaven.plot.datasets.data.IndexableData pointShapes ); - @Override Figure seriesColor( java.lang.String color, java.lang.Object... multiSeriesKey ); + @Override Figure pointShape( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointShape ); - @Override Figure seriesNamingFunction( groovy.lang.Closure namingFunction ); + @Override Figure pointShape( java.lang.String... pointShapes ); - @Override Figure seriesNamingFunction( java.util.function.Function namingFunction ); + @Override Figure pointSize( double... pointSizes ); - @Override Figure toolTipPattern( java.lang.String toolTipPattern ); + @Override Figure pointSize( int... pointSizes ); - @Override Figure toolTipPattern( java.lang.String toolTipPattern, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( io.deephaven.engine.table.Table t, java.lang.String pointSizes ); - @Override Figure xToolTipPattern( java.lang.String xToolTipPattern ); + @Override Figure pointSize( io.deephaven.plot.datasets.data.IndexableData pointSizes ); - @Override Figure xToolTipPattern( java.lang.String xToolTipPattern, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( io.deephaven.plot.filters.SelectableDataSet sds, java.lang.String pointSize ); - @Override Figure yToolTipPattern( java.lang.String yToolTipPattern ); + @Override Figure pointSize( long... pointSizes ); - @Override Figure yToolTipPattern( java.lang.String yToolTipPattern, java.lang.Object... multiSeriesKey ); + @Override Figure funcNPoints( int npoints ); + + @Override Figure funcRange( double xmin, double xmax ); + + @Override Figure funcRange( double xmin, double xmax, int npoints ); @Override Figure pointColor( java.util.Map pointColor ); @@ -1263,67 +1263,67 @@ public interface Figure extends io.deephaven.plot.BaseFigure, io.deephaven.plot. @Override Figure pointSize( CATEGORY[] categories, NUMBER[] pointSizes ); - @Override Figure pointSize( CATEGORY[] categories, NUMBER[] pointSizes, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( java.util.Map pointSizes ); + @Override Figure pointSize( CATEGORY[] categories, NUMBER[] pointSizes, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( java.util.Map pointSizes, java.lang.Object... multiSeriesKey ); @Override Figure pointShape( java.util.Map pointShapes ); - @Override Figure pointShape( java.util.Map pointShapes, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( CATEGORY[] categories, double[] pointSizes ); - @Override Figure pointSize( CATEGORY[] categories, double[] pointSizes, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( CATEGORY[] categories, int[] pointSizes ); - @Override Figure pointSize( CATEGORY[] categories, int[] pointSizes, java.lang.Object... multiSeriesKey ); - @Override Figure pointSize( CATEGORY[] categories, long[] pointSizes ); + @Override Figure pointShape( java.util.Map pointShapes, java.lang.Object... multiSeriesKey ); + + @Override Figure pointSize( CATEGORY[] categories, double[] pointSizes, java.lang.Object... multiSeriesKey ); + + @Override Figure pointSize( CATEGORY[] categories, int[] pointSizes, java.lang.Object... multiSeriesKey ); + @Override Figure pointSize( CATEGORY[] categories, long[] pointSizes, java.lang.Object... multiSeriesKey ); @Override Figure pointColor( groovy.lang.Closure pointColor ); - @Override Figure pointColor( groovy.lang.Closure pointColor, java.lang.Object... multiSeriesKey ); - @Override Figure pointColor( java.util.function.Function pointColor ); + @Override Figure pointColor( groovy.lang.Closure pointColor, java.lang.Object... multiSeriesKey ); + @Override Figure pointColor( java.util.function.Function pointColor, java.lang.Object... multiSeriesKey ); @Override Figure pointColorInteger( groovy.lang.Closure colors ); - @Override Figure pointColorInteger( groovy.lang.Closure colors, java.lang.Object... multiSeriesKey ); - @Override Figure pointColorInteger( java.util.function.Function colors ); + @Override Figure pointColorInteger( groovy.lang.Closure colors, java.lang.Object... multiSeriesKey ); + @Override Figure pointColorInteger( java.util.function.Function colors, java.lang.Object... multiSeriesKey ); @Override