User Defined Java Expression transform Icon User Defined Java Expression

Description

This transform allows you to enter Java expressions that are used to calculate new values or replace values in fields. Any custom jar libraries that your expressions depend on need to be placed in the folder plugins/transforms/janino/lib

Supported Engines

Hop Engine

Supported

Single Threaded

Supported

Native Spark

Supported

Beam Spark

Maybe Supported

Beam Flink

Maybe Supported

Beam Dataflow

Maybe Supported

Usage

If you have a Java expression like :

C=A+B

Then you can simply enter the right side of the expression in the dialog:

A+B

The values are exposed to the expressions as the Java objects they are :

Data type Java Class

BigNumber

BigDecimal

Binary

byte[]

Date

java.util.Date

Integer

java.lang.Long

Number

java.lang.Double

String

java.lang.String

Options

Option Description

Transform name

Specify a name for this transform. This must be unique wihin the pipeline.

New field

The new field in the data stream that contains the result of the expression. If you want to overwrite an existing field, you need to define the same field here and in the "Replace value" option.

Java expression

The Java expression to evaluate. See examples below.

Value type

The field’s data type.

Length

The maximum length of a string in the new field. See Formatting numbers and dates.

Precision

The number of decimal places used to express numbers.

Replace value

Set this to be identical to the "New field" name when you want to replace the value in an existing field.

Examples

Add 2 integers, A and B

A+B

Concatenate 2 Strings : firstname and name and put a space in between

firstname+" "+name

or if you really care about performance, this might be faster:

new StringBuffer(firstname).append(" ").append(name).toString()

Use native Java and API functions

System.getProperty("os.name")

Business rules (If / Then / Else)

a<c?true:false

This can be more complicated

a<c?(a==1?1:2):3

even with OR and AND and other operators and functions

Using Constants

If you use a constant, you may need to define the right type in some expressions otherwise it could throw an error. Eg if you use "0" that is "int" but Apache Hop "Integer" is "java.lang.Long", so you’ll get an exception:

Incompatible expression types "int" and "java.lang.Long"

To solve this, use:

test == null ? new Long(0) : test

The above expression checks if "test" is null and replaces it with a zero Long. Otherwise, it return "test" unchanged.

Cut a string from end and test for null and minimal length

Imagine you have input strings "location" like

Orlando FL
New York NY

and you want to separate the state and city. You could use the following expressions:

For state (get the last 2 characters):

location != null && location.length()>2 ? location.substring(location.length()-2, location.length()) : null

For city (get the beginning without the last 2 characters and trim):

location != null && location.length()>2 ? location.substring(0, location.length()-2).trim() : location

Functionality of a LIKE operator (contains string)

The following example returns 1 when abc is within the source string, otherwise 2. It returns also 2 when the source string is null. If you prefer the return values to be of value type Integer, use "new Long(1)" and "new Long(2)".

samplestr != null && samplestr.indexOf("abc")>-1 ? 1 : 2

The expression editor

Double click a formula in the grid to open it in the expression editor. The tree on the left lists the fields of the incoming stream and a reference of the operators and methods an expression can use, grouped in Operators, Text, Mathematical, Date & time, Logical, Conversion and the row helper below. Selecting an entry shows what it does, what it returns and a few examples, double clicking one inserts it in the expression.

Reading fields by name

Next to the fields of the incoming stream, every expression receives a helper named row that reads the row by field name:

Method Returns

row.exists("field")

true when the stream has a field with this name

row.isNull("field")

true when the field is absent, or present with a null value

row.getString("field")

the value as a String, null when the field is absent

row.getInteger("field")

the value as a Long, null when the field is absent

row.getNumber("field")

the value as a Double, null when the field is absent

row.getBigNumber("field")

the value as a BigDecimal, null when the field is absent

row.getDate("field")

the value as a Date, null when the field is absent

row.getBoolean("field")

the value as a Boolean, null when the field is absent

A field that is read this way does not have to exist, which makes it possible to write an expression for a stream whose layout is only known at runtime. It is also the way to use a field whose name is not a valid Java identifier, e.g. a name with a space in it:

row.exists("discount") ? row.getNumber("discount") : new Double(0)
when the stream itself contains a field named row, that field wins and the helper is not available.

Blocking specific code

As a simple security measure you can block the execution of code containing specific strings. This can be done by adding exclusions to the codeExclusions.xml file located at <Hop Installation>/plugins/transforms/janino

Example:

    <exclusions>
        <exclusion>System.</exclusion>
        <exclusion>HopVfs.</exclusion>
    </exclusions>