CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-querydsl--querydsl-sql

SQL support for Querydsl - enables type-safe SQL query construction in Java

Pending
Overview
Eval results
Files

type-system.mddocs/

Type System

QueryDSL SQL provides a comprehensive type mapping system between Java and SQL types with support for custom types, automatic conversion, and database-specific type handling across 50+ built-in type handlers.

Capabilities

Core Type Interface

Base interface for all type handlers that define how Java objects are converted to and from SQL values.

/**
 * Core interface for type conversion between Java and SQL
 * @param <T> Java type being handled
 */
public interface Type<T> {
    /**
     * Retrieves value from ResultSet and converts to Java type
     * @param rs ResultSet containing the data
     * @param startIndex Starting column index (1-based)
     * @return Converted Java object
     * @throws SQLException if database access error occurs
     */
    T getValue(ResultSet rs, int startIndex) throws SQLException;
    
    /**
     * Sets value in PreparedStatement after converting from Java type
     * @param st PreparedStatement to set value in
     * @param startIndex Starting parameter index (1-based)
     * @param value Java object to convert and set
     * @throws SQLException if database access error occurs
     */
    void setValue(PreparedStatement st, int startIndex, T value) throws SQLException;
    
    /**
     * Gets the JDBC type codes this handler supports
     * @return Array of JDBC type constants
     */
    int[] getSQLTypes();
    
    /**
     * Gets the Java class this type handler manages
     * @return Java class
     */
    Class<T> getReturnedClass();
    
    /**
     * Creates a literal representation for SQL generation
     * @param value Java value to convert to SQL literal
     * @return SQL literal string
     */
    String getLiteral(T value);
}

Abstract Base Types

Base implementations providing common functionality for type handlers.

/**
 * Abstract base class for all type implementations
 * @param <T> Java type being handled
 */
public abstract class AbstractType<T> implements Type<T> {
    /**
     * Creates type handler for specified Java class
     * @param type Java class this handler manages
     */
    protected AbstractType(Class<T> type);
    
    /**
     * Gets null-safe value from ResultSet
     * @param rs ResultSet to read from
     * @param startIndex Column index
     * @return Value or null if SQL NULL
     */
    protected T getNullableValue(ResultSet rs, int startIndex) throws SQLException;
}

/**
 * Base class for date/time type handlers
 * @param <T> Date/time type
 */
public abstract class AbstractDateTimeType<T> extends AbstractType<T>;

/**
 * Base class for JSR-310 (java.time) type handlers
 * @param <T> java.time type
 */
public abstract class AbstractJSR310DateTimeType<T> extends AbstractDateTimeType<T>;

Primitive and Basic Types

Type handlers for Java primitive types and their wrapper classes.

/**
 * String type handler
 */
public class StringType extends AbstractType<String>;

/**
 * String type that handles SQL NULL as empty string
 */
public class StringAsObjectType extends AbstractType<String>;

/**
 * Integer type handler
 */
public class IntegerType extends AbstractType<Integer>;

/**
 * Long type handler
 */
public class LongType extends AbstractType<Long>;

/**
 * Double type handler
 */
public class DoubleType extends AbstractType<Double>;

/**
 * Boolean type handler
 */
public class BooleanType extends AbstractType<Boolean>;

/**
 * Character type handler
 */
public class CharacterType extends AbstractType<Character>;

/**
 * Byte type handler
 */
public class ByteType extends AbstractType<Byte>;

/**
 * Short type handler
 */
public class ShortType extends AbstractType<Short>;

/**
 * Float type handler
 */
public class FloatType extends AbstractType<Float>;

Usage Examples:

// Register custom type in configuration
Configuration config = new Configuration(templates);
config.register(new StringType());
config.register(new IntegerType());

// Type registration is typically automatic for standard types
SQLQueryFactory queryFactory = new SQLQueryFactory(config, dataSource);

// Types are used automatically during query execution
List<String> names = queryFactory
    .select(qUser.name)  // StringType used automatically
    .from(qUser)
    .fetch();

Numeric Types

Specialized type handlers for high-precision numeric types.

/**
 * BigDecimal type handler for precise decimal arithmetic
 */
public class BigDecimalType extends AbstractType<BigDecimal>;

/**
 * BigDecimal type that maps to DOUBLE SQL type
 */
public class BigDecimalAsDoubleType extends AbstractType<BigDecimal>;

/**
 * BigInteger type handler for arbitrary-precision integers
 */
public class BigIntegerType extends AbstractType<BigInteger>;

/**
 * BigInteger type that maps to BIGINT SQL type
 */
public class BigIntegerAsLongType extends AbstractType<BigInteger>;

Usage Examples:

// Working with high-precision numbers
List<BigDecimal> prices = queryFactory
    .select(qProduct.price)  // BigDecimalType used for DECIMAL columns
    .from(qProduct)
    .fetch();

// Custom precision handling
Configuration config = new Configuration(templates);
config.register("product", "price", new BigDecimalType());

Date and Time Types

Type handlers for various date and time representations.

/**
 * java.sql.Date type handler
 */
public class DateType extends AbstractDateTimeType<java.sql.Date>;

/**
 * java.sql.Time type handler
 */
public class TimeType extends AbstractDateTimeType<java.sql.Time>;

/**
 * java.sql.Timestamp type handler
 */
public class TimestampType extends AbstractDateTimeType<java.sql.Timestamp>;

/**
 * java.util.Date type handler
 */
public class UtilDateType extends AbstractDateTimeType<java.util.Date>;

/**
 * java.util.Calendar type handler
 */
public class CalendarType extends AbstractDateTimeType<Calendar>;

JSR-310 (java.time) Types

Modern Java time API type handlers with timezone support.

/**
 * LocalDate type handler
 */
public class JSR310LocalDateType extends AbstractJSR310DateTimeType<LocalDate>;

/**
 * LocalTime type handler
 */
public class JSR310LocalTimeType extends AbstractJSR310DateTimeType<LocalTime>;

/**
 * LocalDateTime type handler
 */
public class JSR310LocalDateTimeType extends AbstractJSR310DateTimeType<LocalDateTime>;

/**
 * OffsetTime type handler with timezone offset
 */
public class JSR310OffsetTimeType extends AbstractJSR310DateTimeType<OffsetTime>;

/**
 * OffsetDateTime type handler with timezone offset
 */
public class JSR310OffsetDateTimeType extends AbstractJSR310DateTimeType<OffsetDateTime>;

/**
 * ZonedDateTime type handler with full timezone support
 */
public class JSR310ZonedDateTimeType extends AbstractJSR310DateTimeType<ZonedDateTime>;

/**
 * Instant type handler for timestamps
 */
public class JSR310InstantType extends AbstractJSR310DateTimeType<Instant>;

Usage Examples:

// Modern time API usage
List<LocalDateTime> createdTimes = queryFactory
    .select(qOrder.createdAt)  // JSR310LocalDateTimeType used automatically
    .from(qOrder)
    .fetch();

// Timezone-aware queries
List<ZonedDateTime> zonedTimes = queryFactory
    .select(qEvent.scheduledAt)  // JSR310ZonedDateTimeType for timezone data
    .from(qEvent)
    .fetch();

Binary and LOB Types

Type handlers for binary data and large objects.

/**
 * byte[] type handler for binary data
 */
public class BytesType extends AbstractType<byte[]>;

/**
 * byte[] type handler for LONGVARBINARY columns
 */
public class LongVarBinaryBytesType extends AbstractType<byte[]>;

/**
 * java.sql.Blob type handler for binary large objects
 */
public class BlobType extends AbstractType<Blob>;

/**
 * java.sql.Clob type handler for character large objects
 */
public class ClobType extends AbstractType<Clob>;

/**
 * InputStream type handler for streaming binary data
 */
public class InputStreamType extends AbstractType<InputStream>;

Usage Examples:

// Binary data handling
byte[] imageData = queryFactory
    .select(qDocument.content)  // BytesType for VARBINARY columns
    .from(qDocument)
    .where(qDocument.id.eq(docId))
    .fetchOne();

// Large object streaming
InputStream stream = queryFactory
    .select(qDocument.largeContent)  // InputStreamType for streaming
    .from(qDocument)
    .where(qDocument.id.eq(docId))
    .fetchOne();

Enum Types

Type handlers for Java enums with different storage strategies.

/**
 * Enum type handler that stores enum values by name (toString)
 * @param <T> Enum type
 */
public class EnumByNameType<T extends Enum<T>> extends AbstractType<T> {
    public EnumByNameType(Class<T> enumClass);
}

/**
 * Enum type handler that stores enum values by ordinal (int)
 * @param <T> Enum type
 */
public class EnumByOrdinalType<T extends Enum<T>> extends AbstractType<T> {
    public EnumByOrdinalType(Class<T> enumClass);
}

/**
 * Enum type handler that stores enum as generic object
 * @param <T> Enum type
 */
public class EnumAsObjectType<T extends Enum<T>> extends AbstractType<T> {
    public EnumAsObjectType(Class<T> enumClass);
}

Usage Examples:

// Enum by name storage
public enum UserStatus { ACTIVE, INACTIVE, SUSPENDED }

Configuration config = new Configuration(templates);
config.register("user", "status", new EnumByNameType<>(UserStatus.class));

// Enum by ordinal storage (more efficient)
config.register("user", "priority", new EnumByOrdinalType<>(Priority.class));

List<UserStatus> statuses = queryFactory
    .select(qUser.status)
    .from(qUser)
    .fetch();

Boolean Conversion Types

Specialized boolean type handlers for databases that don't have native boolean support.

/**
 * Boolean type that stores as 'T'/'F' characters
 */
public class TrueFalseType extends AbstractType<Boolean>;

/**
 * Boolean type that stores as 'Y'/'N' characters
 */
public class YesNoType extends AbstractType<Boolean>;

/**
 * Boolean type that stores as 1/0 integers
 */
public class NumericBooleanType extends AbstractType<Boolean>;

Usage Examples:

// Configure boolean storage for legacy databases
Configuration config = new Configuration(templates);
config.register("user", "active", new YesNoType());        // Store as Y/N
config.register("user", "verified", new TrueFalseType());  // Store as T/F
config.register("user", "premium", new NumericBooleanType()); // Store as 1/0

List<Boolean> activeFlags = queryFactory
    .select(qUser.active)  // Automatically converts Y/N to Boolean
    .from(qUser)
    .fetch();

Array Types

Type handler for SQL array types with generic element type support.

/**
 * Generic array type handler for SQL ARRAY columns
 * @param <T> Element type of the array
 */
public class ArrayType<T> extends AbstractType<T[]> {
    /**
     * Creates array type handler
     * @param elementType Type handler for array elements
     * @param javaType Java array class
     */
    public ArrayType(Type<T> elementType, Class<T[]> javaType);
}

Usage Examples:

// PostgreSQL array support
Configuration config = new Configuration(PostgreSQLTemplates.builder().build());
config.register("user", "tags", new ArrayType<>(new StringType(), String[].class));

// Query array columns
List<String[]> userTags = queryFactory
    .select(qUser.tags)  // Returns String[] from PostgreSQL text[]
    .from(qUser)
    .fetch();

// Array operations in queries
List<User> users = queryFactory
    .selectFrom(qUser)
    .where(qUser.tags.contains("vip"))  // PostgreSQL array contains operator
    .fetch();

Specialized Types

Type handlers for specialized data types like UUID, URL, XML, and others.

/**
 * java.util.UUID type handler
 */
public class UtilUUIDType extends AbstractType<UUID>;

/**
 * java.net.URL type handler
 */
public class URLType extends AbstractType<URL>;

/**
 * java.util.Locale type handler
 */
public class LocaleType extends AbstractType<Locale>;

/**
 * java.util.Currency type handler
 */
public class CurrencyType extends AbstractType<Currency>;

/**
 * java.sql.SQLXML type handler
 */
public class SQLXMLType extends AbstractType<SQLXML>;

/**
 * XML data stored as String
 */
public class XMLAsStringType extends AbstractType<String>;

/**
 * Generic Object type handler
 */
public class ObjectType extends AbstractType<Object>;

Usage Examples:

// UUID primary keys
Configuration config = new Configuration(templates);
config.register("user", "id", new UtilUUIDType());

List<UUID> userIds = queryFactory
    .select(qUser.id)  // UUID type conversion
    .from(qUser)
    .fetch();

// XML data handling
config.register("document", "content", new XMLAsStringType());

List<String> xmlContent = queryFactory
    .select(qDocument.content)  // XML stored as String
    .from(qDocument)
    .fetch();

Custom Type Creation

Framework for creating custom type handlers for application-specific data types.

/**
 * Interface for null value representation in type system
 */
public class Null {
    public static final Object DEFAULT = new Object();
}

/**
 * Base class for creating custom type handlers
 * @param <T> Java type to handle
 */
public abstract class AbstractType<T> implements Type<T> {
    /**
     * Template method for handling null values
     * @param rs ResultSet to read from
     * @param startIndex Column index
     * @return Null-safe value
     */
    protected T getNullableValue(ResultSet rs, int startIndex) throws SQLException;
    
    /**
     * Template method for setting null values
     * @param st PreparedStatement to write to
     * @param startIndex Parameter index
     * @param value Value to set (may be null)
     */
    protected void setNullableValue(PreparedStatement st, int startIndex, T value) throws SQLException;
}

Usage Examples:

// Custom type for application-specific data
public class MoneyType extends AbstractType<Money> {
    public MoneyType() {
        super(Money.class);
    }
    
    @Override
    public Money getValue(ResultSet rs, int startIndex) throws SQLException {
        BigDecimal amount = rs.getBigDecimal(startIndex);
        String currency = rs.getString(startIndex + 1);
        return amount != null ? new Money(amount, currency) : null;
    }
    
    @Override
    public void setValue(PreparedStatement st, int startIndex, Money value) throws SQLException {
        if (value != null) {
            st.setBigDecimal(startIndex, value.getAmount());
            st.setString(startIndex + 1, value.getCurrency());
        } else {
            st.setNull(startIndex, Types.DECIMAL);
            st.setNull(startIndex + 1, Types.VARCHAR);
        }
    }
    
    @Override
    public int[] getSQLTypes() {
        return new int[] { Types.DECIMAL, Types.VARCHAR };
    }
}

// Register custom type
Configuration config = new Configuration(templates);
config.register("order", "total", new MoneyType());

// Use custom type in queries
List<Money> orderTotals = queryFactory
    .select(qOrder.total)  // MoneyType handles conversion automatically
    .from(qOrder)
    .fetch();

Install with Tessl CLI

npx tessl i tessl/maven-com-querydsl--querydsl-sql

docs

configuration.md

database-templates.md

dml-operations.md

index.md

query-construction.md

sql-expressions.md

type-system.md

tile.json