I'm creating a Grails (3.3.9) plugin to hold shared back-end code for some internal applications. For some reason, when I run the plugin to test it, my service is not being injected into my controller.
I've started with the default web-plugin profile, created a single domain class called Entry, and run generate-all to create a controller, service, and views. When I try to run my plugin as an application and view a single domain instance, I get the following error:
Cannot invoke method get() on null object. Stacktrace follows:
java.lang.reflect.InvocationTargetException: null
at org.grails.core.DefaultGrailsControllerClass$ReflectionInvoker.invoke(DefaultGrailsControllerClass.java:211)
at org.grails.core.DefaultGrailsControllerClass.invoke(DefaultGrailsControllerClass.java:188)
at org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter.handle(UrlMappingsInfoHandlerAdapter.groovy:90)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException: Cannot invoke method get() on null object
at com.mycompany.internal.EntryController.show(EntryController.groovy:18)
... 14 common frames omitted
The stacktrace takes me to line 18 in my controller:
def show(Long id) {
respond entryService.get(id)
}
This suggests to me that entryService is null.
My domain class looks like this:
class Entry {
String entryCode
String description
}
The controller is as follows:
class EntryController {
EntryService entryService
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond entryService.list(params), model:[entryCount: entryService.count()]
}
def show(Long id) {
respond entryService.get(id)
}
//snipped for brevity
And the service looks like this:
#Service(Entry)
interface EntryService {
Entry get(Serializable id)
//snipped for brevity
}
Based on the Grails plugin documentation, I would expect to be able to run the plugin standalone like any other application, and in normal applications, defining the service as an interface works fine. If I install this plugin to my local maven cache and use it in an application, it works exactly as I would expect; I am able to hit the controller's show endpoint and get back a result from my database.
At one point I tried implementing the service as a class rather than having it be an interface, but then I receive this error:
URI
/entry/index
Class
java.lang.IllegalStateException
Message
null
Caused by
Either class [com.mycompany.internal.Entry] is not a domain class or GORM has not been initialized correctly or has already been shutdown. Ensure GORM is loaded and configured correctly before calling any methods on a GORM entity.
What am I missing about how to set up and run a Grails plugin correctly?
Finally found an answer by digging into the GORM issue: class Authority is not a domain class or GORM has not been initialized correctly or has already been shutdown
Apparently the root of the problem was the need to add compile "org.grails.plugins:hibernate5" to my dependencies block in build.gradle. The weird thing is that the web-plugin profile provides the create-domain-class command, so I would think GORM and Hibernate support would be included by default, but I'm apparently misunderstanding some aspects of how plugins are supposed to work.
Related
SpringSecurity's #PreAuthorize and #PostAuthorize is ignored when unit testing with MockMvc. But it's OK when access by browser of Postman while normally started the application
I am using Spring 4.3 and Spring security 4.2, not the spring boot. I am using MockMvcBuilders.standaloneSetup to test the controller only. and don't want to use webAppContextSetup to involve the entire application to test.
After check the spring security's source code, I found that the Pre and PostAuthorize is checking by org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice and org.springframework.security.access.expression.method.ExpressionBasedPostInvocationAdvice. But the controller is not include by org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource.
I think this is caused by the controller is not initialized by Spring, so I try to register it to the BeanFactory, but it also fail.
Testing code:
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mockMvc = standaloneSetup(controllers)
.setValidator(validator)
.apply(springSecurity(filterChainProxy))
.alwaysDo(print())
.build();
}
public void itWillFailWhenUpdateOtherOrg() {
CurrentUser user = new CurrentUser();
user.setOrgId(1);
user.setUsername("testuser");
mockMvc.perform(put("/orgs/-1")
.contentType(APPLICATION_JSON)
.content("{\"name\":\"RootOrg\",\"parent\":100}")
.with(user(user))).andExpect(status().isForbidden());
verify(orgService, never()).update(any());
}
Controller code:
#PutMapping("/org/{id}")
#PreAuthorize("principal.orgId == #orgDO.parent")
public OrgDO update(#PathVariable Integer id, #RequestBody OrgDO orgDO) {
}
When testing, the status code is 200, but not 403.
java.lang.AssertionError: Status
Expected :403
Actual :200
I expect the put request will fail and return status code 403, because of the principal.orgId != #orgDO.parent.
Be sure to NOT include all class to the Spring context, I just want to test the controller class.
Thank you very much.
After few hours of digging here is why:
MockMvcBuilders.standaloneSetup normally get passed a controller instantiated manually (not with Spring and therefore not with AOP). Therefore the PreAuthorize is not intercepted and security check is skipped. You can therefore either #Autowire your controller and pass it to MockMvcBuilders.standaloneSetup (which maybe kind of defies the purpose of using standalone setup since it's alos create the rest controller...) or simply use a WebApplicationContext: MockMvcBuilders.webAppContextSetup with an autowired WepAppContext.
As per the grails 3.1.13 guide I am trying to add service dependency to my controller, but somehow it is not working for me. It is throwing NullPointerException for Cannot get property 'serviceMethod' on null object. Below I am mentioning the steps to reproduce.
Execute following commands
grails create-app DepInjectionTest
grails create-controller com.abc.project.KpiReport
grails create-service com.abc.project.KpiReport
Above creates below directory structure
KpiReportService
#Transactional
class KpiReportService {
def serviceMethod() {
return "Hello from KpiReportService"
}
}
KpiReportController
class KpiReportController {
def index() {
def kpiReportService
render kpiReportService.serviceMethod
//render "Hello from KpiReportController"
}
}
Exception
Grails application running at http://localhost:8080 in environment: development
ERROR org.grails.web.errors.GrailsExceptionResolver - NullPointerException occurred when processing request: [POST] /KpiReport/index
Cannot get property 'serviceMethod' on null object. Stacktrace follows:
java.lang.reflect.InvocationTargetException: null
at org.grails.core.DefaultGrailsControllerClass$ReflectionInvoker.invoke(DefaultGrailsControllerClass.java:210)
at org.grails.core.DefaultGrailsControllerClass.invoke(DefaultGrailsControllerClass.java:187)
at org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter.handle(UrlMappingsInfoHandlerAdapter.groovy:90)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:961)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:895)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException: Cannot get property 'serviceMethod' on null object
at com.abc.project.KpiReportController.index(KpiReportController.groovy:7)
... 13 common frames omitted
Using postman for request
I am new to grails, please help me figure out what is going wrong, may be I am missing something.
The error message indicates you are referring to a property that does not exist. Instead of render kpiReportService.serviceMethod you want render kpiReportService.serviceMethod().
Services are injected as class variables
class KpiReportController {
def kpiReportService
def index() {
render kpiReportService.serviceMethod()
//render "Hello from KpiReportController"
}
}
I´ve got some weird behaviour using Grails 2.2.4, SpringSecurityCore 2.0 RC in Production on a Tomcat 7 with Groovy Compiler 2.0.8, Java 1.7.0.
We build a plugin which realize basic behaviors. We included the SpringSecurityCore plugin in it with a person class named User. There are some domain classes in the basic plugin which got User fields.
Then we build an application which include our basic plugin. The application got a special application person class called RUser which extend from User. RUser is set to SpringSecurityCore as person class.
Problem:
The application runs about 1 to 3 days without errors, but then ClassCastExceptions are thrown trying to set a RUser object on a User field of a plugin domain class.
User classes:
Plugin User class:
class User implements Serializable {
transient springSecurityService
String username
String password
...
}
Application User class:
class RUser extends User implements Serializable{
Cart cart
boolean businessUser = false
boolean taxIncluded = false
...
}
Application Config.groovy:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'RUser'
Participated classes of our basic plugin:
class UserRole implements Serializable {
User user
Role role
static UserRole create(User user, Role role, boolean flush = false) {
new UserRole(user: user, role: role).save(flush: flush, insert: true)
}
...
}
class UserHistory implements Serializable{
User user
List historyEntries
static hasMany = [historyEntries:HistoryEntry]
...
}
The errors occur in this example situations:
In a Filter:
54: UserHistory.withTransaction{
def currentUser =springSecurityService.currentUser
def history = UserHistory.findByUser(currentUser)
if(!history){
96: history = new UserHistory(user:user).save(flush:true)
}
}
2014-05-23 13:52:17,279 ERROR errors.GrailsExceptionResolver| IllegalArgumentException occurred when processing request: [GET] /index
java.lang.ClassCastException#7ff92284. Stacktrace follows:
java.lang.reflect.UndeclaredThrowableException
at org.grails.datastore.gorm.GormStaticApi.withTransaction(GormStaticApi.groovy:687)
at de.neomatt.history.HistoryFilters$_closure1_closure2_closure4.doCall(HistoryFilters.groovy:54)
at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53)
at grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:49)
at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:82)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.reflect.InvocationTargetException
at de.neomatt.history.HistoryFilters$_closure1_closure2_closure4_closure5.doCall(HistoryFilters.groovy:96)
... 10 more
Caused by: org.springframework.beans.MethodInvocationException: Property 'springSecurityService' threw exception; nested exception is java.lang.IllegalArgumentException: java.lang.ClassCastException#7ff92284
at java.lang.Class.newInstance0(Class.java:372)
at java.lang.Class.newInstance(Class.java:325)
... 11 more
Caused by: java.lang.IllegalArgumentException: java.lang.ClassCastException#7ff92284
... 13 more
2014-05-23 13:52:17,288 ERROR errors.GrailsExceptionResolver| IllegalArgumentException occurred when processing request: [GET] /reservation_demo/ToolsOne
Method name must not be null. Stacktrace follows:
java.lang.IllegalArgumentException: Method name must not be null
at grails.plugin.cache.web.ProxyAwareMixedGrailsControllerHelper.retrieveAction(ProxyAwareMixedGrailsControllerHelper.java:41)
at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53)
at grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:49)
at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:82)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
In a Controller:
RegistrationCode.withTransaction {
def user = lookupUserClass().findByUsername(registrationCode.username)
def role = Role.findByAuthority(roleName)
281: UserRole.create user, role
}
2014-05-26 13:02:24,780 ERROR errors.GrailsExceptionResolver| IllegalArgumentException occurred when processing request: [GET] /app/register/verifyRegistration
java.lang.ClassCastException#a7c83d. Stacktrace follows:
java.lang.IllegalArgumentException: java.lang.ClassCastException#a7c83d
at java.lang.Class.newInstance0(Class.java:372)
at java.lang.Class.newInstance(Class.java:325)
at de.neomatt.security.UserRole.create(UserRole.groovy:32)
at de.neomatt.security.RegisterController$_closure4_closure14.doCall(RegisterController.groovy:281)
at org.grails.datastore.gorm.GormStaticApi.withTransaction(GormStaticApi.groovy:687)
at de.neomatt.security.RegisterController$_closure4.doCall(RegisterController.groovy:271)
at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:195)
at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53)
at grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:49)
at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:82)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
The ClassCastExceptions occurs everywhere, where an object with type RUser is setted on a User field. The RUser object is retrieved from springSecurityService.currentUser or with the lookupUserClass().findBy(...) method.
protected Class<?> lookupUserClass() {
grailsApplication.getDomainClass(lookupUserClassName()).clazz
}
As mentioned before, the application runs without errors for a undefined period of time in a production environment (no reloading, no config changes). A new deployment of the same war solves the problem for the next few hours/days.
Any suggestions?
#neomatt
I've deployed my grails application on weblogic server. The front end is grails and backend is using spring and hibernate (not using gorm).
I am seeing the following error when I try to access a static dummy page:
<Dec 11, 2011 5:15:02 AM EST> <Error> <HTTP> <BEA-101362> <[ServletContext#450252357[app: spec-version:2.5]] could not deserialize the request scoped attribute with name: "userService"
java.io.NotSerializableException: org.codehaus.groovy.grails.commons.spring.ReloadAwareAutowireCapableBeanFactory
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
at org.springframework.transaction.interceptor.TransactionInterceptor.writeObject(TransactionInterceptor.java:186)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Truncated. see log file for complete stacktrace
><[ServletContext#450252357[app: spec-version:2.5]] could not deserialize the request scoped attribute with name: "referenceDataService"
java.io.NotSerializableException: org.codehaus.groovy.grails.commons.spring.ReloadAwareAutowireCapableBeanFactory
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
at org.springframework.transaction.interceptor.TransactionInterceptor.writeObject(TransactionInterceptor.java:186)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Truncated. see log file for complete stacktrace
>
Here are the action & controller classes:
class UserAdminController {
def messageSource
def userService
def referenceDataService
def manageUsers = {
render(view: "manageUsers")
}
def showCreateUserAdmin = {
//code goes here
}
}
The reason for writing a dummy action is that the user shouldn't call the gsp page using manageUsers.gsp.
How can I fix this issue?
I am trying to use dependency injection for export to excel functionality provided by "Export Plugin"
It seems that whenevery I try to use service in my project i get error like following
Stacktrace follows:
java.lang.NullPointerException: Cannot invoke method export() on null object
at pm.ProjectsController$_closure2.doCall(ProjectsController.groovy:39)
at pm.ProjectsController$_closure2.doCall(ProjectsController.groovy)
at java.lang.Thread.run(Thread.java:662)
The code I am using is following, this just means service variable is null
def exportService// i have tried with and without the initialization
if(params?.format && params.format != "html"){
response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
response.setHeader("Content-disposition", "attachment; filename=books.${params.extension}")
exportService.export(params.format, response.outputStream,projectsList, [:], [:])
}
It seems that no plugin that uses services is working in my project for example AsynchronousMailService in my project didn't work as it was suppose to and thus I have been using it like following
AsynchronousMailService asynchronousMailService = new AsynchronousMailService()
asynchronousMailService.sendAsynchronousMail {
to projectsInstance.projectLead.emailAddress
subject "New project is assigned to you"
html msg
}
Unless I am missing somethig very basic I do not beleive I should be instantiating this class if the plugin offers the same as service.
Thanks
Right, you should never instantiate services or other Spring beans - use dependency injection. It might work, but if the bean has any dependencies of its own they'll be null since you're bypassing Spring.
You're not using dependency injection, you're declaring a local variable and expecting magic.
Dependency injection in Grails uses public fields. Since Groovy creates a public field into a getter and setter under the hood, Spring sees the setter and Grails is configured to inject by name, so as long as the field/setter matches a Spring bean name it works.
So your controller should look something like this:
class MyController {
def exportService
def myAction = {
if (params?.format && params.format != "html") {
response.contentType = grailsApplication.config.grails.mime.types[params.format]
response.setHeader("Content-disposition",
"attachment; filename=books.${params.extension}")
exportService.export(params.format,
response.outputStream,projectsList, [:], [:])
}
}
}
Note that I also removed the use of ConfigurationHolder since it's deprecated. The best way to get access to the config is from the grailsApplication bean. It's already injected in controllers (and taglibs), and in a service or other bean you'd just need a def grailsApplication field declaration.