Message-ID: <1181883644.1281.1432778776441.JavaMail.firstname.lastname@example.org> Subject: Exported From Confluence MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_Part_1280_714194561.1432778776441" ------=_Part_1280_714194561.1432778776441 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Location: file:///C:/exported.html
Whether you are using groovyc to compile classes or a = ;GroovyShell, for example, to execute scripts, under the hood, a <= a href=3D"http://groovy.codehaus.org/api/org/codehaus/groovy/control/Compil= erConfiguration.html" class=3D"external-link" rel=3D"nofollow">compiler con= figuration is used. This configuration holds information like the sourc= e encoding or the classpath but it can also be used to perform more operati= ons like adding imports by default, applying AST transformations transparen= tly or disabling global AST transformations.
Before Groovy 1.8.0, doing tasks like adding imports transparently (for = DSLs) was a bit complicated. It involved writing a custom GroovyClassLoader= and lots of trickery. The goal of compilation customizers is to make those= common tasks easy to implement. For that, the CompilerConfigurati= on class is the entry point. The general schema will always be based o= n the following code:
Compilation customizers must extend the org.codehaus.groovy.con= trol.customizers.CompilationCustomizer class. A customizer works:
You can implement your own compilation customizer but Groovy includes so= me of the most common operations.
Using this compilation customizer, your code will have imports added tra= nsparently. This is in particular useful for scripts implementing a DSL whe= re you want to avoid users from having to write imports. The import customi= zer will let you add all the variants of imports the Groovy language allows= , that is:
The AST transformation customizer is meant to apply AST transformations = transparently. Unlike global AST transformations that apply on every class = beeing compiled as long as the transform is found on classpath (which has d= rawbacks like increasing the compilation time or side effects due to transf= ormations applied where they should not), the customizer will allow you to = selectively apply a transform only for specific scripts or classes.
As an example, let's say you want to be able to use @Log i= n a script. The problem is that @Log is normally applied on a= class node and a script, by definition, doesn't require one. But implement= ation wise, scripts are classes, it's just that you cannot annotate this im= plicit class node with @Log. Using the AST customizer, you ha= ve a workaround to do it:
That's all! Internally, the @Log AST transformation is app= lied to every class node in the compilation unit. This means that it will b= e applied to the script, but also to classes defined within the script.
If the AST transformation that you are using accepts parameters, you can= use parameters in the constructor too:
As the AST transformation customizers works with objects instead of AST = nodes, not all values can be converted to AST transformation parameters. Fo= r example, primitive types are converted to ConstantExpression (that is 'LOGGER' is converted to new ConstantExpression('LOGGER= '), but if your AST transformation takes a closure as an argument, the= n you have to give it a ClosureExpression, like in the follow= ing example:
This customizer will allow the developer of a DSL to restrict the gramma= r of the language, to prevent users from using some constructs, for example= . It is only "secure" in that sense only and it is very important= to understand that it does not replace a security ma= nager. The only reason for it to exist is to limit the expressiveness of th= e language. This customizer only works at the AST (abstract syntax tree) le= vel, not at runtime! It can be strange at first glance, but it makes much m= ore sense if you think of Groovy as a platform to build DSLs. You may not w= ant a user to have a complete language at hand. In the example below, we wi= ll demonstrate it using an example of language that only allows arithmetic = operations, but this customizer allows you to:
For all those features, the secure AST customizer works using either a w= hitelist (list of elements that are allowed) or a bla= cklist (list of elements that are disallowed). For each type of feature (im= ports, tokens, ...) you have the choice to use either a whitelist or a blac= klist, but you can mix whitelists and blacklists for distinct features. In = general, you will choose whitelists (disallow all, allow selected).
If what the secure AST customizer provides out of the box isn't enough f= or your needs, before creating your own compilation customizer, you might b= e interested in the expression and statement checkers that the AST customiz= er supports. Basically, it allows you to add custom checks on the AST tree,= on expressions (expression checkers) or statements (statement checkers). F= or this, you must implement org.codehaus.groovy.control.customizer= s.SecureASTCustomizer.StatementChecker or org.codehaus.groovy= .control.customizers.SecureASTCustomizer.ExpressionChecker.
Those interfaces define a single method called isAuthorized, returning a boolean, and taking a Statement (or E= xpression) as a parameter. It allows you to perform complex logic over= expressions or statements to tell if a user is allowed to do it or not. As= an example, let's think of a DSL for which you want to make sure that user= s only call methods for which the name is in lowercase:
Here, we say that if the expression is a method call expression, then we= can check the name and return true only if it's all lowercase. Otherwise, = the expression is allowed.
This customizer, available since Groovy 2.1.0 only, is a bit special in = the sense that it may be used as a filter for other customizers. The filter= , in that case, is the org.codehaus.groovy.control.SourceUnit= . For this, the source aware customizer takes another customizer as a deleg= ate, and it will apply customization of that delegate only and only if pred= icates on the source unit match.
SourceUnit gives you access to interesting things, in particular the fil= e being compiled (if compiling from a file, of course), which gives you the= potential to perform operation based on the file name, for example. Here i= s how you would create a source aware customizer:
Then you can use predicates on the source aware customizer:
If you are using compilation customizers in Groovy code (like the exampl= es above) and you are using Groovy 2.1+, then you can use an alternative sy= ntax to customize the compilation. A builder org.codehaus.groovy.c= ontrol.customizers.builder.CompilerCustomizationBuilder is available. = Creating a customizer has never been so easy!
The code sample above shows how to use the builder. A static method,&nbs= p;withConfig, takes a closure corresponding to the builder code, a= nd automatically registers compilation customizers to the configuration. Yo= u can use:
Inlined customizer allows you to write a compilation customizer directly= , without having to create a dedicated class for it.
Of course, the builder allows you to define multiple customizers at once= :
For now, we've shown you how to customize compilation using a C= ompilationConfiguration access, but this is only possible if you embed= Groovy and that you create your own instances of CompilerConfigur= ation (be it with GroovyShell, GroovyScriptEngi= ne, ...). But if you want it to be applied on the classes you compile = (with groovyc, ant or gradle, for= example), until Groovy 2.1.0, there was no way to do that.
Since Groovy 2.1.0 (and Groovy 2.1.1 for the groovy Ant task), it is pos= sible to use a compilation flag named configscript that takes= a groovy configration script as a parameter. This script gives you access = to the CompilerConfiguration instance before the files are compiled (exposed as a variable named configuration= ), so that you can tweak it. It also transparently integrates the comp= iler configuration builder above.
Since static compilation has been released, many people asked for it to = be enabled by default. For various reasons, including the fact that we thin= k you should only limit static compilation to pieces of code where you have= performance problems, we never included such a feature. Other people asked= for default imports too. Since we didn't want to add lots of flags for eac= h and every magic that Groovy can do, we decided to go for a configuration = script. This means that having static compilation by default is just a matt= er of compiling classes using this configuration file. And the content is v= ery easy:
You don't need to add an import for the builder, it's automatically adde= d. Then, compile your files using the following command line:
We strongly recommand you to separate configuration files from classes, = hence the src/main and src/conf directories above.