Add the Grails compiler phase operations?
Eugene, have you considered adding GrailsAwareInjectionOperation to the compiler for Grails projects?
I have been working a javaagent/classloader that bootstraps Grails via a JUnit4TestRunner and dynamically compiles Domain artefacts so they can be tested interactively. It is quite easy to bootstrap grails with a mock MockServletContext, but getting the classloader to work just right is quite complicated. I'll post the details some other time, but I will say now that I have it all working except the Domain class loaded in the unit test turns out to a different instance loaded elsewhere. But even should resolve this last problem, its a shame to have idea do all the work of compiling only to have "grails test-app" do it all over again only to run a single test.
If jetgroovy were to simply to configure compilation units like below, we would be able to test grails apps directly within Idea. Its not enough to have pleasure in coding groovy/grails, testing must be pleasurable as well!
Of course, the integration would need be flexible, not how I hard coded it below.
请先登录再写评论。
Yep, this is where I got stuck: I don't want to hard-code the stufff, ad I don't want a general purpose compiler dfepend on the grails classes. Do you have any idea how this could be handled in a unified manner?
Sure, I have some ideas. It would require some changes to the compilation API in the 'rt' module. But basically Groovy only modules would be as is. Grails modules would add the phase operations. Should be pretty clean. If you willing to add this in, I'll do a spike.
But first I need help building the plugin. (Maybe you answered this in my other post...)
I think, I've devised how to make it lightweight without using Grails libraries. But it would be very interesting to get to know with your ideas.
I wasn't going to try to avoid using the grails libraries. Since only grails projects would need this capability, the grails install must already be configured with the plugin. So why recreate grails code? Simply reusing grails would not required the plugin to change if grails changed its internal implementation.
Do you feel its important not to depend on the grails jars?
Sure, we don't want to drag grails libraries with our plugin. In case of Grails project it would be reasonable to use installed grails.
But I still don't understand how you're going to reuse grails compiler logic not changing our rt module according to it.
I'm thinking along the lines of extending the compiler to allow for generically adding ClassInjectors, which is a groovyc abstraction -- nothing grails specific. Then having the grails facet (or any future facet) "register" facet specific injectors for classes contained within the facet.
As I see it (please correct me if I'm wrong, as I have never worked with the Idea plugin system), GroovycRunner is invoked by the groovy plugin via GroovyCompiler. GroovyCompiler pulls the files from the module being compiled. (What invokes GroovyCompiler.compile? The Idea build system?) Maybe the GroovycRunner could be extended to take the ClassInjectors as command line arguments and GroovyCompiler could extract the ClassInjectors from the Grails facet. Will the GroovyCompiler will also need to add the grails.jar to GroovycRunner's classpath, or is that already there?
Ok, this is just off the top of my head. I you guys have a better or cleaner idea, or any improvements, I'm willing to implement that. But I really need to be able to run tests with the same frequency and productivity as Java in order to make working Groovy just as productive. Groovy is much nicer and more productive in theory than Java, but with a much weaker compiler the tests become even more critical, and hence need to be executable very quickly. Recompiling a large Grails app (via grails test-app) every time one needs to a run a single test is not going to scale.
Barry,
Let me explain our difficulties in implementing this idea. At first, let me notice, that ClassInjector is a class from Grails (not Groovy) distribution. Groovy compiler API provides only CompilationUnit.PrimaryClassNodeOperation interface to alter class structure at some phases of compiler routine. That's why in Grails there are many abstractions such as ClassInjectors. Only this makes your conception hard to implement.
Secondly, as I said we don't want to use Grails API directly to emulate these injections. That's why our current solution is to use Java reflection API to add necessary operations. You can see PhaseOperationUtil class in last revisions of our project.
GroovyCompiler is invoked by CompilerManager and it runs "core" Groovy compiler in separate thread according the legacy issues (see class GroovycRunner).
So, now we can add Grails-specific properties to Grails Domain classes during compilation from IDEA, but not dynamic methods (like addToSmt(...)) which are next issue...
Yes, sorry IIya, I meant GrailsAwareInjectionOperation (its interface) not ClassInjector. Like I said, I've only thought about this, I have not spent any time yet experimenting to see what might be hard or impossible.
If jetgroovy implemented the behavior in GrailsAwareInjectionOperation, where would the code that parses the gorm dsl static declartions and knows what fields/methods need to be injected be located? How would that information be conveyed to GroovycRunner? How would that code keep up to date with changes within grails?
The gorm dynamic methods are added by the gorm plugin, so jetgroovy would not need to inject those. The only stuff that needs to be inject is what is required by hibernate.
I'll look at the PhaseOperationUtil if you want me to pursue this. I don't really care so much what approach is taken. But I would like it the plugin does not break due to internal changes in the gorm implementation.