Controller inheritance in grails 2.2 - grails

I have some code that I am trying to port from Grails 1.3.7 to Grails 2.2.
The current problem is that I have an BaseController class that defines some convenience methods, and specific controllers (ones actually instantiated by Grails) that inherit from it.
package com.fxpal.querium
import grails.converters.JSON
import groovy.lang.Closure;
abstract class BaseController {
protected def executeSafely(Closure c) {
def resp = null
try {
populateContext();
resp = c()
}
catch(Exception ex) {
resp = [error: ex.message]
ex.printStackTrace()
}
def json = resp as JSON
return json
}
protected void populateContext() {
}
}
An example of a derived class is
package com.fxpal.querium
import grails.converters.JSON
import grails.plugins.springsecurity.Secured
import javax.servlet.http.HttpServletResponse
#Secured(['IS_AUTHENTICATED_REMEMBERED'])
class DocumentController extends BaseController {
def grailsApplication
#Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
def getText = {
try {
String text = new URL(grailsApplication.config.querium.docurl + params.paperId).text
render contentType: 'text/plain', text: text
}
catch(Exception ex) {
render contentType: 'text/plain', text: "Error loading document: ${ex.getMessage()}; please retry"
}
}
...
}
This worked in Grails 1.3.7. When I try to compile my app with Grails 2.2, I get the following error:
C:\code\querium\AppServer-grails-2\grails-app\controllers\com\fxpal\querium\DocumentController.groovy: -1: The return ty
pe of java.lang.Object getGrailsApplication() in com.fxpal.querium.DocumentController is incompatible with org.codehaus.
groovy.grails.commons.GrailsApplication getGrailsApplication() in com.fxpal.querium.BaseController
. At [-1:-1] # line -1, column -1.
Is this pattern no longer supported? I tried adding abstract to be BaseController declaration (it wasn't necessary in Grails 1.3.7), but that didn't seem to make any difference. I compiled my code after a clean, if that matters.
PS: To those who can: please create a grails-2.2 tag

Remove def grailsApplication - the field is already added to the class bytecode via an AST transformation as a typed field (GrailsApplication) so your def field creates a second get/set pair with a weaker type (Object).

Related

How to mock service in groovy/src class under test with Grails 3.3.x

I've recently upgraded to grails 3.3.1 and realised that grails.test.mixin.Mock has been pulled to separate project which has been build just for backward compatibility according to my understanding org.grails:grails-test-mixins:3.3.0.
I've been using #Mock annotation to mock Grails service injected into groovy/src class under test. What is the tactic to mock collaborating services in this case? Is there anything from Spock what I can use or should I fallback to grails-test-mixins plugin?
Class under test:
import gra
ils.util.Holders
import grails.util.Holders
class SomeUtilClass {
static MyService myService = Holders.grailsApplication.mainContext.getBean("myService")
static String myMethod() {
// here is some code
return myService.myServiceMethod()
}
}
My test spec (Grails 3.2.1):
import grails.test.mixin.Mock
import spock.lang.Specification
#Mock([MyService])
class ValidatorUtilsTest extends Specification {
def 'my test'() {
when:
def result = SomeUtilClass.myMethod()
then:
result == "result"
}
}
Due to you use Holders.grailsApplication in your SomeUtilClass, you can try to add #Integration annotation:
import grails.testing.mixin.integration.Integration
import spock.lang.Specification
#Integration
class ValidatorUtilsTest extends Specification {
def 'my test'() {
when:
def result = SomeUtilClass.myMethod()
then:
result == "result"
}
}
Not sure, but hope it work for you.
Try with this code
#TestMixin(GrailsUnitTestMixin)
#Mock([your domains here])
class ValidatorUtilsTest extends Specification {
static doWithSpring = {
myService(MyService)
}
def 'my test'() {
when:
def result = SomeUtilClass.myMethod()
then:
result == "result"
}
}
Remove the #Mock annotation and implement ServiceUnitTest<MyService> in your test class.

Register HoverProvider with Xtend

I try to implement a custom HoverProvider according to this tutorial: enter link description here
However, I'm stuck translating to Java code of MyDSLUiModuleto Xtend.
The register-method should read like this:
def Class<? extends IEObjectDocumentationProvider> bindIEObjectDocumentationProviderr() {
return MyDSLHoverProvider.class
}
However, this doesn't compile since MyDSLHoverProvider only implements the IEObjectDocumentationProvider but not extend this class (MyDSLHoverProvider is the same as in the tutorial).
Therefore this error is thrown:
Type mismatch: cannot convert from Class<? extends Class> to Class<? extends IEObjectDocumentationProvider>
How can I get around this error?
Btw: If I test my DSL in an Eclipse instance, I get a wierd NPE:
!ENTRY org.eclipse.oomph.setup.ui 2 0 2016-09-16 16:42:34.203
!MESSAGE java.lang.NullPointerException
!STACK 0
java.lang.NullPointerException
at org.eclipse.oomph.setup.ui.SetupUIPlugin.performStartup(SetupUIPlugin.java:373)
at org.eclipse.oomph.setup.ui.SetupUIPlugin.access$4(SetupUIPlugin.java:344)
at org.eclipse.oomph.setup.ui.SetupUIPlugin$1$1.run(SetupUIPlugin.java:241)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
I have no clue where this exception comes from.
The class MyDSLHoverProvider looks like this:
import org.eclipse.emf.ecore.EObject
import org.eclipse.xtext.documentation.IEObjectDocumentationProvider
class MyDSLHoverProvider implements IEObjectDocumentationProvider {
override getDocumentation(EObject o) {
println("Hover: " + o)
if (o instanceof MyFieldElements) {
return "This is a nice Greeting with nice <b>markup</b> in the <i>documentation</i>";
}
}
}
Edit:
I found a way to display the tooltips, but it seems strange.
A tooltip is shown for this rule:
name = ID
but if I rename it to
myField = ID
the tooltip is not triggered.
Is this the expected behaviour?
the correct Xtend syntax is
def Class<? extends IEObjectDocumentationProvider> bindIEObjectDocumentationProviderr() {
return MyDSLHoverProvider
}
or
def Class<? extends IEObjectDocumentationProvider> bindIEObjectDocumentationProviderr() {
MyDSLHoverProvider
}
MyDSLHoverProvider.classis the same as MyDslHoverProvider.class.getClass() in Java

How to wrap all Grails service methods with a Groovy closure?

Grails 2.4.x here.
I have a requirement that all the methods of all my Grails services, generated by grails create-service <xyz>, be "wrapped"/intercepted with the following logic:
try {
executeTheMethod()
} catch(MyAppException maExc) {
log.error(ExceptionUtils.getStackTrace(maExc))
myAppExceptionHandler.handleOrRethrow(maExc)
}
Where:
log.error(...) is the SLF4J-provided logger you get when you annotate your class with the #Slf4j annotation; and
ExceptionUtils is the one from org.apache.commons:commons-lang3:3.4; and
myAppExceptionHandler is of type com.example.myapp.MyAppExceptionHandler; and
This behavior exists (or has the option to exist in the event that it needs to be explicitly called somehow) for each method defined in a Grails service
So obviously this wrapper code needs to include import statements for those classes as well.
So for example if I have a WidgetService that looks like this:
class WidgetService {
WidgetDataService widgetDataService = new WidgetDataService()
Widget getWidgetById(Long widgetId) {
List<Widget> widgets = widgetDataService.getAllWidgets()
widgets.each {
if(it.id.equals(widgetId)) {
return it
}
}
return null
}
}
Then after this Groovy/Grails/closure magic occurs I need the code to behave as if I had written it like:
import groovy.util.logging.Slf4j
import org.apache.commons.lang3.exception.ExceptionUtils
import com.example.myapp.MyAppExceptionHandler
#Slf4j
class WidgetService {
WidgetDataService widgetDataService = new WidgetDataService()
MyAppExceptionHandler myAppExceptionHandler = new MyAppExceptionHandler()
Widget getWidgetById(Long widgetId) {
try {
List<Widget> widgets = widgetDataService.getAllWidgets()
widgets.each {
if(it.id.equals(widgetId)) {
return it
}
}
return null
} catch(MyAppException maExc) {
log.error(ExceptionUtils.getStackTrace(maExc))
myAppExceptionHandler.handleOrRethrow(maExc)
}
}
}
Any ideas as to how I might be able to achieve this? I'm worried that a pure Groovy closure might interfere somehow with whatever Grails is doing to its services under the hood at runtime (since they are all classes that don't explicitly extend a parent class).
Here is what I was trying to pin point in my comment:
package com.example
import groovy.util.logging.Log4j
#Log4j
trait SomeTrait {
def withErrorHandler(Closure clos) {
try {
clos()
} catch(Exception e) {
log.error e.message
throw new ApplicationSpecificException(
"Application Specific Message: ${e.message}"
)
}
}
}
Service class:
package com.example
class SampleService implements SomeTrait {
def throwingException() {
withErrorHandler {
throw new Exception("I am an exception")
}
}
def notThrowingException() {
withErrorHandler {
println "foo bar"
}
}
}
Test:
package com.example
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(SampleService)
class SampleServiceSpec extends Specification {
void "test something"() {
when:
service.throwingException()
then:
ApplicationSpecificException e = thrown(ApplicationSpecificException)
e.message == "Application Specific Message: I am an exception"
}
void "test something again"() {
when:
service.notThrowingException()
then:
notThrown(Exception)
}
}
Here is the sample app.
Grails 3.0.9 but it should not matter. this is applicable for Grails 2.4.*
You can intercept the calls to your Service class methods either using MetaInjection or Spring AOP. So you don't have to write closure in each Service class. You can look into this blog that explains both the approaches with examples.

Where to put a xsl file in Grails, and how to get the path

I need to pass my xsl and read file on the service to generate pdf. i always get an error meesage something like
Document is empty (something might be wrong with your XSLT stylesheet).. Stacktrace follows:
Message: Document is empty (something might be wrong with your XSLT stylesheet).
i also autowire the file on the bean resource.xml or resource.groovy
class MyClassHolder{
Resource template
}
//in my controller
class MyController{
method(){
File resource = classHolder.template.file
def reader = new FileReader(resource)
myservice.convert(reader)
}
}
Whenever I required to put some file and read content from that file I create a directory e.g. resources in the web-app directory and read content in service like:
import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH
class MyService {
def readFile() {
def servletContext = SCH.servletContext
def file = servletContext.getResource('/resources/example.xsl').getContent()
println "Content = ${file}"
}
}
If you put it in the web-app folder, and you are using Grails 2, you can use the Grails Resource Locator.
class MyService {
def grailsResourceLocator
def templateResource
#PostConstruct
init() {
templateResource = grailsResourceLocator.findResourceForURI('/resources/example.xsl')
}
def convert() {
// no need to pass in resource or filereader, can use file or inputStream
def templateFile = templateResource.file
def templateStream = templateResource.inputStream
}
}
class MyController {
MyService myService
method() {
myService.convert()
}
}
Handy tip: to mock this in Spock, use GroovyPageStaticResourceLoader
#TestFor(MyService)
class MyServiceSpec extends Specification {
def setup() {
service.grailsResourceLocator = Mock(GroovyPageStaticResourceLocator)
}
}

Mock testing in Grails 2.0 errors

I've recently upgraded a Grails 1.3.7 project up to Grails 2.0.4 and noticed that many of my unit tests with mocking have started to fail. The Controller tests seem to pass just fine, the issue comes when you have Services collaborating with one another and try to mock out the calls to the collaborators. The strange part about it is if I run the single test, it passes, but as soon as I run the entire suite, they fail giving the error:
No more calls to 'getName' expected at this point. End of demands.
junit.framework.AssertionFailedError: No more calls to 'getName' expected at this point. End of demands.
I've even tried using GMock instead of new MockFor(), but get this very similar error:
No more calls to 'getSimpleName' expected at this point. End of demands.
junit.framework.AssertionFailedError: No more calls to 'getSimpleName' expected at this point. End of demands.
Here's a contrived example showing how to duplicate the errors I'm getting, and the entire sample project on GitHub at https://github.com/punkisdead/FunWithMocks. Any ideas of how to make this work?
BarController:
package funwithmocks
class BarController {
def barService
def fooService
def index() { }
}
BarService:
package funwithmocks
class BarService {
def fooService
def bazService
def serviceMethod() {
}
}
BarControllerTests:
package funwithmocks
import grails.test.mixin.*
import org.junit.*
import groovy.mock.interceptor.MockFor
/**
* See the API for {#link grails.test.mixin.web.ControllerUnitTestMixin} for usage instructions
*/
#TestFor(BarController)
class BarControllerTests {
def fooService
def barService
#Before
public void setUp() {
fooService = new MockFor(FooService)
fooService.use {
controller.fooService = new FooService()
}
barService = new MockFor(BarService)
barService.use {
controller.barService = new BarService()
}
}
#Test
void doSomething() {
controller.index()
}
}
BarServiceTests:
package funwithmocks
import grails.test.mixin.*
import org.junit.*
import groovy.mock.interceptor.MockFor
/**
* See the API for {#link grails.test.mixin.services.ServiceUnitTestMixin} for usage instructions
*/
#TestFor(BarService)
class BarServiceTests {
def fooService
def bazService
#Before
public void setUp() {
fooService = new MockFor(FooService)
fooService.use {
service.fooService = new FooService()
}
bazService = new MockFor(BazService)
bazService.use {
service.bazService = new BazService()
}
}
#Test
void callSomeService() {
service.serviceMethod()
}
}
You shouldn't to combine the new test mixin with MockFor groovy class. Replace all MockFor instance with the mockFor method.
http://grails.org/doc/latest/guide/testing.html#mockingCollaborators

Resources