Why does inheriting from GroovyTestCase cause Spring errors in Grails 2.2? - spring

The integration test classes generated for me by Grails when I created my domain classes do not extend the class GroovyTestCase. However, I have seen it recommended by many authors (here is an example in order to use the shouldFail method, which indeed seems to work).
However, extending my test class from GroovyTestCase has resulted in the following error message when I run test-app in the interactive Grails console:
Spring Loaded: Cannot reload new version of foo.barTests
Reason: Supertype changed from java/lang/Object to groovy/util/GroovyTestCase
Is this something I should be concerned about? I have searched online and cannot find other people complaining about this error, so it might be something new with Grails 2.2. Please advise.
I am running my tests in the grails interactive console (what you get when you run grails without arguments). I've left my tests inheriting from Object for a while, but when I run test-app I still occasionally get those messages output to the HTML test report (of the "changed from GroovyTestCase to Object" variety).

I am quite sure it's a Grails bug related to
AST Transformation annotations
spring-loaded module
As I've encountered this strange behaviour as well.
The steps that caused this problem seem to be that a Groovy class is compiled once without transformation, so that it's a subclass of java.lang.Object.
When the AST transformaton kicks it, the class is recompiled again. This time, it becomes a subclass of another class. Then Spring-loaded fails to re-load them into the memory (as JVM does not allow the same class to redefine its super class).

Related

Difference Between Spring MockMvcBuilders.standaloneSetup and WebMvcTest

I have a Spring Boot 2.6.0 application that depends on libraries which use fields initialised with SpEL syntax, e.g.
#Value("${some.value.in.library}") aField;
I attempted to write a Spring MVC test for a controller with #WebMvcTest. However I kept getting failed to load applicationcontext errors due to a SpELEvaluationException for the fields mentioned above.
Even after trying many, many, different test annotations such as #ConfigurationProperties and other fixes. I could see the properties that are defined in application-test.yml being loaded in the startup logs but they were not getting injected into the class.
Finally, I tried using:
MockMvcBuilders.standaloneSetup
and the test was able to start and run successfully.
Unfortunately, due to the complexity of the application and the use of a library where the problem occurs, it is difficult to create a minimal reproducable example.
So my question is, why does MockMvcBuilders.standaloneSetup work, whereas #MockMvcTest doesn't?
This answer suggests that #MockMvcTest should not load the full application context. But that does not seem to be the case based on the failed to load applicationcontext errors.

OptaPlanner got java reflection error in Spring boot

I just tried to run an OptaPlanner project in Spring Boot, but there's only very simple text in OptaPlanner User Guide for Spring.
Actually, I think it is very easy to copy all domain objects, configuration files and drools files from an OptaPlanner project to Spring Boot project without any changes, but the only question is how to call Solver's solve method.
I made it run after Spring Boot startup with a class (named CommandLineAppStartupRunner) which implements CommandLineRunner interface, and I called solve method in its run method. Finally, I got an exception like follows:
Caused by: java.lang.IllegalArgumentException: Can not set org.optaplanner.core.api.score.buildin.hardmediumsoft.HardMediumSoftScore field springbootcloudbalance.domain.CloudBalance.score to springbootcloudbalance.domain.CloudBalance
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
at java.lang.reflect.Field.get(Field.java:393)
at org.optaplanner.core.impl.domain.common.accessor.ReflectionFieldMemberAccessor.executeGetter(ReflectionFieldMemberAccessor.java:54)
at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.getScore(SolutionDescriptor.java:1071)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.cloneSolution(AbstractScoreDirector.java:212)
at org.optaplanner.core.impl.solver.scope.DefaultSolverScope.setWorkingSolutionFromBestSolution(DefaultSolverScope.java:230)
at org.optaplanner.core.impl.solver.AbstractSolver.solvingStarted(AbstractSolver.java:75)
at org.optaplanner.core.impl.solver.DefaultSolver.solvingStarted(DefaultSolver.java:210)
at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:190)
at springbootcloudbalance.CommandLineAppStartupRunner.run(CommandLineAppStartupRunner.java:55)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:818)
... 10 common frames omitted
I checked the code, and found the exception throws because the object from field.getDeclaringClass() is a different instance from the one from var1.getClass(). I'm afraid it due to the implementation of java reflection conflicts between OptaPlanner and Spring Boot.
The version I used is as follows:
OptaPlanner 7.11.0.Final
Spring Boot 2.0.5.RELEASE
JVM 1.8.0_181
Removing the spring-boot-devtools dependency fixes this error. Another SO question similar to this one explains it has something to do with different classloaders: Optaplanner's Drools working memory is empty. The accepted answer also mentions a possible fix:
To fix it, configure spring dev tools to load Drools libraries in the RestartClassLoader, together with the project's classes: using-boot-devtools-customizing-classload
Nick's answer is correct. This is just to figure out what's going on.
This line means that optaplanner is extracting CloudBalance.getScore():
at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.getScore(SolutionDescriptor.java:1071)
This line means that it's using a ReflectionFieldMemberAccessor for that, which is just way to read a field through reflection (including private fields):
at org.optaplanner.core.impl.domain.common.accessor.ReflectionFieldMemberAccessor.executeGetter(ReflectionFieldMemberAccessor.java:54)
Now the error message is where it gets interesting:
Can not set ...HardMediumSoftScore field ...CloudBalance.score to ...CloudBalance
It looks like basically doing:
CloudBalance cloudBalance2 = cloudBalance.getScore();
Huh?
Musa provided this answer, but someone deleted it, despite that the JIRA link is extremely relevant, as it points out which version of OptaPlanner will deal better with this problem:
"An issue was submitted to OptaPlanner to provide better error messages for such cases: https://issues.jboss.org/browse/PLANNER-1586. Feel free to add any comments or suggestions."

Maven surefire java 8 with EasyMock yields: java.lang.NoClassDefFoundError: Could not initialize class com.sun.proxy.$Proxy33

I am attempting to upgrade our application to Java 8 and am having some issues with maven and surefire. When I run all of my unit tests, a handful of them fail when using EasyMock.createMock with the following error: java.lang.NoClassDefFoundError: Could not initialize class com.sun.proxy.$Proxy33. Not all instances of EasyMock.createMock fail, and I can't find anything special about the classes we're mocking where it fails. Also, if I run the unit test inside of IntelliJ it works perfectly fine. It's only when running it via maven directly that it fails. I haven't been able to find anything that is causing this, but I'm assuming it has to be some sort of classpath issue. Any help would be greatly appreciated.
That is a strange error. The Proxy33 means you are mocking an interface. And that something failed at class loading.
Check if you have static initializers in your code. You can also add remote debug to maven and break on the exception.

Method on class [com.secure.Role] was used outside of a Grails application

I'm completing doing everything same as described in tutorial at Grail website . However I'm receiving this strange error message :
Method on class [com.secure.Role] was used outside of a Grails application
I've done it in my business computer and personal notebook. I've tried to it with Spring IDE and different grails versions. What's the problem can not understand.
If you are trying to run a unit test without first applying mocking to a domain class then you will get this error.
Also integration tests cannot curerntly be run in an IDE and require use of the command line (some IDEs integrate the command line to run these tests). If you run an integration test from the IDE you will likely get an error like this.

ClassLoader finds Resource only in specific Threads

I am struggling with a situation in which a ClassLoader is trying to resolve a resource, which only works under certain conditions.
The use-case is as follows: I am using IBM Rational Functional Tester in combination with JBehave for automated acceptance tests. JBehave specifies the tests as plain text story files. These story files can refer to other story files, so called "Given Stories". JBehave uses the ExecutorService to execute stories potentially multi-threaded. While JBehave has no problems to load the text files (with ClassLoader.getResourceAsStream), it fails finding the same files in the thread launched from ExecutorService.
The ClassLoader in action is the ContextFinder. When debugging the application, and suspending both threads, the "main thread" that originally started JBehave and the "story thread" launched from the executor service to run the story file, I can identify that the instance of the classloader is the same. Also the instances of the parents, etc.
But a call to
Thread.currentThread().getContextClassLoader().getResource("HelloWorld.story")
works perfectly in the main thread, and fails for the story thread and returns null.
Judging from the source code of the ContextFinder, it seems like it does little else then gathering all the ClassLoaders for the classes on the stack. So I tried this:
SomeClass.class.getClass().getClassLoader().getResource("HelloWorld.story")
... with the same result.
This is too strange for me. Any pointer for debugging or reasing why this behavior is showing is appreciated!
The thread context classloader (TCCL) is basically undefined in OSGi. You should avoid using it.
As an extension to standard OSGi, Equinox does supply this thing called the ContextFinder, which performs stack inspection to try to find the topmost OSGi bundle classloader in the call stack. However you get almost no control, and the result can be quite unexpected as you have seen. Of course since this is an Equinox-specific extension, any code that relies on ContextFinder working properly will fail on all other OSGi Frameworks.
So, rather than wasting time trying to debug this, it's better just not to use the TCCL at all. If you want to load a resource relative to a specific class, then do it from the literal class object, e.g.:
MyClass.class.getResource("HelloWorld.story");
UPDATE:
I noticed this in your original question: SomeClass.class.getClass(). The result of this will be the class-object of java.lang.Class itself. Calling getClassLoader() on that will always return the JVM boot class loader.... probably not what you intended!

Resources