You are on page 1of 42

Embedded Typesafe Domain

Specific Languages for Java

Rein Raudjärv
rein@zeroturnaround.com

Your Logo Here


Estonia

Your Logo Here


About me

• R&D Java developer


• Public projects
 ZeroTurnaround JSP Weaver – JSP

interpreter
 Aranea Web Application Platform

• I work at Webmedia Ltd


• I teach at University of Tartu
Your Logo Here
Based on
• Article “Embedded Typesafe Domain
Specific Languages for Java”

– by Jevgeni Kabanov & Rein Raudjärv

– applied to Principles and Practice of


Programming in Java '08

– http://typed-asm.googlecode.com

Your Logo Here


Case Studies
• Building SQL queries
– by Rein Raudjärv

• Engineering Java bytecode


– by Jevgeni Kabanov

Your Logo Here


Implementation
• Master thesis “Typed SQL in Java” (2008)

– by Juhan Aasaru

– http://flu.googlecode.com/

Your Logo Here


Domain Specific Language
• Small sub-language that has very little
overhead when expressing domain specic
data and behaviour
• Can be
– A fully implemented language
– A specialised API that looks like a sublanguage
but still written using some general-purpose
language

Your Logo Here


Patterns
• Fluent Interface
• Operator overloading
• Type safety (usually statically typed)

Your Logo Here


DSL Example (dot)
digraph simple_hierarchy {

B [label="The boss"]
E [label="The employee"]

B->E [label="commands",
fontcolor=darkgreen]

Your Logo Here


DSL in Java
• Examples:
– BigDecimal calculations?
– jMock
– Hibernate Criteria (untyped)

Your Logo Here


Building SQL queries
• Unsafe vs safe SQL in Java
• Metadata dictionary
• Builders
• Expressions
• Aliases
• Control Flow and reuse

Your Logo Here


Example 1:
Unsafe SQL in Java

Your Logo Here


Possible mistakes
• Misspelling any SQL command,
like “SELETC".
• Misspelling the table or column names
• Mistaken about the column type
• Reading wrong types from the result set

Your Logo Here


Example 2:
Safe SQL in Java

Your Logo Here


Tuples
• Select builders return only tuples that have
precisely the selected data with types
known ahead
public class Tuple2<T1, T2> implements Tuple{
public final T1 v1;
public final T2 v2;
public Tuple2(T1 v1, T2 v2) {
this.v1 = v1; this.v2 = v2;
}
}
Your Logo Here
Typesafe Metadata
• Metadata used by your DSL should
include compile-time type information.

• We make use of pregenerated metadata


dictionary that contains type information
about tables and columns

Your Logo Here


Builder
Person p = new Person();
List<Tuple3<String, Integer, Date>> rows =
new QueryBuilder()
.from(p)
.select(p.name, p.height, p.birthday)
.list();
...

We use Fluent Interface construct

Your Logo Here


Restricting Syntax
• At any moment of time the DSL builder
should have precisely the methods
allowed in the current state.

• SQL query builders allow from, where and


select to be called
– once and only once
– only in valid order
Your Logo Here
Query Builder
class QueryBuilder extends Builder {
...
<T extends Table> FromBuilder<T>
from(T table);
}

Your Logo Here


From Builder
class FromBuilder<T extends Table>
extends Builder {
...
<C1> SelectBuilder1<T, C1>
select(Col<T, C1> c1);
<C1, C2> SelectBuilder2<T, C1, C2>
select(Col<T, C1> c1, Col<T, C2> c2);
...
}

Your Logo Here


Select Builder
class SelectBuilder2<T extends Table,C1,C2>
extends SelectBuilder<T> {
...
List<Tuple2<C1,C2>> list();
...
}

Your Logo Here


Type History
• You can accumulate type history as a
type list and use it to reject actions that
do not fit with that history

• Select builder types encode information


about selected columns

Your Logo Here


Expression
public interface Expression<E> {
String getSqlString();
List<Object> getSqlArguments();
Class<E> getType();
}

Your Logo Here


Expressions
class ExpressionUtil {
Expr<Bool> and(Expr<Bool>... e)
<E> Expr<Bool> eq(Expr<E> e1, Expr<E> e2)
Expr<Bool>
like(Expr<?> e, Expr<String> pattern)
<E> Expr<E> constant(E value)
Expr<String> concat(Expr... e)
...
}

Your Logo Here


Hierarchical Expressions
• Use
– method chaining when you need context
– static functions when you need hierarchy
and extensibility
or(
eq(p.name, "Peter"),
gt(p.height, 170)
)

Your Logo Here


Example 3:
Safe SQL including WHERE

Your Logo Here


Examples 4 & 5:
Safe SQL including an alias

Your Logo Here


Closures
interface Closure { void apply(Builder b); }

class SelectBuilderC2<C1,C2>
extends SelectBuilder {
SelectBuilderC2<C1,C2>
closure(Closure closure) {
closure.apply(this);
return this;
}
}
}

Your Logo Here


Examples 6:
Safe SQL including control flow
using closures

Your Logo Here


Examples 7:
Safe SQL including rest of the SELECT

Your Logo Here


Examples 8:
Safe SQL including unsafe SQL

Your Logo Here


Unsafe Assumptions
• The unchecked expressions have to
declare the expected type
Expression<Integer> count =
unchecked(Integer.class,
"util.countChildren(id)");

Your Logo Here


Used Patterns
• Restricting syntax (builders allow from,
where and select to be called only once)
• Type history (selected columns)
• Typesafe metadata (data dictionary)
• Unsafe assumptions (unchecked
expressions declare the expected type)
• Closures for mixing with the control flow

Your Logo Here


Bytecode Studycase
• Basics of the bytecode
• Used patterns

Your Logo Here


Class Definition
Modifiers, name, super class, interfaces
Enclosing class reference
Annotation*
Inner class* Name
Field* Modifiers, name, type
Annotation*
Method* Modifiers, name, return and parameter types
Annotation*
Compiled code

Your Logo Here


Java Execution Model
Method B
L0 L1 Local variables
Throwing an exception

O1 Operand stack
Calling a method

Method A
L0 L1 L2

O1 O2 O3 Frame
Main Execution stack
L0 L1 L2 L3

O1 O2

Your Logo Here


Instruction Example
Instruction:

INVOKEINTERFACE java/util/List get (I)V

opcode arguments

Operands stack when applying the instruction:

apply
... java.util.List int ... java.util.List.get(int)

Your Logo Here


Bytecode Engineering
• ASM – Java bytecode engineering library
– Visitor-based API
– Tree-based API
• Completely untyped
• Produced bytecode is only verified runtime
• We introduce a builder that wrappes the
visitor-based API

Your Logo Here


Possible mistakes
• Not enough stack elements for the
instruction
• Stack elements have the wrong type
• Local variables have the wrong type
• Using illegal modifiers or opcodes

Your Logo Here


Used Patterns
• Restricting syntax (hide methods that
consume more stack slots than available)
• Type history (local vars, operand stack)
• Typesafe metadata (class literals)
• Unsafe assumptions (deprecated
methods instead of hidden methods)
• Closures for mixing with the control flow

Your Logo Here


Conclusions
• We have introduced two different DSLs
• Trying to use the most of Java type
system to inhibit wrong behaviour at
compile-time
• Found generic patterns which we
conjecture to be domain-independent

Your Logo Here


QA

Your Logo Here

You might also like