How to use Micronaut & depenency injection in a single-file Groovy script? - groovy

I want to use Micronaut from a Groovy script. It seems that annotations such as #Inject and #PostConstruct are not processed.
Here is the code I tried:
#!/usr/bin/env nix-shell
#!nix-shell -i groovy
#Grapes([
#Grab('ch.qos.logback:logback-classic'),
#Grab('io.micronaut:micronaut-runtime')
])
package org.sdf // NPE without package
import io.micronaut.runtime.Micronaut
import javax.inject.*
import javax.annotation.*
#Singleton
class Component {
}
#Singleton
class App implements Runnable {
#Inject
Component comp
#Override
#PostConstruct
public void run() {
// Never runs
assert this.comp != null
assert false
}
}
static void main(String... args) {
Micronaut.run(App, args);
}
It doesn't run post-construct method and logs this:
22:17:43.669 [main] DEBUG i.m.context.DefaultBeanContext - Resolved bean candidates [] for type: interface io.micronaut.runtime.EmbeddedApplication
22:17:43.671 [main] INFO io.micronaut.runtime.Micronaut - No embedded container found. Running as CLI application
How can I use Micronaut with dependency injection in a single-file Groovy script?

How can I use Micronaut with dependency injection in a single-file
Groovy script?
You would have to compile all of the code in your script with Micronaut's annotation processors configured on the compile time classpath for your script. Technically that could be done with a single script but as a practical matter I don't think many folks are going to have a good reason to do or build support for making that more easily done.
FYI: Not an answer to your question as asked but one simple alternative approach is to not define all of your bean related classes in a single script, instead define them in their own separate source files in a project configured to build with Maven or Gradle using our annotation processors and then consume those classes from your script using #Grab like you have for other dependencies.

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.

why can't my spring-cloud-stream mockito test Autowire my Processor?

I'm trying to create tests for my spring-cloud-stream project. I've created my own BizSyncProcessor interface instead of using the default Processor, which seems to be in all the documentation. I've done this kind of project before with tests, but can't remember if I used mockito at the same time, so I'm wondering if that's the issue, because I'm doing #RunWith(MockitoJUnitRunner.class) instead of #RunWith(SpringRunner).
I also had similar problems when building the actual app, before I included the rabbit implementation as a dependency in maven.
IntelliJ flags an error on the #Autowired BizSyncProcessor saying 'no Beans of type 'BizSyncProcessor' could be found. However I'm able to run the test, so it compiles, but then bizSyncProcessor is null when running the test.
I'm including mockito because the handler that listens for the message makes a call to another service (the SFISClient), so I'm mocking out that call.
Here's my test:
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#EnableAutoConfiguration
#Configuration
#EnableBinding(BizSyncProcessor.class)
public class UpdatedBusinessHandlerTest {
#Autowired
private BizSyncProcessor bizSyncProcessor;
#Autowired
private MessageCollector messageCollector;
#Mock
SFISClient sfisClient;
#InjectMocks
UpdatedBusinessHandler updatedBusinessHandler;
#Test
public void testWiring() throws Exception {
UpdatedBusinessAlert updatedBusinessAlert = new UpdatedBusinessAlert();
updatedBusinessAlert.setBusinessId(UUID.randomUUID());
Message<UpdatedBusinessAlert> updatedBusinessAlertMessage = MessageBuilder.withPayload(updatedBusinessAlert).build();
bizSyncProcessor.writeUpdatedBusinessIds().send(updatedBusinessAlertMessage);
Message<BusinessFlooringSummary> businessFlooringSummaryMessage = (Message<BusinessFlooringSummary>) messageCollector.forChannel(bizSyncProcessor.writeFlooringSummaries()).poll();
BusinessFlooringSummary businessFlooringSummary = businessFlooringSummaryMessage.getPayload();
assertNotNull(businessFlooringSummary);
}
}
The #SpringBootTest and everything Spring-based are not going to work in your case because you don't use #RunWith(SpringRunner). There is just nothing what can trigget those Spring hooks.
On the other hand there is no reason to use a MockitoJUnitRunner. You simply can rely on the #MockBean instead for your SFISClient: https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#boot-features-testing-spring-boot-applications-mocking-beans

Could dagger get the context of injection point?

In cdi doc:
https://docs.jboss.org/cdi/api/1.0/javax/enterprise/inject/spi/InjectionPoint.html
The example shows how to get context by using InjectionPoint:
#Produces
Logger createLogger(InjectionPoint injectionPoint) {
return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName() );
}
I am currently using Dagger2 in my project and I found no such class as InjectionPoint available. So is there any other options?
Thanks

How do I load spring-data(-neo4j)-repositories lazily?

I am using spring-data-neo4j (standalone) in my JavaEE7-application as nice neo4j-OGM.
For time being, I am trying to integrate spring-data-neo4j repositories via #Autowired into my project.
public interface UserRepository extends GraphRepository<User> {}
I have started writing some JUnit-tests, which are testing beans which themselves use this repositories. Everything works fine so far.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/spring/application-context.xml" })
#Transactional
#Import(NeighborinoNeo4jConfiguration.class)
public class UserFactoryTest {
private UserFactory userFactory;
...
}
#Named
#Stateless
public class UserFactory {
#Autowired
private UserRepository userRepo;
...
}
Now, I want to integrate this new repositories-classes into my JavaEE7-application, which I am deploying to a wildfly-8.1.
Adding the mentioned UserRepository to my application and deploying it results in following error:
javax.enterprise.inject.UnsatisfiedResolutionException: Unable to resolve a bean for 'org.springframework.data.neo4j.support.mapping.Neo4jMappingContext' with qualifiers [#javax.enterprise.inject.Default(), #javax.enterprise.inject.Any()].
at org.springframework.data.neo4j.repository.cdi.Neo4jCdiRepositoryExtension.createRepositoryBean(Neo4jCdiRepositoryExtension.java:109)
at org.springframework.data.neo4j.repository.cdi.Neo4jCdiRepositoryExtension.afterBeanDiscovery(Neo4jCdiRepositoryExtension.java:83)
...
To make myself clear: Just by adding this new interface to my source-code and deploying it, results in this error in the application-server. The app without this repository is deployed just fine.
As far as I can see, Neo4jCdiRepositoryExtension.createRepositoryBean(), runs too early. I have an own #ApplicationScoped-bean "Application" which, without this repository in the source-code, does the spring-configuration. But with this repository added, this ApplicationScoped-bean "Application" is not executed at all; and I assume this UnsatisfiedResolutionException occurs, because spring-configuration was not done before Neo4jCdiRepositoryExtension runs . I guess my problem could be solved by having the repositories initialization done after my "Application"-bean.
so... How do I load spring-data-neo4j repositories lazily?
Hint#1: #NoRepositoryBean makes the app deployable again. Of course, I cannot use the UserRepository.
import org.springframework.data.repository.NoRepositoryBean
#NoRepositoryBean
public interface UserRepository extends GraphRepository<User> {}
Hint#2: #Lazy does not help, same error.
import org.springframework.context.annotation.Lazy;
#Lazy
public interface UserRepository extends GraphRepository<User> {
versions:
pom.xml:
<spring.version>4.0.7.RELEASE</spring.version>
<spring.data.neo4j.version>3.2.0.RELEASE</spring.data.neo4j.version>
I was finally able to develop a workaround. In short I stopped using "#Autowired" at all and falled back to using javax.inject.Inject etc. again, and I am boostrapping spring-data-neo4j in good old fashioned "ClassPathXmlApplicationContext" way.
The main difficulty was to find out, how to build a spring-data-neo4j repository on my own. It is easy.
// The repo you want to have an instance of.
#NoRepositoryBean // Has to be here to avoid UnsatisfiedResolutionException from question.
public interface UserRepository extends GraphRepository<User> {
}
(Hint: "#NoRepositoryBean" is required on your repository-interfaces. Even tough I removed "#EnableNeo4jRepositories(...)".)
I assume you have a running springApplication:
final ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"spring/application-context.xml");
final Neo4jTemplate neo4jTemplate = applicationContext .getBean(Neo4jTemplate.class);
final Neo4jMappingContext neo4jMappingContext = applicationContext .getBean(Neo4jMappingContext.class);
Next is to create a GraphRepositoryFactory, which is needed to build the repositories:
org.springframework.data.neo4j.repository.GraphRepositoryFactory graphRepositoryFactory = new GraphRepositoryFactory(neo4jTemplate, neo4jMappingContext);
UserRepository userRepository = graphRepositoryFactory.getRepository(UserRepository.class);

Jmeter BSF using Groovy, Import one script's function to another

I use groovy in my Jmeter BSF, and sometimes I have functions that are used frequently enough to be moved to some script which I than can use as a library.
My approach was to create a file, say "library.groovy", and add there some function
public void function()
{
println("hello!");
}
and then use the following code in my BSF script
import library.groovy;
function();
Both files lie in the same dir, but script refuses to locate library. I also tried to explicitly wrap this function into class but I took no effect as well.
Can anyone suggest a solution for this?
Update:
I tried almost all possible solutions described in the internet. And everything that works in groovy console or Eclipse does not in Jmeter. Probably that is because of BSF. Anyone knows some workarounds?
I just had this problem, and solved it in a way that seems, to me, nicer-looking. It is basically winstaan74's answer, but with the extra bits needed to make it work.
You have your function's groovy file, named say: MyJmeterFunctions.groovy:
package My.JmeterFunctions
public class MyHelloClass {
public void hello() {
println("Hello!");
}
}
Then you compile this from the terminal:
$groovyc -d myJmeterFunctions myJmeterFunctions.groovy
and turn it into a .jar inside the /lib folder of your jmeter install, with all the other .jar files that came with jmeter
$jar cvf /<>/apache-jmeter-2.8/lib/myJmeterFunctions.jar -C myJmeterFunctions .
Now, restart jmeter. It won't know about your new .jar until you do.
Lastly you have the script that you want to run the hello() function from, which your jmeter BSF assertion/listener/ whatever points to:
import My.JmeterFunctions.*
def my_hello_class_instance = new MyHelloClass();
my_hello_class_instance.hello();
And this is what worked for me. If you'd rather organize you .jar into a different folder than jmeter's /lib, I believe you can run jmeter using (from here):
$jmeter -Jsearch_paths=/path/to/yourfunction.jar
But I haven't tried that myself.
I ended up having 2 files like below:
"MyHelloClass.groovy"
public class MyHelloClass {
public void hello() {
println("Hello!");
}
}
And "HelloScript.groovy"
try {
ClassLoader parent = getClass().getClassLoader();
GroovyClassLoader loader = new GroovyClassLoader(parent);
Class groovyClass = loader.parseClass(new File("../GroovyScripts/MyHelloClass.groovy"));
GroovyObject helloClass = (GroovyObject) groovyClass.newInstance();
helloClass.hello();
}
catch (Throwable e) {
println(e.toString());
}
Then I can run "HelloScript.groovy" in BSF from Jmeter.
I think you'll need to wrap your helper methods in a class, and then import that class. So, your helper methods file should contain..
package library
class UsefulFunctions {
static function() {
println 'hello'
}
}
And then in your test script, say
import static library.UsefulFunctions.*
function()
Now, this is just scratching the surface, but I hope it'd be enough to get you started.

Resources