Java objects and classes in query strings

Using Java classes and objects directly in query strings is one of Deephaven's most powerful features. Your queries can use the whole Java standard library and any Java class on the server's classpath, just as Groovy's seamless Java interoperability lets your scripts use them. This guide shows how to:

You don't need much Java experience to follow it.

Classes and objects in Java

Java is an object-oriented programming language where classes serve as blueprints for creating objects. Java distinguishes between primitive types and objects:

  1. Primitive types: Basic data types like int, double, and boolean that are not objects.
  2. Objects: Instances of classes that bundle data and methods together.

For performance reasons, Deephaven tables primarily use primitive types for numeric columns. Other columns, such as text and timestamp columns, hold Java objects. query strings can call those objects' methods, as the rest of this guide shows.

Common Java objects in Deephaven

All objects in Java inherit from the java.lang.Object class. Common Java objects used in Deephaven queries include:

Variables

Java classes can have two types of variables:

  1. Static variables (class variables): Belong to the class itself, not to instances. They are shared across all instances of the class.
  2. Instance variables: Belong to individual object instances created from the class.

In query strings, you access a static variable through its class name and an instance variable through an object. The following example reads the static variable Integer.MAX_VALUE, creates an int array, and reads the array's length instance variable. It creates the array with the new keyword, which Methods and constructors explains:

The sourceMeta table lists each column's type: Instance holds an int[] object, and StaticVariable and InstanceVariable are int values.

Methods and constructors

Query strings can use three kinds of Java methods and constructors:

  1. Static methods: Called on the class itself, not on instances.
  2. Constructors: Create new instances with the new keyword.
  3. Instance methods: Called on object instances.

The following example calls static methods of Math, creates a UUID with a constructor, and calls the new object's toString instance method. The query library imports both Math and UUID by default, so the example needs no import:

In sourceMeta, UUIDConstructor is a java.util.UUID column, and UUIDStringInstanceMethod is a String column.

Import Java classes

Query strings can use many Java classes by their simple names, with no import step. A simple name is the class name alone, such as Math. A fully qualified name also includes the package, such as java.lang.Math.

The query library holds the imports that query strings can use. By default, it includes:

For the complete list, see Auto-imported functions.

A Groovy import statement doesn't make a class available in query strings, which are compiled separately from your Groovy script.

To use a class that isn't imported by default, refer to it by its fully qualified name. You can also add it to the query library of the current execution context with ExecutionContext.getContext().getQueryLibrary().importClass and then use its simple name. Either way, the class must be on the server's classpath. To add your own JAR, see Install and use Java packages.

The following example adds java.net.URI to the query library and uses its simple name. The LoopbackName column uses java.net.InetAddress by its fully qualified name, with no import. The URI is a string literal, which query strings delimit with backticks:

QueryLibrary has two other import methods:

For an importStatic example, see Add Java classes to the query library.

Nested classes

Java lets you define a class inside another class. In a query string, you refer to a nested class with dot notation, such as OuterClass.NestedClass. This is standard Java syntax.

The following example creates a java.util.AbstractMap.SimpleEntry, a class nested inside java.util.AbstractMap, and reads its key and value. AbstractMap is in java.util, so the example needs no import:

The example uses SimpleEntry without type parameters, so getKey and getValue return Object. The casts make Key a String column and Value a double column, as sourceMeta shows. Without them, both columns would hold Object values.

A query string can also refer to a nested class by its fully qualified name, such as java.util.AbstractMap.SimpleImmutableEntry. To use the nested class's simple name alone, add it to the query library with importClass. The following example imports java.util.AbstractMap.SimpleImmutableEntry and then uses both its simple name and its fully qualified name:

As Import Java classes explains, a Groovy import of a nested class doesn't make the class available in query strings.

Built-in query language functions

The Deephaven Query Language (DQL) has a large number of built-in functions that take Java objects as input.

For example, java.time.Instant and java.time.Duration are common in tables. Many methods in io.deephaven.time.DateTimeUtils accept these object types as input. The query library imports these methods by default, as described in Import Java classes.

The following example passes Instant and Duration objects to the built-in functions minus, plus, upperBin, and lowerBin:

  • The Timestamp column starts at a date-time literal and adds one minute per row. ii is the row index, and MINUTE is a built-in constant.
  • The durations, such as 'PT5s', are duration literals.
  • In the result, UpperBin and LowerBin round each timestamp up or down to a 15-minute boundary.
  • sourceMeta shows that every column holds Instant values.