Why is this Groovy AST transformation within a Grails app only being applied during class reloading? - grails

In an attempt to develop a global AST transformation to add a new method to an Enum class within my app, I've set up this example project using Grails 5.
https://github.com/davebrown1975/grails_enum_experiment
The expected behaviour is that on compilation/building, the AST transform will be applied to the single enum class in the project ('tst.ExampleEnum'). I can see the 'visit' method being called in my Transformer ('tst.EnumTranslationTransformation'), however the sourceunit ast classes passed as a parameter to the visit method never include my Enum class.
Once the app is running however, if I make the simplest change to the Enum class, e.g. pressing space somewhere and saving it to trigger compilation and reloading, then this time I will see output in the console informing me the visit method was called AND the enum class was detected and AST has been applied.
Things I've tried, as per Grails docs, established the transforming class in it's own 'plugin', putting the class into a sub package of org.grails.compiler. Neither of these made a difference and I didn't see the AST being called at ever until I referenced the EnumTranslatorTransformation class from within a new file META-INF/services/org.codehaus.groovy.transform.ASTTransformation
Any thoughts as to what I'm missing here would be greatly appreciated.

The solution I found that ensures the AST is compiled and applied to the Enums at build time was to place the transformation into an inline plugin. What was critical at this point was to ensure that the META-INF/services/org.codehaus.groovy.transform.ASTTransformation file was moved to the plugin and not the main app. Only then would I see the transformation applied after a clean and build of the project.

Related

Using the analyzer package, is it possible to create an instance of a DartType representing a would-be generated code?

While using the analyzer package, I was wondering if it was possible to create an instance of its DartType object.
The issue I'm facing is, the analyzer output doesn't give me a valid DartType for a given class because that class has yet to exist (it is not yet generated by a code-generator).
I can work around not using DartType directly and instead make some copycat class. But that adds a lot of complexity. So I'd like to be able to create a DartType representing the would-be generated class.
I've looked into the TypeSytem/TypeProvider objects which seem to object type-related utilities but didn't find anything I wanted.
Is that possible?

grails 2.5+ Duplicate class definition error when implementing serializable on a controller

Upgrading a legacy system of grails. One of the controllers implements Serializable. This is throwing the following error in newer versions of grails:
Invalid duplicate class definition of class com.regional.ScheduleController :
The source contains at least two definitions of the class.
One of the classes is an explicit generated class using the class statement,
the other is a class generated from the script body based on the file name.
Solutions are to change the file name or to change the class name.
The solution mentioned would break (previous) grails convention. Anyone know how to handle this in grails 2.5+?
EDIT
Serializable is not the issue. I tried removing it and got the same error.
I found this explanation from another question:
IN groovy.. class B{} is a class structure and defines a class B.
Scripts are classes too.
Now you may create a B.groovy, with the content "class B{}; def b = new B()".
There would be one class named B, and a script with the very same name.
This is a conflict.
However this does not explain why it runs fine below grails 2.5 and not above it. And I can't find a def conflict like the one mentioned above in that controller.
ANSWER:
One of the imports was what was actually failing- in a way that caused groovy to generate a class definition based on the current file name. When it hit the class definition, there was already an auto generated class name to collide with.

What its the first, the annotated class (egg) or used class (chicken)?

certainly I have not read something fundamental, and it seems very strange, but I wonder.
Suppose you use
#SharedPref
public interface SharedPreferencesInterface {
#DefaultBoolean(true)
boolean showDeviceName();
I have the IDE (idea) configured with Gradle, and I generated the SharedPreferencesInterface_ class that I can use in another class as
#Pref
SharedPreferencesInterface_ prefs;
But suppose someone now download the project, how can the use? Because the class where used SharedPreferencesInterface_ not compile because the class does not exist, and the class does not exist because compilation errors ...
How it's made? Surely there is a way ... configured to compile certain classes first?
Help is appreciated.
A greeting.
But suppose someone now download the project, how can the use? Because
the class where used SharedPreferencesInterface_ not compile because
the class does not exist, and the class does not exist because
compilation errors ...
This is the same situation when you compile a project in a full build (when no classes are generated yet). Actually Gradle always does a full build currently in Android projects. No configuration is needed at all in addition to the standard AndroidAnnotaions config.
Actually this works because the compiler does not fully compiles your class before passing it to annotations processing. It is clear it should not to, because the class may reference generated classes, which are only available after the processing. So first the compiler creates a model of the classes, only parses the structure of the them (fields, methods, return types, parameter types, etc), but not the implementations. Also it allows missing types even on fields. If it finds a missing type, it assigns to TypeKind.ERROR, but the name of the type is still available for the annotation processor. After the processor is done, it generates the missing class, so the kind of the class is no longer TypeKind.ERROR, and the compilation can succeed.

Grails Logging - Exclude One Class

I have a project consisting of hundreds of various classes. One of these extends a class located in a JAR library and produces tons of log info. I would like to exclude this one class from producing all this logging information.
Here's my config.groovy logging section:
trace('grails.plugin.springsecurity.web.filter.DebugFilter',
'grails.app.conf.com.myrootpackage',
'grails.app.controllers.com.myrootpackage',
'grails.app.domain.com.myrootpackage',
'grails.app.filters.com.myrootpackage',
'grails.app.services.com.myrootpackage',
'grails.app.taglib.com.myrootpackage',
'com.myrootpackage')
Since all of my classes are located in the com.myrootpackage package or sub packages of that, I'm not sure how to exclude the one class. As far as I can tell, the logging setup in config.groovy only allows specifying the beginning of class names so I would have to specify by name all other classes and omit the one I want to omit, or move the one I want to omit to a separate root package. Both of these seem silly to have to do to just omit one class from producing log output.
As far as I can tell, the logging setup in config.groovy only allows specifying the beginning of class names
No, you can use the full class name to configure an individual class, so the following should work
trace('grails.plugin.springsecurity.web.filter.DebugFilter',
'grails.app.conf.com.myrootpackage',
'grails.app.controllers.com.myrootpackage',
'grails.app.domain.com.myrootpackage',
'grails.app.filters.com.myrootpackage',
'grails.app.services.com.myrootpackage',
'grails.app.taglib.com.myrootpackage',
'com.myrootpackage')
error 'com.myrootpackage.ExcludeMe'
I've assumed
com.myrootpackage.ExcludeMe is the fully-qualified name of the class in question
this class should log at the error level instead of trace

Reduce number of class files produced by BlackBerry app

I have developed an order processing application for BlackBerry. When I look at the bin folder I see more than 100 .class files.
I have created a main screen class for adding new clients. The screen has 7 LabelField objects and 7 corresponding TextField objects. This screen also creates a VerticalFieldManager and adds all these fields to it and then adds the VerticalFieldManager to the screen.
For this screen, I have 14 .class files in the bin folder. It seems there is one class file for every field in the progam.
For example:
NewClient.class
NewClient$1.class
...
NewClient$14.class
How do I design the UI in order to reduce the number of compiled classes?
Building a Java-ME app for BlackBerry is a two step process. First the java source code is compiled to class files, then those class files are compiled again into a .cod file, which can be deployed onto a simulator or a device.
'rapc' is the RIM compiler that takes java programs and turns them into a cod or alx file for deployment. 'rapc' can take either java source code, or compiled java classes. Either way, it can produce output suitable for a device.
When starting with Java source files, you can explicitly compile them to class files and hand those class files to rapc or you can pass the Java source to rapc and it will compile the source directly. rapc just defers to the JDK javac compiler when presented with java source code. This means a standard java JDK compiler is always used as the first step of compiling a BlackBerry app, and we can look at standard java behavior to understand what is happening.
In Java, every class that is instantiated has exactly one .class file. For normal classes with a declared name, like this:
public class Foo extends Bar {
}
The .class file is assigned a name that matches the declared class name. However, Java also allows anonymous classes. These take the form of a new Foo() followed by a curly brace which turns this into an anonymous class. This presents a problem, as this anonymous class must be assigned a name at the VM level, despite having none at the Java source level. The solution is to use a character that is invalid in Java source, but valid in the VM, namely $. The anonymous classes are assigned a name based on the enclosing Java class, followed by $, then an integer index based on the number of anonymous classes ahead of this one. In your case, that is NewClient, followed by 14 distinct integers.
To see the behavior you describe, your fields must all actually be anonymous implementations of those classes you mention. To reduce the number of classes, try reusing explicit classes, instead of writing custom behavior with each instantiation.
Set your jdk bin folder path on the environment variable path on right clicking on the myComputer icon
Then Restart the pc
Other way is to don't use overwrite method on your code such as
btmSave.setChangeListner(new FieldChangeListner()
{
private void fieldChange()
{
}
}
);
Avoid This type of writing code it create your no of class Files on project bin folder

Resources