Custom Value Processors – Reference
ON THIS PAGE
API Overview
The custom value processor API lives in the com.basis.startup.type.sql package,
which is available in BBjStartup.jar. This JAR must be on the compile-time
classpath of any project that implements a custom processor. At runtime, the BBj SQL engine
uses its own class loader to load your processor class, so you do not need to and
should not re-bundle BBjStartup.jar inside your own JAR.
| Type | Package | Role |
|---|---|---|
ValueProcessor (abstract class) |
com.basis.startup.type.sql
|
Base class you extend to create a custom processor. |
BBjSQLLiteral (interface) |
com.basis.startup.type.sql
|
Wraps an SQL literal value passed to computeRawValue(); provides typed accessors. |
ValueProcessorBBjSQLFactory (interface) |
com.basis.startup.type.sql
|
Factory interface your class implements to advertise your processors to the BBj SQL engine.
Also extends BBjSQLFactory, making it the single class you need to
register with the database. |
The ValueProcessor Abstract Class
Extend com.basis.startup.type.sql.ValueProcessor and provide implementations of
all six abstract methods described below. Your class must also expose a public
default (no-argument) constructor because the SQL engine instantiates it via
reflection.
computeReturnedValue(Object p_value)
public abstract Object computeReturnedValue(Object p_value) throws SQLException
Called by the SQL engine each time a row is read from the data file. The engine passes the
raw value parsed from the string template, and your implementation must return the converted
value in the Java type that corresponds to the SQL type declared by getSqlType().
| Parameter | Type | Description |
|---|---|---|
p_value
|
Object
|
The raw value from the data file after string-template parsing. For a character field
(C type) this will be a String. For a numeric field
(N, I, etc.) this will be a Number subtype.
May be null for empty or missing fields.
|
Returns: The converted value. The runtime type must match the SQL
type returned by getSqlType(). For example:
- If
getSqlType()returnsTypes.BOOLEAN, return aBooleanobject. - If
getSqlType()returnsTypes.DATE, return ajava.sql.Dateobject. - Return
nullto represent a SQL NULL value.
Throws: java.sql.SQLException if the raw value cannot be converted.
computeRawValue(BBjSQLLiteral p_value)
public abstract Object computeRawValue(BBjSQLLiteral p_value) throws SQLException
Called by the SQL engine when a row is being written (via INSERT or
UPDATE). The engine passes the SQL-typed value provided in the statement, and your implementation must return the raw value in the native form that matches the underlying
string template field.
| Parameter | Type | Description |
|---|---|---|
p_value
|
BBjSQLLiteral
|
The SQL literal value provided by the INSERT or UPDATE statement. Use the typed
accessor methods on BBjSQLLiteral to retrieve
the value in the most appropriate form (e.g., getBoolean(),
getString()); value may be null.
|
Returns: The raw value to be written to the data file. The type
must match what the underlying string template field expects. For a C(1) field,
return a String. For a numeric field, return a Number.
Throws: java.sql.SQLException if the value cannot
be converted.
getSqlType()
public abstract int getSqlType();
Returns the JDBC SQL type constant (from java.sql.Types) that represents the
logical data type this processor produces. The SQL engine uses this value to:
- Report the column type via JDBC metadata (e.g.,
ResultSetMetaData.getColumnType()). - Determine how to handle type coercions in SQL expressions.
- Override the native type stored in the type definition's
sqlTypefield.
Common return values include Types.BOOLEAN, Types.DATE,
Types.INTEGER, and Types.VARCHAR. See
java.sql.Types Quick Reference below.
getDisplayName()
public abstract String getDisplayName()
Returns a short, human-readable name for this processor. This name appears in the Enterprise Manager type definition editor, in the dropdown list where administrators select which processor to assign to a column. Choose a name that clearly identifies what the processor does.
Example: Boolean Y/N Processor
getDescription()
public abstract String getDescription()
Returns a short description that provides additional context about what the processor does. This text is shown alongside the display name in Enterprise Manager to help administrators choose the correct processor.
Example: Converts string values Y and N to boolean true and false values respectively.
isLexicallyOrdered()
public abstract boolean isLexicallyOrdered()
Tells the SQL engine whether the raw values stored on disk sort in the same order as the
processed values returned by computeReturnedValue(). When this returns
true, the engine knows it can use an existing index on the raw data to
optimize range queries (e.g., WHERE date_col > '2024-01-01').
Return true only when you are certain the sort orders are equivalent.
Returning true incorrectly will produce wrong query results for range queries
that rely on index optimization.
For boolean value processors (where the raw values are typically just two distinct values),
it is generally safe to return true.
The BBjSQLLiteral Interface
The BBjSQLLiteral interface wraps a single SQL literal value that is passed to
computeRawValue(). It provides typed accessors so you can retrieve the value in
the most convenient form for your conversion. All accessors that involve type conversion may
throw SQLException if the literal cannot be coerced to the requested type.
| Method | Returns | Notes |
|---|---|---|
isNull()
|
boolean
|
Returns true if the literal is SQL NULL. |
getString()
|
String
|
String representation of the value. |
getBoolean()
|
boolean
|
Boolean representation. Throws SQLException if conversion fails. |
getByte()
|
byte
|
Byte representation. |
getShort()
|
short
|
Short integer representation. |
getInt()
|
int
|
Integer representation. |
getLong()
|
long
|
Long integer representation. |
getFloat()
|
float
|
Float representation. |
getDouble()
|
double
|
Double representation. |
getBigDecimal()
|
BigDecimal
|
BigDecimal representation. |
getDate()
|
java.sql.Date
|
Date representation. |
getTime()
|
java.sql.Time
|
Time representation. |
getTimestamp()
|
java.sql.Timestamp
|
Timestamp representation. |
getObject()
|
Object
|
The underlying object in its natural type. |
The ValueProcessorBBjSQLFactory Interface
To make your custom value processor visible to the BBj SQL engine, you must also provide
an implementation of the
com.basis.startup.type.sql.ValueProcessorBBjSQLFactory interface. This
interface extends BBjSQLFactory, which means your factory class is the single
point of registration for both custom value processors and (optionally) custom scalar/group
functions.
The interface declares one method:
| Method | Returns | Purpose |
|---|---|---|
getValueProcessors()
|
Collection<ValueProcessor>
|
Return a collection containing one instance of every
ValueProcessor implementation this factory provides.
The SQL engine calls this method to populate the processor list shown
in the Enterprise Manager type definition editor. |
Implementation Requirements
- Public default constructor. The BBj SQL engine instantiates your factory class using reflection, so it must have a public no-argument constructor.
- Implements
ValueProcessorBBjSQLFactory. The class must explicitly declareimplements ValueProcessorBBjSQLFactory. Implementing onlyBBjSQLFactoryis not sufficient — the engine checks specifically for theValueProcessorBBjSQLFactorysub-interface when discovering processors. - Package in the same JAR as your processors. The factory and all processor
classes it references must be in the same JAR that is registered via the
SQL_FACTORY_SSCPdatabase property.
Minimal Example
The following factory exposes a single custom processor. The fully-qualified class name of
this factory class is what you enter in the database's SQL_FACTORY
property in Enterprise Manager.
|
Note: If you have multiple processors, return all of them from
getValueProcessors():
|
Relationship Between SQL_FACTORY and SQL_FACTORY_SSCP
Two database properties work together to wire your factory into a database:
| Property | EM Label | What to Set |
|---|---|---|
SQL_FACTORY
|
BBjSQLFactory Implementation | The fully-qualified class name of your factory, e.g.
com.example.sql.valueprocessor.MyProcessorFactory. |
SQL_FACTORY_SSCP
|
Scalar/Group Function SSCP | The name of the SSCP (Session Specific Classpath) entry that points to the JAR containing your factory and processor classes. |
Both properties are found under the Custom Functionality category in the
database properties view in Enterprise Manager. The engine loads the factory class from
the classpath defined by SQL_FACTORY_SSCP, so both properties must be set
for your processor to appear in the type definition editor and function at query time.
Implementation Requirements
- Public default constructor. Your class must have a public, no-argument constructor. The SQL engine instantiates value processors using reflection and requires this constructor.
- No instance state that changes after construction. A single instance
of your processor may be used concurrently by multiple threads. Your class must be
thread-safe. The simplest approach is to make all fields
finaland set during construction only. - Handle null and empty values defensively. The
p_valueparameter tocomputeReturnedValue()can benull, and the string representation of an empty field may be an empty string. Always check for these conditions before attempting conversion. - Throw
SQLExceptionon unrecoverable errors. If a value cannot be converted, throw ajava.sql.SQLExceptionwith a descriptive message. Do not swallow exceptions silently. - Compile against
BBjStartup.jar. TheValueProcessorandBBjSQLLiteraltypes are defined inBBjStartup.jar, located in the BBj installation directory. Do not ship this JAR in your own deployment.
Packaging and Deployment
Compile your ValueProcessor implementation(s) and your
ValueProcessorBBjSQLFactory implementation and package them together
in a single standard JAR file. The JAR must not re-bundle
BBjStartup.jar or any other core BBj JARs.
Place your JAR in a location accessible to the BBj server machine — for example:
/usr/local/basis/lib/custom/myprocessors.jar
The exact location does not matter as long as BBj can reach it as a file path; you will register this path as an SSCP entry in the next section.
Configuring a Database to Use Your Processor
Once your JAR is in place you must register it with BBj and then link it to the appropriate database column. This is a five-step process performed in Enterprise Manager.
Step 1: Register the JAR as a Session Specific Classpath (SSCP)
An SSCP (Session Specific Classpath) is a named classpath entry managed by BBj. It tells BBj where to find external classes at runtime. You need one SSCP entry that points to your JAR.
-
Open Enterprise Manager and connect to your BBj server.
-
Navigate to Settings > Classpath (or the equivalent SSCP management section in your version of Enterprise Manager).
-
Create a new SSCP entry. Give it a meaningful name such as
myProcessorsSSCP.
-
Add the path to your JAR file as an entry in the classpath, for example
/usr/local/basis/lib/custom/myprocessors.jar.
-
Save the SSCP entry.
Step 2: Set the Database SQL_FACTORY Property
The SQL_FACTORY property (displayed in Enterprise Manager as
BBjSQLFactory Implementation) tells the SQL engine which factory class to
instantiate. Set it to the fully-qualified class name of your
ValueProcessorBBjSQLFactory implementation.
- In Enterprise Manager, expand the Databases tree and select the target database.
- Open the database properties / configuration view.
- Locate the field labelled BBjSQLFactory Implementation
(
SQL_FACTORY) under the Custom Functionality category.
- Set its value to the fully-qualified class name of your factory, for example
com.example.sql.valueprocessor.MyProcessorFactory.
- Save the database configuration.
Step 3: Set the Database SQL_FACTORY_SSCP Property
Every BBj database has a property named SQL_FACTORY_SSCP (displayed in Enterprise
Manager as Scalar/Group Function SSCP). This property tells the SQL engine which SSCP
to use when loading external classes — including value processor classes — for that database.
- In Enterprise Manager, expand the Databases tree and select the target database.
- Open the database's properties / configuration view.
- Locate the property labelled Scalar/Group Function SSCP
(
SQL_FACTORY_SSCP) under the Custom Functionality category.
- Set its value to the name of the SSCP entry you created in Step 1, for example
myProcessorsSSCP.
- Save the database configuration.
SQL_FACTORY and SQL_FACTORY_SSCP
are also used by the custom scalar/group functions feature. If you are already using a
custom BBjSQLFactory for scalar functions, you can extend that existing
factory to also implement ValueProcessorBBjSQLFactory rather than creating
a separate factory class. Both can coexist in the same JAR and the same SSCP.
Step 4: Assign the Processor to a Type Definition
A Type Definition (also called a custom type) is a named schema object in the BBj data dictionary that describes how a column's raw data should be interpreted. It can hold a reference to a value processor class. Type definitions are managed at the database level and can be reused across many columns and tables.
- In Enterprise Manager, navigate to the target database and open the Types (or Type Definitions) section.
- Create a new type definition or edit an existing one.
- In the type definition editor, locate the Value Processor field. A dropdown list will show all value processors discovered for this database (built-in processors plus any found via the configured SSCP).
- Select your processor from the list. The display name and description you implemented
in
getDisplayName()andgetDescription()will be shown to help you identify the correct entry.
- Save the type definition.
Step 5: Assign the Type Definition to a Column
Once a type definition with a value processor is defined, assign it to the specific column(s) whose raw data should be processed.
- In Enterprise Manager, navigate to the target table and open its column editor.
- Select the column whose data the processor should convert.
- In the column's property editor, find the Type Definition (or Custom Type) field and select the type definition you configured in Step 4.
- Save the table definition.
The processor is now active. Any SQL query that reads or writes that column will automatically
invoke computeReturnedValue() and computeRawValue() respectively.
ResultSetMetaData.getColumnType()) and
how it evaluates SQL expressions. Existing queries that compare the column to raw string or
numeric literals (e.g., WHERE flag = 'Y') may need to be updated to use the
processed type (e.g., WHERE flag = TRUE).
Built-In Processor Example: YNBooleanValueProcessor
The built-in YNBooleanValueProcessor is the simplest complete example of a value
processor. It converts a one-character string field whose values are "Y" or
"N" (or variants "T" / "F") to a SQL
BOOLEAN. The full source is reproduced here for reference.
|
Key observations about this implementation:
computeReturnedValue()handlesnulland empty string defensively, treating them asfalse. It checks the first character only, accepting both"Y"/"y"(yes) and"T"/"t"(true) as truthy values.computeRawValue()converts the SQL boolean back to the canonical"Y"or"N"string for storage.getSqlType()returnsTypes.BOOLEANso JDBC clients see an accurate column type.isLexicallyOrdered()returnstruebecause the field has only two possible values, making ordering irrelevant for range query optimization.
java.sql.Types Quick Reference
The following are the most commonly used java.sql.Types constants. Return the
appropriate constant from getSqlType().
| Constant | Integer Value | SQL Type | Expected Java Return Type from computeReturnedValue() |
|---|---|---|---|
Types.BOOLEAN
|
16 | BOOLEAN
|
java.lang.Boolean
|
Types.INTEGER
|
4 | INTEGER
|
java.lang.Integer
|
Types.BIGINT
|
5 | BIGINT
|
java.lang.Long
|
Types.NUMERIC
|
2 | NUMERIC
|
java.math.BigDecimal
|
Types.DOUBLE
|
8 | DOUBLE
|
java.lang.Double
|
Types.VARCHAR
|
12 | VARCHAR
|
java.lang.String
|
Types.DATE
|
91 | DATE
|
java.sql.Date
|
Types.TIME
|
92 | TIME
|
java.sql.Time
|
Types.TIMESTAMP
|
93 | TIMESTAMP
|
java.sql.Timestamp
|
See Also
SQL Custom Value Processors – Overview