ATL Transformations

Debugging Transformations

Learn techniques for debugging ATL transformations and diagnosing common transformation issues.

In this tutorial, you’ll discover how to trace transformation execution, diagnose binding errors, and resolve common ATL problems.

You’ll master systematic debugging approaches that help you quickly identify and fix transformation issues.

35 mins Estimated Time

Section 1

Understanding Transformation Errors

ATL transformations can fail for various reasons: missing bindings, type mismatches, undefined references, or OCL expression errors.

Understanding error messages and common failure patterns is essential for efficient debugging.

Step 1

Recognise common error patterns.

This example shows typical error scenarios: undefined bindings, null references, and type mismatches.

DebugExample.atl
1-- @path Source=/Source/Source.ecore
2-- @path Target=/Target/Target.ecore
3
4module DebugExample;
5create OUT: Target from IN: Source;
6
7-- Common error: accessing property of undefined reference
8helper context Source!Element def: errorProne(): String =
9 self.parent.name; -- Fails if parent is undefined!

Step 2

Add defensive checks.

Use oclIsUndefined() and type checks to prevent runtime errors.

DebugExample.atl
1-- @path Source=/Source/Source.ecore
2-- @path Target=/Target/Target.ecore
3
4module DebugExample;
5create OUT: Target from IN: Source;
6
7-- Fixed: check before accessing
8helper context Source!Element def: safeName(): String =
9 if not self.parent.oclIsUndefined() then
10 self.parent.name
11 else
12 'No parent'
13 endif;

Step 3

Validate helper results.

Ensure helpers return valid values before using them in bindings.

DebugExample.atl
1-- @path Source=/Source/Source.ecore
2-- @path Target=/Target/Target.ecore
3
4module DebugExample;
5create OUT: Target from IN: Source;
6
7-- Validate helper returns expected type
8helper context Source!Element def: getCount(): Integer =
9 if not self.items.oclIsUndefined() then
10 self.items->size()
11 else
12 0 -- Safe default
13 endif;

Step 4

Handle edge cases.

Test boundary conditions like empty collections and optional references.

DebugExample.atl
1-- @path Source=/Source/Source.ecore
2-- @path Target=/Target/Target.ecore
3
4module DebugExample;
5create OUT: Target from IN: Source;
6
7-- Handle empty collections
8helper context Source!Container def: firstElementName(): String =
9 if self.elements->notEmpty() then
10 self.elements->first().name
11 else
12 'Empty container'
13 endif;

Section 2

Debugging Techniques

Systematic debugging involves tracing execution, validating intermediate results, and testing transformations incrementally.

Use logging helpers, incremental development, and careful testing to identify issues.

Step 1

Add logging helpers for debugging.

Create helpers that output diagnostic information during transformation.

DebugExample.atl
1-- @path Source=/Source/Source.ecore
2-- @path Target=/Target/Target.ecore
3
4module DebugExample;
5create OUT: Target from IN: Source;
6
7-- Debug helper that traces execution
8helper context Source!Element def: debugInfo(): String =
9 'Processing: ' + self.name + ' (type: ' + self.oclType().name + ')';

Step 2

Debug collection operations.

Verify collection operations produce expected results.

DebugExample.atl
1-- @path Source=/Source/Source.ecore
2-- @path Target=/Target/Target.ecore
3
4module DebugExample;
5create OUT: Target from IN: Source;
6
7-- Verify collection operations
8helper context Source!Container def: verifiedChildren: Sequence(Source!Element) =
9 let filtered : Sequence(Source!Element) =
10 self.children->select(c | not c.name.oclIsUndefined()) in
11 filtered; -- Can add debug output here

Step 3

Test transformations incrementally.

Build transformations gradually, testing each rule independently.

DebugExample.atl
1-- @path Source=/Source/Source.ecore
2-- @path Target=/Target/Target.ecore
3
4module DebugExample;
5create OUT: Target from IN: Source;
6
7-- Test one rule at a time
8rule SimpleTransform {
9 from
10 s: Source!Element
11 to
12 t: Target!Item (
13 name <- s.name
14 )
15}
16
17-- Add more rules incrementally after testing above

Step 4

Build a robust transformation with error handling.

The complete transformation demonstrates defensive programming and error handling techniques.

DebugExample.atl
1-- @path Source=/Source/Source.ecore
2-- @path Target=/Target/Target.ecore
3
4module DebugExample;
5create OUT: Target from IN: Source;
6
7-- Defensive helper with null checking
8helper context Source!Element def: safeName(): String =
9 if not self.parent.oclIsUndefined() then
10 self.parent.name
11 else
12 'Root Element'
13 endif;
14
15-- Helper with collection validation
16helper context Source!Container def: validChildren: Sequence(Source!Element) =
17 if not self.children.oclIsUndefined() then
18 self.children->select(c | not c.oclIsUndefined())
19 else
20 Sequence{}
21 endif;
22
23-- Robust rule with comprehensive error handling
24rule ElementTransform {
25 from
26 s: Source!Element
27 to
28 t: Target!Item (
29 name <- s.safeName(),
30 description <- if not s.description.oclIsUndefined() then
31 s.description
32 else
33 'No description provided'
34 endif
35 )
36}

Check Your Understanding

Question 1 of 3

What is the most common cause of ATL transformation failures?

Question 2 of 3

When should you use oclIsUndefined()?

Question 3 of 3

What is the best approach to debugging complex transformations?

Complex Model Transformations

Master complex transformation scenarios including refining mode, multiple source/target models, and sophisticated rule coordination.