Code Injection

Note, first of all, that the INJECT statement does not exist in Legacy JavaCC.

INJECT allows you to specify extra code that will be placed (or “injected”) in generated java code. It can appear anywhere in your grammar where you could place a BNF production or Token production. It can be written in one of two forms.

1. An INJECT block that specifies the class name

This form a class (or interface) name and looks something like this:

 INJECT Foobar : 
    import foo.bar.IFoobar; 
    implements IFoobar;
 { 
     private Foo value;
     public Foo getValue() { return value; }
     void setValue(Foo value) { this.value = value; }
 }

The above snippet should be self-explanatory. The INJECT statement specifies the class in which to inject the code. In this example, it is Foobar. The first block after the colon is a prologue in which you can specify imports as well as en extends and/or an implements clause. The second block contains the actual code to be injected in the type declaration itself.

Since an INJECT block can be placed anywhere in your grammar file where you could put a production, you would naturally tend to place the above snippet next to the relevant BNF production, which would, of course, be the Foobar production.

2. The INJECT block with no type specified

The other form of writing INJECT does not specify the class into which the code will be injected. That looks something like this:

   INJECT : {
     import foo.bar.Edible;
     import foo.bar.Eater;

     public Token implements Edible {

         public void eatMe(Eater e) {
            e.eat(this);
         }
     }
   }

The above code causes the code within the block to be injected inside the generated Token.java file – in this example, it would be presumably so that the Token object can implement the foo.bar.Edible interface.

Using injected code is incompatible with post-editing the files

It is important to realize that post-editing generated files and using INJECT are mutually exclusive – well, at least on a file by file basis. JavaCC 21 assumes that any file into which you inject code is to be regenerated each time. Thus, any changes you make by post-editing the generated source would be overwritten. Of course, that said, the INJECT feature was designed to supersede the post-editing of generated files, which is basically… evil.

Note that the other way of altering the generated code (that is also unavailable in Legacy JavaCC) is to provide custom FreeMarker templates. However, that should only be necessary quite rarely.