Grails 4.0.12 and 5.0.1: VERY strange behavior in controller action using enumeration
- Dominant language
- Groovy
- Stars
- 2.9k
- Forks
- 975
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 92
Description
We did upgrade some production application of ours to Grails 4.0.12 from 3.3.x and some specific code suddenly stopped working. I managed to extract a minimal example application with similar code, which produces the exception. I also added some Spock tests which verify the problem. Additionally I also tried with the newest Grails version 5.0.1, but the problem is still present there.
**grails-app/controllers/myapp/TestController.groovy**
```
package myapp
import groovy.util.logging.Slf4j
import myapp.utils.UIState
@Slf4j // works if @Slf4j is removed
class TestController {
// works if parameter name is changed from someState to something else
def something(String someState) {
render 'something'
}
private UIState getUIState() {
// works if variable someState is changed to something else
UIState.SomeState someState = UIState.SomeState.NORMAL
return new UIState(state: someState)
}
}
```
**src/main/groovy/myapp/utils/UIState.groovy**
```
package myapp.utils
import groovy.transform.Immutable
@Immutable
class UIState {
enum SomeState { NORMAL, THING, THINGY }
SomeState state = SomeState.NORMAL
}
```
This produces an `java.lang.IllegalArgumentException: No enum constant myapp.utils.UIState.SomeState.` when I open the URL http://localhost:8080/test/something?someState= inside the browser.
What is very strange in this code is the fact, that when I change only one of the marked lines above (see my comments in the code), the example suddenly starts working. Also I don't understand why in the non-working example some `Enum.valueOf` call seems to happen, but in my very simple controller code the action `something` doesn't utilize the parameter and it is not even an enumeration. Also the private utility method `getUIState` is not invoked at all and why the presence of the `@Slf4j` annotation changes the behavior is very unclear to me.
### Task List
- [x] Steps to reproduce provided
- [x] Stacktrace (if present) provided
- [x] Example that reproduces the problem uploaded to Github
- [x] Full description of the issue provided (see below)
### Steps to Reproduce
1. clone example repository
2. `grails run-app`
3. `curl http://localhost:8080/test/something?someState=`
4. or `./gradlew test`
### Expected Behaviour
I don't see why the given example should not work.
### Actual Behaviour
```
Grails application running at http://localhost:8080 in environment: development
2021-11-22 21:43:37.729 ERROR --- [nio-8080-exec-3] o.g.web.errors.GrailsExceptionResolver : IllegalArgumentException occurred when processing request: [GET] /test/something - parameters:
someState:
No enum constant myapp.utils.UIState.SomeState.. Stacktrace follows:
java.lang.reflect.InvocationTargetException: null
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
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:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.IllegalArgumentException: No enum constant myapp.utils.UIState.SomeState.
at java.base/java.lang.Enum.valueOf(Enum.java:240)
... 15 common frames omitted
```
### Environment Information
- **Operating System**: Windows 11 / Ubuntu 18.04 running in WSL
- **Grails Version:** 4.0.12 / 5.0.1
- **JDK Version:** 11
### Example Application
https://github.com/davidkron/grails-strange-controller-action-problem
Contributor guide
Research direction
Start by running ./gradlew test and reproducing the request against grails-app/controllers/myapp/TestController.groovy with the src/main/groovy/myapp/utils/UIState.groovy model. Compare the behavior with and without @Slf4j and with the alternate parameter or variable names, then trace the controller invocation shown in DefaultGrailsControllerClass. Done means the supplied tests pass and the empty someState request no longer raises the enum exception.
Written by the indexing model from the issue text.
Assessment
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 42/100