Groovy Class in Mule 4 - spring-bean

I want to invoke a groovy class in Execute Component of Scripting Module.
Earlier I kept the groovy packages in src/main/resources folder. I was able to invoke them using
import com.exampes.project.service.CustomerService;
But when added Spring Module to Mule 4 (for adding spring beans), I get an error
com.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Script1.groovy: 1: unable to resolve class com.exampes.project.service.CustomerService
# line 1, column1.
import com.exampes.project.service.CustomerService;
^
I tried adding the packages in mule-artifact.json too:
{
"minMuleVersion": "4.3.0",
"requiredProduct": "MULE_EE",
"classLoaderModelLoaderDescriptor": {
"id": "mule",
"attributes": {
"exportedResources": [ "jpa-beans.xml" ],
"exportedPackages": [ "com.examples.project.service"]
}
}
}
Any Idea why this is happening?
I tried by keeping the packages in src/main/java, but didn't help. Do I need to change the packages location?

I have a similar project and added the Spring Module without any issues. I didn't had to change the mule-artifact.json. Current versions of the Mule Maven Plugin handle the packging much more automatically. What I noticed is that sometimes the Spring beans you use might interact badly with the application. If you comment the <spring:config> element, do you still have the same issue? It might point to the actual cause.

Related

Invoking groovy method in Mule 4

I have built a complete groovy project with JPA repo for data persistence operations. Now I want to invoke the methods from the script in Mule 4 without changing anything in the groovy project.
eg. CustomerService.groovy (pseudo code)
import com.example.dao.CustomerDao.groovy
... other imports...
#Service
class CustomerService {
#Autowired
CustomerDao cDao
#Transactional
publid Customer createCustomer(Customer customer) {
return cDao.save(customer)
}
... other methods...
}
CustomerDao.groovy
import spring.JPA (the original import path may vary)
#Repository
class CustomerDao implements JPARepository<Customer, Integer> {
}
This project is working in Mule 3. In Mule 3 we have an Invoke component which could be used to invoke the methods from the groovy script. The Mule 4 the Invoke component is compatible only with Java and not groovy.
The Scripting module's 'Execute' component can invoke a groovy script but not sure how to invoke the method. Is the any work around for this in Mule 4?
Problems occured as of now
In 'Execute' component if I import another file I get the error as
Unalbe to resolve class com.example.dao.CustomerDao
# line 3 column 1,
import com.example.dao.CustomerDao.groovy
^
Found a solution for similar problem https://help.mulesoft.com/s/article/Compilation-exception-in-Mule4-x-when-using-Groovy-script-with-Import-statement but unable to implement it.
In the article, he developer had an issue with an apache dependency, which he/she could get from mvn repo. I am trying to import a groovy file which I have developed. So unable to add it in the dependency. I tried adding the groovy project in my local repo and fetch it but it didn't work. Moreover, when this Mule 4 application will be deployed on CloudHub it will have an issue as it won't be able to access my local repo.
Need a solution to add a spring-groovy project to Mule 4
Thanks :)
The problem is that the Groovy script executed by the Scripting Module is trying to import a class, which is not in Java's classpath. So it throws the error. The class is in another Groovy source file. What you can do is to compile the Groovy code into an actual Java class. You can try one the methods described in the Groovy documentation to integrate a Maven plugin with your Mule application pom.xml file.
Another alternative if you have a large number of Groovy classes is to create a separate project to build a Jar library, then use the solution from the KB article you mentioned.

Is additional context configuration required when upgrading cucumber-jvm from version 4 to version 6?

I am using cucumber-jvm to perform some functional tests in Kotlin.
I have the standard empty runner class:
#RunWith(Cucumber::class)
#CucumberOptions(features=[foo],
glue=[bar],
plugin=[baz],
strict=true,
monochrome=true)
class Whatever
The actual steps are defined in another class with the #ContextConfiguration springframework annotation.
This class also uses other spring features like #Autowire or #Qualifier
#ContextConfiguration(locations=["x/y/z/config.xml"])
class MyClass {
...
#Before
...
#Given("some feature file stuff")
...
// etc
}
This all work fine in cucumber version 4.2.0, however upgrading to version 6.3.0 breaks things. After updating the imports to match the new cucumber project layout the tests now fail with this error:
io.cucumber.core.backend.CucumberBackendException: Please annotate a glue class with some context configuration.
It provides examples of what it means...
For example:
#CucumberContextConfiguration
#SpringBootTest(classes = TestConfig.class)
public class CucumberSpringConfiguration {}
Or:
#CucumberContextConfiguration
#ContextConfiguration( ... )
public class CucumberSpringConfiguration {}
It looks like it's telling me I can just add #CucumberContextConfiguration to MyClass.
But why?
I get the point of #CucumberContextConfiguration, it's explained well here but why do I need it now with version 6 when version 4 got on fine without it? I can't see any feature that was deprecated and replaced by this.
Any help would be appreciated :)
Since the error matches exactly with the error I was getting in running Cucumber tests with Spring Boot, so I am sharing my fix.
One of the probable reason is: Cucumber can't find the CucumberSpringConfiguration
class in the glue path.
Solution 1:
Move the CucumberSpringConfiguration class inside the glue path (which in my case was inside the steps package).
Solution 2:
Add the CucumberSpringConfiguration package path in the glue path.
The below screenshot depicts my project structure.
As you can see that my CucumberSpringConfig class was under configurations package so it was throwing me the error when I tried to run feature file from command prompt (mvn clean test):
"Please annotate a glue class with some context configuration."
So I applied solution 2, i.e added the configurations package in the glue path in my runner class annotation.
And this is the screenshot of the contents of CucumberSpringConfiguration class:
Just an extra info:
To run tests from command prompt we need to include the below plugin in pom.xml
https://github.com/cucumber/cucumber-jvm/pull/1959 removed the context configuration auto-discovery. The author concluded that it hid user errors and removing it would provide more clarity and reduce complexity. It also listed the scenarios where the context configuration auto-discovery used to apply.
Note that it was introduced after https://github.com/cucumber/cucumber-jvm/pull/1911, which you had mentioned.
Had the same error but while running Cucumber tests from Jar with Gradle.
The solution was to add a rule to the jar task to merge all the files with the name "META-INF/services/io.cucumber.core.backend.BackendProviderService" (there could be multiple of them in different Cucumber libs - cucumber-java, cucumber-spring).
For Gradle it is:
shadowJar {
....
transform(AppendingTransformer) {
resource = 'META-INF/services/io.cucumber.core.backend.BackendProviderService'
}
}
For Maven something like this:
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/services/io.cucumber.core.backend.BackendProviderService</resource>
</transformer>
</transformers>
A bit more explanation could be found in this answer

Spring Session with Hazelcast 4

I'm trying to upgrade to Hazelcast 4.0 in our Spring Boot 2.2.1 application.
We use the #EnableHazelcastHttpSession annotation, which pulls in HazelcastHttpSessionConfiguration, which pulls in HazelcastIndexedSessionRepository from the spring-session-hazelcast jar.
However, this class won't compile because it imports Hazelcast's IMap which has moved to a different package in Hz 4.0.
Is there any way to fix this so that Spring Session works with Hazelcast 4?
I just copied the HazelcastIndexedSessionRepository into my own source code, changed the import from com.hazelcast.core.IMap to com.hazelcast.map.IMap, and swapped the sessionListenerId from String to UUID. If I keep it in the same package, then it loads my class instead of the one in the jar, and everything compiles and works fine.
Edit: We no longer get the SessionExpiredEvent, so something's not quite right, but manual testing shows us that our sessions do time out and force the user to log in again, even across multiple servers.
I found the cause of the error, you must look that the session repository is created by HazelcastHttpSessionConfiguration, in the class it checks wich version of hazelcast is in the classpath, when hazelcast4 is true then it instantiates Hazelcast4IndexedSessionRepository that doesn't use 'com.hazelcast.core.IMap' and you don't get the class not found exception.
Code of class HazelcastHttpSessionConfiguration
#Bean
public FindByIndexNameSessionRepository<?> sessionRepository() {
return (FindByIndexNameSessionRepository)(hazelcast4 ? this.createHazelcast4IndexedSessionRepository() : this.createHazelcastIndexedSessionRepository());
}
Remove the usage of HazelcastIndexedSessionRepository replace it with Hazelcast4IndexedSessionRepository or remove the code and let spring autoconfiguration do the job by HazelcastHttpSessionConfiguration

Trying to inject an #Client in to a Groovy Function

I'm trying to write a Micronaut AWS Groovy Lambda which makes HTTPS calls out to another service. I have followed the MN Docs and have created my project using:
mn create-function hello-world -lang groovy
This gave me a skeleton "hello-world" project with a functional test that I can run.
I then tried to modify the Groovy function (hello.world.HelloWorldFunction) to inject an HTTP client with the intention of calling the API within my function:
import static io.micronaut.http.HttpRequest.GET
#Field #Inject #Client("https://www.googleapis.com/books/v1") RxHttpClient httpClient
Maybe<String> helloWorld() {
httpClient.retrieve(GET("/volumes?q=isbn:0747532699"))
.firstElement()
}
Having done this I now get an exception when I run the functional test:
08:51:25.269 [nioEventLoopGroup-1-5] ERROR
i.m.h.s.netty.RoutingInBoundHandler - Unexpected error occurred:
Failed to inject value for field [httpClient] of class:
hello.world.HelloWorldFunction
Path Taken: HelloWorldFunction.httpClient
io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for field [httpClient] of class:
hello.world.HelloWorldFunction
Path Taken: HelloWorldFunction.httpClient
I'm almost certainly doing something wrong, but I'm at a bit of a loss in terms of how to figure out what. Hence grateful for any pointers.
Many thanks,
Edd
Found the answer to this. It's a bug in 1.0.0.M1. It's already fixed in master though so can be worked around by building Micronaut from source and using that.
In addition I discovered that I was returning a type that is unsupported by Lambda functions (Maybe<String>). After building MN from master and changing this to a supported return type everything is now working.

Referring to core modules from NativeScript UI plugin

I'm working on a UI component in VIM with TypeScript plugin that highlights the errors on the spot, so it's not something I get during the actual plugin installation into the app at this point (although I haven't tried yet).
declare module "card-view" {
import view = require("ui/core/view");
export class CardView extends view.View {
}
}
And I get this:
Cannot find module 'ui/core/view'.
I realize that ui/core/view is unavailable at this point, since it's a standalone plugin, but it will be available at runtime. Is there anything to be done to resolve the error? I must be missing some step that wasn't mentioned in the guide -- http://docs.nativescript.org/plugins/ui-plugin.
UPDATE 1:
When I got to card-view-common.js implementation I hit another issue. TypeScript expects android and ios properties to be implemented, but since the class extends View (from ui/core/view) they are supposed to be implemented there. In other words, I believe I still need to somehow point to the existing core module, not sure how though.
Found it. I added a devDependency to package.json with tns-core-modules like below, ran npm install and then it began recognizing the module. Makes sense if you think about how it is supposed to compile the module during the development phase without installing in the real app, but may be worth mentioning in the guide anyway.
"devDependencies": {
"tns-core-modules": "^1.5.1"
}
'ui/core/view' (and the modules, distributed through the tns-core-modules package are declared as ambient external modules.
It could be that the vim plugin you use does not recognize ambient modules correctly.

Resources