New action in Grails controller errors out - grails

I'm new to groovy & grails so this may be silly.
But I have a very simple hello world app, the index action works fine, but I tried to add a new action ok and it errors out when rebuilding.
My controller is very simple
class AggregatorController {
def index() {
render "hello world 2222"
}
def ok() {
render "no"
}
}
This is the error I get:
org.grails.core.exceptions.GrailsRuntimeException: Error instantiated artefact class [class nba.AggregatorController] of type [class org.grails.core.DefaultGrailsControllerClass]: InvocationTargetException
And inside of the traceback I see this:
Caused by: java.lang.NoSuchMethodError: nba.AggregatorController.ok()Ljava/lang/Object;
If I delete the ok method everything works great

Related

#Transactional not applied to all controller actions

We notices after the update from Grails 3.1.11 to 3.2.0 that one action of a controller is no longer working:
#Transactional(readOnly = true)
class RoomPlanController {
...
def show(RoomPlan roomPlan) {
...
}
def getRooms(RoomPlan roomPlan) {
...
}
}
The problem is that when we call roomPlan/getRooms/1 roomPlan is null. If we call the show action with the same parameter roomPlan is set correct.
A call of getErrors() inside the controller gives us the following error message:
Could not obtain current Hibernate Session; nested exception is org.hibernate.HibernateException: No Session found for current thread
which has it's origin from grails.artefact.Controller.initializeCommandObject. After some more debugging I noticed a difference in the stacktrace between show and getRooms
Stacktrace of show:
show:100, RoomPlanController (at.byte_code.businessSuite.hotel)
$tt__show:-1, RoomPlanController (at.byte_code.businessSuite.hotel)
doCall:-1, RoomPlanController$_show_closure13 (at.byte_code.businessSuite.hotel)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
Stacktrace of getRooms:
getRooms:109, RoomPlanController (at.byte_code.businessSuite.hotel)
getRooms:-1, RoomPlanController (at.byte_code.businessSuite.hotel)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
The error message and the different stacktrace let us assume it has something to do with the database session/transaction and after adding #Transactional(readOnly = true) to the action everything work as expected and before the update to grails 3.2.0. If we remove the annotation and fails again.
We were not able see the issue in any other controller and were not able to reproduce it in a small test project. We already tried to rebuild the project, also on a completely new workstation we were not.
Did anybody else observed such an issue?
I don't think you would even need #Transactional(readOnly = true) in controller.
Grails controllers are by default readOnly. You can simply delete the annotation from the controller.
In contrast, Grails service class are transactional by default. If you need to call the save() method, it's more desirable to call that method in the service class.

Codeception injection fails using page object

I'm new to Codeception, but I'm running into an issue injecting Page Objects. The problem occurs when I add the following construct logic to my page object.
public function __construct(\AcceptanceTester $I) {
$this->tester = $I;
}
... I got this from Login Page object example here: http://codeception.com/docs/06-ReusingTestCode#PageObjects
The error I'm getting is:
[Codeception\Exception\InjectionException]
Failed to inject dependencies in instance of 'MyCest'. Failed to create instance of 'Page\Login'. Failed to create instance of 'AcceptanceTester'. Failed to create instance of 'Codeception\Scenario'. Failed to resolve dependency 'Codeception\TestCase'.
This is how I'm injecting the page in my Cest.
protected function _inject(\Page\Login $login) {
$this->login_page = $login;
}
If I remove the __construct code, the error goes away. Is this a bug in Codeception or am I doing something wrong?
This is the work-around I found...
use \AcceptanceTester;
use Page\Login as LoginPage;
class MyCest {
protected $login_page;
public function _before(AcceptanceTester $I) {
$this->login_page = new LoginPage($I);
}
}
It is expected behaviour.
Your LoginPage constructor should not have any arguments to be instantiated during DI, so your workaround is right way to initialize LoginPage instance with AcceptanceTester instance.
When you specify AcceptanceTester as LoginPage's ctor arg DI mechanism of Codeception tries resolve dependencies recursively in the following way:
LoginPage(AcceptanceTester) -> AcceptanceTester(Scenario) -> Scenario(TestCase) -> TestCase
but TestCase is abstract class so it can not be instantiated.

Exception handling with dynamic mixins in Grails controller

I am using dynamic mixins on my Grails 2.3.11 controllers according to this proposal on SO, for DRY reasons:
class SomeApiController {
def SomeApiController() {
SomeApiController.mixin MyControllerMixin
}
...
Unfortunately it does not work for exception handlers, like:
class MyControllerMixin {
...
def businessException( BusinessException e ) {
log.error( "API exception: ${e.message} ${e.errorCode}", e )
def result = [
status: 'Failure',
errorCode: e.errorCode.name()
]
response.status = 400
render result as JSON
}
...
}
In this case, the default exception handler in SomeApiController is called when a BusinessException is thrown from somewhere. It works nicely if I place the handler directly in the controller, though, but this is what I want to avoid obviously.
Is there any workaround to get that working as well?
See http://grails.org/doc/latest/guide/theWebLayer.html#controllerExceptionHandling. That includes the following...
Exception handler methods must be present at compile time.
Specifically, exception handler methods which are runtime
metaprogrammed onto a controller class are not supported.

NullPointerException for Service-in-Service Injection during test-app

Recently came across with a weird scenario, that dependency injection for a service within a service, threw NPE while running test-app
Reason for service-in-service injection is to make the GORM/criteriaBuilder as DRY as possible. So following are my two services.
Following class SearchService1.groovy is implemented to provide search capability.
class SearchService1{
def search = { ...//Calls to local closures to build a dynamic criteria }
...
}
Class SearchService2.groovy uses the search closure of SearchService1 class
class SearchService2{
def searchService1
...
def searchEntity(){
searchService1.search()
}
}
Now, the above stated code works pretty well in run-app mode.
But for Integration test written for SearchService2 throws NPE as follows :
Cannot invoke method searchEntity() on null object
java.lang.NullPointerException: Cannot invoke method search() on null object
at com.myapp.service.SearchService2.searchEntity(SearchService2.groovy:326)
at com.myapp.service.SearchService2$searchEntity$0.callCurrent(Unknown Source)
at com.myapp.service.SearchService2.searchEntity(SearchService2.groovy:295)
at com.myapp.service.SearchService2$searchEntity.call(Unknown Source)
at com.myapp.integration.SearchService2Tests.testWhenSearch(SearchService2Tests.groovy:125)
Am I missing something very basic here ? Any thoughts are greatly appreciated. Many Thnx :)
Snippet from TestClass :
class SearchService2Tests extends GroovyTestCase{
...
def searchService2
...
void testWhenSearch(){
def resultSet = searchService2.searchEntity() //This is the line throwing NPE
...
}
}
Woah ! Got rid of this stupid error by this workaround.
To TestClass, inject the searchService1 to searchService2 object like this :
def searchService2
def searchService2.searchService1 = new SearchService1()
But come on ! Is this the right way to do it ? Can anyone explain the above error by the way, that why a Service-in-Service is not instantiated while running test-app.
try this:
class SearchService2Tests extends GroovyTestCase {
...
def searchService1
def searchService2
...
void testWhenSearch(){
def resultSet = searchService2.searchEntity()
...
}
}
but use standard Grails service naming convention and placement

How to do safe inserts using GORM for Mongo's low-level API?

I am trying to do a safe insert using GORM for Mongo's low-level API.
I have reproduced the problem in a clean Grails project like follows:
Create a new Grails project
Uninstall the Hibernate plugin
Install the GORM for Mongo plugin
Create a controller with the following action
import com.mongodb.*
class TestController {
def mongo
def index = {
def database = mongo.getDB("ExampleDatabase")
def collection = database.getCollection("ExampleCollection")
def document = new BasicDBObject();
document.put("key", "value")
collection.insert(document, WriteConcern.SAFE)
render ""
}
}
When firing the action, the following exception is thrown:
2011-07-27 12:53:03,161 [http-8080-1] ERROR errors.GrailsExceptionResolver - Exception occurred when processing request: [GET] /WriteConcern.SAFE-test/test/index
Stacktrace follows:
groovy.lang.MissingPropertyException: No such property: value for class: com.mongodb.WriteConcern
at com.gmongo.internal.Patcher$__converAllCharSeqToString_closure2.doCall(Patcher.groovy:81)
at com.gmongo.internal.Patcher._converAllCharSeqToString(Patcher.groovy:80)
at com.gmongo.internal.Patcher$_converAllCharSeqToString.callStatic(Unknown Source)
at com.gmongo.internal.Patcher$_converAllCharSeqToString.callStatic(Unknown Source)
at com.gmongo.internal.Patcher._convert(Patcher.groovy:69)
at com.gmongo.internal.Patcher$_convert.callStatic(Unknown Source)
at com.gmongo.internal.Patcher$__patchInternal_closure1.doCall(Patcher.groovy:31)
at writeconcern.safe.test.TestController$_closure1.doCall(TestController.groovy:17)
at writeconcern.safe.test.TestController$_closure1.doCall(TestController.groovy)
at java.lang.Thread.run(Thread.java:680)
If I change the action to use the Mongo Java API as follows:
def index = {
def database = new Mongo().getDB("ExampleDatabase")
def collection = database.getCollection("ExampleCollection")
def document = new BasicDBObject();
document.put("key", "value")
collection.insert(document, WriteConcern.SAFE)
render ""
}
Now it works and the document is persisted to the Mongo database as expected.
My question is this: Is this a bug with the GMongo wrapper, or then how should safe writes be done using the low level API?
This appears due to the GMongo library and how it patches the DBCollection object to handle passing of Map objects to the insert method and converts them. It assumes that all of the arguments of the insert method are Map objects and will then try to get the value property from the Map.Entry.
Looking at the source of Patcher.groovy from GMongo library you'll see the function _convert() that attempts to do this. It looks like a fork of the Github project with type check on the argument (either to see if it's a WriteConcern or to check if it's actually a Map before passing to the _converAllCharSeqToString) is necessary.
EDIT:
I created a pull request on Github for the appropriate code change, but as with all things Groovy, patching the class can also help. You can "patch" the WriteConcern class in your BootStrap.groovy to have a getValue method and that will allow you to pass the parameter in:
def init = { servletContext ->
com.mongodb.WriteConcern.metaClass.getValue = { null }
}

Resources