Grails's #Transactional will disable the #CompileStatic annotation - grails

I add two annotations on the service method, after compiled, I found the method were compiled to a new class file, and I decompiled the generated class files and found the #CompileStatic were not work as wished.
Is is right or a bug of grails?
class FoobarService {
#grails.transaction.Transactional
#groovy.transform.CompileStatic
void foobar() {
....
}
}

The grails.transaction.Transactional annotation is a replacement for the traditional Spring org.springframework.transaction.annotation.Transactional annotation. It has the same attributes and features and works essentially the same, but it avoids an unfortunate side effect of using the Spring annotation.
The Spring annotation triggers the creation of a runtime proxy of the annotated class. Spring uses CGLIB to create a subclass of the target class (typically a Grails service) and an instance of the CGLIB proxy is registered as the Spring bean instead of registering a service instance directly. The proxy gets an instance of your service as a data variable.
Each method call is intercepted in the proxy, where it does whatever checks and/or setup is required based on the transaction settings, e.g. joining an existing transaction, creating a new one, throwing an exception because one isn't already running, etc. Once that's done, your real method is called.
But if you call another annotated method with different settings (e.g. the first method uses the default settings from #Transactional but the second should be run in a new separate transaction because it's annotated with #Transactional(propagation=REQUIRES_NEW)) then the second annotations settings will be ignored because you're "underneath" the proxy , inside the real instance of your service that the proxy is intercepting calls to. But it can't intercept direct calls like that.
The traditional workaround for this is to avoid direct calls and instead make the call on the proxy. You can't (at least not conveniently) inject the service bean into itself, but you can access the application context and access it that way. So the call that you would need in that situation would be something like
ctx.getBean('myService').otherMethod()
which works, but is pretty ugly.
The new Grails annotation works differently though. It triggers a reworking of the code via an AST transformation during compilation. A second method is created for each annotated method, and the code from the real method is moved inside there, in a GrailsTransactionTemplate that runs the code using the annotations settings. Once there, the code runs with the required transaction settings, but since every method is rewritten in this way, you don't have to worry about the proxy and where you're calling the methods from - there is no proxy.
Unfortunately there's a side effect that you're seeing - apparently the transformation happens in a way that isn't preserving the #CompileStatic annotation, so the code runs in dynamic mode. Sounds like a bug to me.

Related

grails how to disable transactional for a method

I have a service method to transfer funds to/from an external system.
it should create a transaction in our system first (so we have a transactionId)
Then we call the external system.
If the external system fails, we need to rollback the transaction, then write a new record in our payment audit log table, regardless of if the call failed or worked.
I cant figure out how to control the transaction in this case.
I understand services are transactional by default.
I assume I could create 3 methods (they are all 1 method now, which doesn't work as I have no control over what gets committed and what gets rolled back)
createPaymentTransaction()
sendToPaymentSystem()
createPaymentRecord()
I need to rollback 1 if 1 fails, and do nothing more.
I need to rollback 1 if 2 fails, but write 3.
I need to write 3 if 1 and 2 works.
I don't know how to annotate these, or how to structure a 4th request to manage the 3.
I'd go with something like this:
package com.myapp
import grails.transaction.Transactional
import org.springframework.transaction.annotation.Propagation
#Transactional
class MyService {
def createPaymentTransaction() {}
def sendToPaymentSystem() {}
#Transactional(propagation=Propagation.REQUIRES_NEW)
def createPaymentRecord() {}
def method4() {
try {
def transactionId = createPaymentTransaction()
sendToPaymentSystem(transactionId)
}
finally {
createPaymentRecord()
}
}
}
By annotating at the class level, we set the defaults for all methods, but can customize as needed, e.g. for createPaymentMethod.
So what will happen is that calling method4 will join an existing transaction, or start a new one if necessary. If there's a problem in either createPaymentTransaction or sendToPaymentSystem then the transaction will be rolled back, but the call to createPaymentRecord will happen because it's in the finally block, and it will run in a separate transaction so it isn't affected by a rollback in the main transaction, and a failure there doesn't affect the main transaction.
If you're not able to use the new grails.transaction.Transactional annotation, use the standard Spring org.springframework.transaction.annotation.Transactional annotation, but you need to make a small change. One of the motivations for the Grails annotation is to provide the same functionality as the Spring annotation, but avoid the problems with calling an annotated method from within the service. The Spring annotation triggers creation of a proxy at runtime which intercepts all calls, manages transactionality for the method, and then calls the real method in the service instance. But with the current code, the call to createPaymentRecord will bypass the proxy (the service instance is just calling itself) and there won't be a new transaction. The Grails annotation rewrites the bytecode to wrap each method in a transaction template which uses the applicable annotation settings (explicit or inferred from a class-scope annotation), so it works correctly internally and externally. If using the Spring annotation, you need to call the method on the proxy, which just involves accessing the Spring bean for this service. Add a dependency injection for the GrailsApplication as a field:
def grailsApplication
and then call createPaymentRecord via
grailsApplication.mainContext.myService.createPaymentRecord()
in the finally block.
By default all methods in a service are transactional, but you can change the behaviour on a method-by-method basis with annotations, e.g.
import grails.transaction.*
// By default all methods are transactional
#Transactional
class MyService {
#NotTransactional
def notTransactional() {
}
// inherits the class-level default
def transactional() {
}
}
See the Grails manual for more details about the transaction annotations.
If you need to manage transactions at a more fine-grained level than per-method, you can use the withTransaction domain class method to manage transactions programatically.

Grails Spring Security Expression - How to access Method parameter

Using the Spring Security Plugin for Grails:
Version: 2.0-RC2
For my controllers I am using the #Secured annotation.
Is there a way to access the method parameter from the spring security expression.#paramName does not work for me.
#Secured(['ROLE_ADMIN',"hasRole('ROLE_USER') && #permissionService.updateAllowed( #myInstance )"])
def update(Bug myInstance) {
The problem: myInstance is null!
Software I am using:
Grails: 2.4.3
Intellij 14
JDK 8
I didn't notice that you were doing this in a controller - there's no support for method args in annotated controllers. The reason for this is that in traditional Spring Security, the annotation is applied to Spring Beans and the bean becomes proxied, and the proxy does the security checks before calling the method and only calls the real method if the checks pass. That works well with Spring MVC controllers because they're regular Java classes, and also in Grails services because there isn't much added to services by Grails - they're really just regular Groovy classes that are auto-registered as Spring Beans, and by default are made transactional.
But controllers are weird. There is actually one SpringMVC controller in any Grails app, and it's internally created and used by Grails. It interacts with the rest of SpringMVC, and delegates to the controller that best matches the url mappings rule for the current request to do its work, and it uses that to create the ModelAndView that Spring expects. Additionally, to support databinding, there's an AST transform that runs on your code during compilation which creates a no-arg method for each method with args, and that is what is called from the Grails internal request handling code. It does databinding and type conversions, and calls the "real" method to handle the request.
The support in Spring Security for working with method args depends on debug information being available in the compiled code, and usually this is not available because it's rarely needed - javac connects everything for us at compile time and getting the value of a method arg from outside of the method isn't often needed. Grails does keep that debug info - that's why this works in a service - but it looks like the AST isn't. It might be possible to get that working, but I have no idea if it is or what would be involved, and to be honest it would likely be a lot of work for a feature that wouldn't be used a lot.
But you can rework the check to pass the params to the service and let it lookup the Bug instance and then do its check. You can access the params from the service, so there's no need to pass anything as args:
import org.springframework.web.context.request.RequestContextHolder
...
def params = RequestContextHolder.requestAttributes.params
I've managed to get a workaround for the problem described in the comments to the accepted answer. Use #this in SpEL expression:
#Secured('#securityService.userCanEditOffer(#this)')
def edit(int id) {..}
Then create such methods in your service:
def userCanEditOffer(WebSecurityExpressionRoot webSecurityExpressionRoot) {
UrlMappingInfo urlMappingInfo = Holders.applicationContext.grailsUrlMappingsHolder.match(webSecurityExpressionRoot.request.forwardURI.substring(webSecurityExpressionRoot.request.contextPath.length()))
userCanEditOffer(Integer.valueOf(urlMappingInfo.params.id))
}
#Transactional(readOnly = true)
def userCanEditOffer(Integer id) { .. }
Inside ulrMappingInfo.params you'll have id, action and controller!

Grails Cache and EHCache Plugin caches Controller methods but not Service methods

I'm having trouble getting the Grails EHCache Plugin to cache service methods. Here is my setup:
Grails 2.4.2, JDK 1.7
BuildConfig.groovy compile ":cache-ehcache:1.0.4"
Config.groovy defines the following cache named "cache"
grails.cache.config = {
cache {
name 'cache'
timeToLiveSeconds 60
}
}
The following controller method properly caches. I have tested by setting a breakpoint in the method, and it only is hit the first time, until the cache expires.
#Cacheable('cache')
def index() {
render "index-$params.id"
}
I can check the keys in the cache with:
grailsCacheManager.getCache('cache').getNativeCache().getKeys()
and see the value:
localhost:GET:/grails-cache-test/cache/index?id=34
So far so good.
The following service method exists:
#Cacheable('cache')
public method1(id) {
"method1+$id"
}
I set a break point in here, and this method is always called, regardless of the #Cacheable annotation. I've tried setting the value and key annotation attributes manually, and no change. I test calling this method from a non-cached controller method, as well as directly from the console plugin. When I get the keys in the service method I see that there are no keys set.
I've looked through examples in the official documentation, code samples online, github, a book I have, everything looks good, so I'm not sure where the problem lies.
Any ideas on why this service method does not cache the value? Thanks!
UPDATE 1
I've been digging into the grails cache-1.1.8 plugin (as well as the associated cache-ehcache-1.0.4 plugin), and believe I've found something helpful. In PageFragmentCachingFilter.doFilter() there are calls to check the controller's annotations - but nothing to check the service. It appears that as a result, the service annotations are never honored. There is a lot of documentation that mentions service methods, so I don't know if there is something elsewhere that handles this, or if it's a less common use case compared to controller methods.
UPDATE 2
It appears that Controllers and Services are handled separately. In CacheAspectSupport.execute() there is a for() loop that will call cachePutRequest.apply(result.get());, which will actually add the entry to the cache. Unfortunately after the entry is added to the request, it is not immediately available to be retrieved. The underlying put() code is part of Spring Source, so at this point I'm not sure if it's a grails plugin issue or a Spring Source issue.
I have created a JIRA issue for this plugin GPCACHEEHCACHE-16

Openrasta: Swap instance in dependency resolver

Suppose I register some instance in OpenRasta's dependency resolver using
resolver.AddDependencyInstance(IInterface, instance, DependencyLifetime.Singleton)
Now if I want to swap that instance later, say to reread fresh data from the db, is another call to resolver.AddDependencyInstance the right thing to do?
Checking the InternalDependencyResolver implementation, it seems to be fine. However I'm asking because the behavior is not defined (in openrasta's sources, where I checked), and the method prefix "Add" is suggestive of different behavior.
I wouldn't use Singleton if you have to swap the instance at some point.
Use DependencyLifetime.Transient and have a constructor injection in the class where you need the new instance

Using resources.groovy to define services

I'm using the resources.groovy to declare a service e.g.
aService(com.foo.OrganizationService)
so that I can tie aService to my controllers instead of using organizationService which could change in the future.
I've noticed that the OrganizationService doesn't get treated special like other services "not" declared in the resources.groovy. For example it doesn't get injected with grailsApplication, and likely a hibernateSession etc and other things I've not hit yet....
Now, I know I can manually wire in stuff to my service but I'd rather not have to maintain that...
Is there a special way to declare a service in the resources.groovy so that gets treated like another service that grails loads up?
TIA
The short answer to your question is "no".
Under the covers, Grails services are driven by some intelligent code that is referencing a specific location and expecting certain properties.
Viewing the source code (especially around the ServicesGrailsPlugin.groovy) is a good way to see the "magic" in how these are wired together.
Is there a reason you wouldn't want to use a bonafide Grails service to solve your problem? If you are expecting things like a grailsApplication, it seems like that use is pretty specific to Grails and would be a good candidate for porting over to a "true" Grails service.
Good luck!
So I've come full circle on this. This is a timing problem. Where services haven't been grails initialized yet.
Basically when you use the resources.groovy to do service wiring you run the risk of using a Service that might initialize itself e.g. afterPropertiesSet method or static initializers that use grails services (log, hibernate session, ..) that haven't been injected yet.
So... What I've turned to instead is to create my own BeanBuilder in a BootStrap.groovy file.
BeanBuilder builder = new BeanBuilder(grailsApplication.parentContext)
def bb = builder.beans {
LoginListener(com.foo.LoginListener) {
springSecurityService = ref("springSecurityService")
userService = ref("userService")
}
}
bb.registerBeans(grailsApplication.mainContext)

Resources