DEV Community

SHASHIDHAR PATIL
SHASHIDHAR PATIL

Posted on

Stop Writing Boilerplate Code: Automate Code Generation with Eclipse Xtext.

I've been working as Software Developer mainly focussed on Java and builts many application using Eclipse RCP framework or VS Code Application.

Almost all the time I had to deal with multiple large files (either read/generate/validate) them which seemed very difficult and some of them almost impossible as most of them would be dependant on each other and would be referencing each other (just like how java files work together).

Now assume client1 requires the same content in multiple Json files and client2 needs it in xml files. We couldn't go on writing a different application or go on adding if conditions and blah blah blah !!!!

Wouldn't it be easier if as soon as I execute the application it generates the content in whatever format I choose and also taking care of dependencies/ references (like adding import statements). Additionally integrate with features of IDE and provide proposals, perform validations on the fly.

Rela World Examples : Try googling Arxml once (Trust me I've dealing with these files for almost 7 years and it's always a nightmare to debug these)

Solution: Xtext framework

In this tutorial, I will show you how to use Eclipse Xtext and Xtend to build a simple, readable DSL that automatically generates Java boilerplate for you.

Fair Warning: There will be no running executions screenshots or anything. You are gonna have to run it yourself and check the results and of course questions are always welcome in the comments section. But if for some reason you are unable to replicate this then let me know I'll try to explain further. I believe the best way to learn is by doing it yourself.

The Goal: What are we building?

Instead of writing 100 lines of Java with private fields, getters, and setters, we want our developers to write 5 lines of code in our own custom language (basically you can create your own programming language with your own custom syntax), like this:


entity User {
    var name : String
    var age : Integer
}
Enter fullscreen mode Exit fullscreen mode

When this file (assume file extension is .sp) is saved, Xtext compiler will automatically read it and generate a fully formed Java class in the background.

Prerequisites

  • Java 11 or higher.

  • Eclipse IDE for Java and DSL Developers (which comes pre-packaged with Xtext and Xtend).

  • Basic understanding of Abstract Syntax Trees (AST).

Step 1: Defining the Grammar (The Rules of our Language)

In Xtext, everything starts with the Grammar. The grammar defines the exact syntax user is allowed to type. Xtext uses a format similar to EBNF (Extended Backus-Naur Form).

Create a new Xtext project in Eclipse (In this wizard you can customize extension of your file like .sp as mentioned earlier.) and open your .xtext file. Define the grammar like this:

grammar org.example.domain.EntityDsl with org.eclipse.xtext.common.Terminals // This provides the common elements //which we can use

//It generates POJO classes based on the grammar specified 
generate entityDsl "http://www.example.org/domain/EntityDsl"

// The main root model of your file
RootModel:
    elements+=Entity*;

// An Entity has a name and contains multiple features (variables)
Entity:
    'entity' name=ID '{'
        features+=Feature*
    '}';

// A feature is a variable declaration
Feature:
    'var' name=ID ':' type=ID;
Enter fullscreen mode Exit fullscreen mode

The Enterprise Advantage: EMF and Ecore Integration

One of Xtext's greatest strengths is it's native integration with the Eclipse Modeling Framework (EMF). In an enterprise environment, you don't always generate an AST from scratch. Instead, you can import existing .ecore meta-models directly into your grammar:

// Example of importing an existing Ecore model
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
Enter fullscreen mode Exit fullscreen mode

This allows you to directly reference, map, and reuse production-ready models within your DSL, making it incredibly powerful for legacy migration or systems working within existing modeling structures.

Basically you can create a ecore file and define your model structure there and use it in xtext. This helps when grammar becomes too long or model is huge.

Step 2: The Code Generator (Translating to Java)

Now that grammar is ready, we need to generate something out of it (like a java file / xml/ json / any other format). We do this using Xtend, a dialect of Java perfectly suited for template-based code generation.

Open the generated EntityDslGenerator.xtend file. This class receives the AST (your parsed custom code) and allows you to output strings (Here I'm programming to generate a java file with java appropriate syntax).

class EntityDslGenerator extends AbstractGenerator {

    override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
        // Find every 'Entity' in our parsed custom file
        for (entity : resource.allContents.toIterable.filter(Entity)) {
            // Create a new .java file for each Entity
            fsa.generateFile(entity.name + ".java", entity.compile)
        }
    }

    // The template that generates the Java code
    def compile(Entity e) '''
        public class «e.name» {

            «FOR f : e.features»
                private «f.type» «f.name»;
            «ENDFOR»

            «FOR f : e.features»
                public «f.type» get«f.name.toFirstUpper»() {
                    return this.«f.name»;
                }

                public void set«f.name.toFirstUpper»(«f.type» «f.name») {
                    this.«f.name» = «f.name»;
                }
            «ENDFOR»
        }
    '''
}
Enter fullscreen mode Exit fullscreen mode

Notice the French quotes« » and triple template '''. These are Xtend's template expressions. They allow you to seamlessly mix raw string output (the Java code) with the logic of your AST (the variables from your DSL).

Step 3: Run, Validate, and Auto-Complete

1.Run the GenerateEntityDsl.mwe2 workflow file. This compiles your grammar.

2.Launch a new Eclipse instance from your workspace. (Click on Run or debug option)

3.In the new instance, create a file named Model.entity and paste in our custom code. (Just like how a new java file is created from context menu in the explorer)

4.Saving the created file triggers the generator. Check the src-gen folder, and you will see your perfectly formatted User.java file.

Elevating the Developer Experience (IDE Tooling)

Modern developers expect IDEs to guide them. Just like Eclipse or VS Code provides error indicators and auto-complete suggestions, Xtext allows you to customize validations and proposals out-of-the-box.

  • Custom Validation: Open your generated EntityDslValidator.xtend file to write custom compiler checks. For example, if you want to warn developers against capitalized variable names:
@Check
def checkFeatureNameStartsWithLowercase(Feature feature) {
    if (!Character.isLowerCase(feature.name.charAt(0))) {
        warning("Name should start with a lowercase letter", 
                EntityDslPackage.Literals.FEATURE__NAME)
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Custom Proposals (Content Assist): You can open the EntityDslProposalProvider.xtendfile to inject custom logic into the Ctrl+Space menu, suggesting context-specific templates or default variables dynamically as the developer types.

Real-World Gotchas (Senior Developer Tips)

If you are implementing this in a production environment, watch out for these critical architecture traps:

1. The Multi-File Import and Scope Nightmare

In real-world systems (especially when dealing with massive automotive ARXML configurations), you will almost never be working with a single isolated file. Your DSL will span dozens or hundreds of files that reference each other.

Tracking imports, dependencies, and index changes across a distributed file structure is incredibly tedious if coded manually.

The Fix: Xtext excels at global scope resolution. By utilizing Xtext's default ImportUriGlobalScopeProvideror customizing your own IScopeProvider, Xtext automatically indexes all files in the developer's workspace. This allows a variable defined in FileA.entity to be referenced in FileB.entity with instant compiler validation and zero manual tracking code.

2. Workspace Synchronization

When your generator writes files to the src-gen folder, ensure you are using the IFileSystemAccess2API (as shown in Step 2) rather than standard java.io.File. The Eclipse workspace needs to be notified that a new file was created so it can automatically compile it. IFileSystemAccess2handles this perfectly.

3. Grammar Ambiguity

If your custom language starts to grow, be careful of left-recursive rules in your grammar, which will cause the parser to crash with infinite loops. Always structure your rules hierarchically.

Conclusion

Building a DSL sounds like academic computer science, but it is one of the most practical tools in an enterprise engineer's toolbelt. By spending 3 days building a custom Xtext grammar and generator, you can save your development team hundreds of hours of manual boilerplate coding over the lifespan of a project.

Have you ever built a custom code generator for your team? Let me know in the comments below!

Top comments (0)