quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.67k stars 2.65k forks source link

Groovy language support #2720

Closed aaloise closed 1 year ago

aaloise commented 5 years ago

It's would be nice to have Groovy supported. It has smooth Java integration, relatively short learning curve and support for unit testing.

Version 3 is being worked on to support the new features that have emerged since Java 9, with support for lambda expressions and JPMS, for instance.

Also, Vert.x has Groovy support and it would be consistent that Quarkus also supports it. Groovy has an average of 12 million downloads per month, so it is considered a popular and growing language.

geoand commented 5 years ago

Given the fact that everything that Quarkus supports works OOTB on GraalVM native images, I think that it would be very difficult (perhaps impossible?) to make Groovy work properly

aaloise commented 5 years ago

With current Groovy 2.x I agree that it is very difficult (https://speakerdeck.com/wololock/groovy-and-graalvm). I believe in a better horizon with version 3. I suggest leaving this issue open as we follow the evolution of Groovy in the coming months.

ovkhasch commented 5 years ago

Please, check this article - it might be helpful for this task: https://e.printstacktrace.blog/graalvm-and-groovy-how-to-start/

dhonig commented 5 years ago

This probably isn't as hard as it seems. Just a matter of appending the things needed to get groovy working properly on GraalVM.

stale[bot] commented 4 years ago

This issue/pullrequest has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

maxandersen commented 4 years ago

This is definitely something we want to keep around as a "really like to have". marking as pinned.

Namphibian commented 3 years ago

I have seen Groovy being used extensively in production Camel applications. Groovy makes mapping objects super easy and efficient. It is the XSLT of the JSON world for a lot of people. This is not a nice to have this is a requirement to be taken seriously as a contender for Springboot/Karaf etc.

gastaldi commented 3 years ago

IMHO JBang (https://www.jbang.dev/) is much nicer than Groovy and already runs Quarkus applications

Namphibian commented 3 years ago

@gastaldi it might be nicer but converting an entire system where the mapping have been done in Groovy from scratch is not going to fly. These services are currently working as is if it was a simple shift and lift to Quarkus no worries but redeveloping those mappings over into JBang is money. Note that this is particular to Camel.

gastaldi commented 3 years ago

@Namphibian thanks for the feedback!

Yes, I agree with you, I was talking about greenfield applications.

It's a good thing we have https://github.com/apache/camel-quarkus/issues/1746 (as part of Camel Quarkus), since we're talking Camel use cases here.

maxandersen commented 3 years ago

I don't think jbang would help here. Jbang is about bootstrapping the app from simpler means.

Here the ask is that one can use groovy classes similar to how we support kotlin, Scala etc.

Since groovy is quite compatible with Java and can compile to a .class I'm wondering if not at least something like using it for mapping or other auxiliary work would "just" work at least in Java mode ?

Native mode might be more challenging.

geoand commented 3 years ago

Groovy should definitely just work with Quarkus apps in JVM mode. Not sure about how compatible the latest Groovy versions are with native mode though...

Namphibian commented 3 years ago

Yeah look I love the Qaurkus project. And I am dying to push it into production just several key features are not there quiet yet.

geoand commented 3 years ago

What key features do you have in mind @Namphibian ?

GavinRay97 commented 3 years ago

@geoand Just out of curiosity -- the problem here is whether the compiled sources would work properly in GraalVM native and not just a matter of implementing the extension/language support right?

I think something roughly like this should barebones get the language running in devmode, no clue about how well it would run as a native image though

import java.io.File;
import java.nio.file.Path;

import org.codehaus.groovy.tools.Compiler;
import org.codehaus.groovy.control.CompilerConfiguration;

import io.quarkus.bootstrap.model.PathsCollection;
import io.quarkus.deployment.dev.CompilationProvider;

public class GroovyCompilationProvider implements CompilationProvider {
    @Override
    public Set<String> handledExtensions() {
        return Collections.singleton(".groovy");
    }

    @Override
    public void compile(Set<File> files, Context context) {
        // Groovy 3.0.8 API
        CompilerConfiguration config = new CompilerConfiguration();
        // public void setClasspathList(List<String> parts)
        // sets the classpath using a list of Strings
        config.setClasspath(context.getClassPath());
        config.setTargetDirectory(context.getOutputDirectory().getAbsolutePath());
        Compiler compiler = new Compiler(config);
        compiler.compile(files.toArray(File[]::new));
    }

    @Override
    public Path getSourcePath(Path classFilePath, PathsCollection sourcePaths, String classesPath) {
        return classFilePath;
    }
}
geoand commented 3 years ago

Yes exactly, we need something that would work with GraalVM

GavinRay97 commented 3 years ago

Yes exactly, we need something that would work with GraalVM

Got it. I have been looking some more into this, it seems some folks have had success by using "Static Groovy", which is one of two Groovy variants (Static/Dynamic), where it's compiled AoT in exchange for losing some of the flexibility/power of the language.

(I know absolutely nothing about Groovy, fair warning)

I went digging through the compiler API some more and through some Graal + Groovy stuff, I think this should theoretically allow Groovy to work properly with Quarkus + Graal:

import groovy.transform.CompileStatic
import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer

CompilerConfiguration config = new CompilerConfiguration();

// Ref: https://blog.mrhaki.com/2016/01/groovy-goodness-customising-groovy.html
// Add the AST annotation @CompileStatic to all classes.
config.addCompilationCustomizers(new ASTTransformationCustomizer(CompileStatic))

This is the same as providing the Groovy compiler "Configscript" during compilation that the user posts here (I think): https://github.com/oracle/graal/issues/346#issuecomment-383186999

import groovy.transform.CompileStatic

withConfig(configuration) {
    ast(CompileStatic)
}

I will try this weekend to get this working, with Groovy 4.0 Alpha 3 Would be neat =D

GavinRay97 commented 3 years ago

I got it working with CompileStatic! What would be a good way to test that the native image functionality is preserved, though @geoand?

https://user-images.githubusercontent.com/26604994/125884729-97c7f9db-951a-42bd-9cbe-c7fbf269be5f.mp4

geoand commented 3 years ago

Nice! What you can do is take a couple of the quickstarts (say getting-started, hibernate-reactive and rest-client-reactive) write them in Groovy and then run the native tests to see what happens.

GavinRay97 commented 3 years ago

Got it, will do this tonight/this weekend if time permits and then report back on status =) Thank you!

GavinRay97 commented 3 years ago

An update on this, for anyone that wants this/is following along:

So, the current implementation works for running Groovy in non-native image. It also MOSTLY works for running it in a native image.

There's a bit of finagling you need to do for this to even have a remote chance of succeeding.

  1. You need to set a few extra Graal flags. I used the article below as a reference, and these are what I have set in application.properties. Without this, the compilation itself will fail:
  2. Even after successfully compiling, once you try to hit an endpoint, you'll crash due to an issue with MethodHandle dynamic stuff. Fortunately, this issue was solved with a PR merged last month. You can use the current dev releases, 21.3.0-dev of Graal to get around this:

There's also an odd issue which isn't a huge deal, but you need to explicitly add the name to @PathParam annotations, or the value will always be null. I think this is some weird reflection interplay between REST-easy and Groovy or something:

@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/greeting/{name}")
public String greeting(@PathParam("name") String name) { // "name" required in @PathParam
    return service.greeting(name)
}

So, if you compile this as a native-image with GraalVM CE 21.3.0-dev, using those quarkus.native.additional-build-args and setting the @PathParam name, then what you get is that /hello works fine but /hello/greeting/{name} does this:

 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-0) HTTP Request to /hello/greeting/person failed, error id: b80ff2d7-5a81-43ac-b122-84c22ea85907-1: org.jboss.resteasy.spi.Unh
andledException: groovy.lang.MissingMethodException: No signature of method: org.acme.getting.started.GreetingService.greeting() is applicable for argument types: (String) values: [person]
Possible solutions: getAt(java.lang.String)
        at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:106)

Caused by: groovy.lang.MissingMethodException: No signature of method: org.acme.getting.started.GreetingService.greeting() is applicable for argument types: (String) values: [person]
Possible solutions: getAt(java.lang.String)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:70)
        at org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.unwrap(IndyGuardsFiltersAndSignatures.java:172)
        at java.lang.reflect.Method.invoke(Method.java:567)
        at com.oracle.svm.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:214)
        at java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:81)
        at com.oracle.svm.methodhandles.MethodHandleIntrinsicImpl.execute(MethodHandleIntrinsicImpl.java:180)
        at com.oracle.svm.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:147)
        at java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:81)
        at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:76)
        at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:985)
        at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:962)
        at java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:87)
        at com.oracle.svm.methodhandles.MethodHandleIntrinsicImpl.execute(MethodHandleIntrinsicImpl.java:180)
        at com.oracle.svm.methodhandles.Util_java_lang_invoke_MethodHandle.invokeInternal(Target_java_lang_invoke_MethodHandle.java:147)
        at java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:81)
        at java.lang.invoke.LambdaForm$NamedFunction.invokeWithArguments(LambdaForm.java:76)
        at java.lang.invoke.LambdaForm.interpretName(LambdaForm.java:985)
        at java.lang.invoke.LambdaForm.interpretWithArguments(LambdaForm.java:962)
        at java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:87)
        at java.lang.invoke.MethodHandle.invokeBasic(MethodHandle.java:0)
        at java.lang.invoke.LambdaForm$MH.0x00000007c1e11c00.invokeExact_MT(LambdaForm$MH)

Apparently, at some point during the compilation, GraalVM decides that GreetingService.greeting() does not exist.

If you grep the used_classes and used_methods by configuring Quarkus to output these:

quarkus.native.enable-reports=true
quarkus.native.debug.enabled=true
quarkus.native.additional-build-args =\
    --allow-incomplete-classpath,\
    --report-unsupported-elements-at-runtime,\
    --initialize-at-run-time=org.codehaus.groovy.control.XStreamUtils,\
    --no-fallback,\
    -H:GenerateDebugInfo=1

Then you will see that every other method in the application/class is there, in both GreetingService and GreetingResource -- except for that one 😐

I have asked in the GraalVM slack #native-image channel if anyone might know what is going on here/how to fix it 🤞

Used Classes

getting-started-quickstart/target/getting-started-1.0.0-SNAPSHOT-native-image-source-jar via ☕ v16.0.2
❯ cat reports/used_classes_getting-started-1.0.0-SNAPSHOT-runner_20210718_155908.txt | grep GreetingResource
com.oracle.svm.reflect.GreetingResource_$getStaticMetaClass_671f17df54ec52ccd062cada2deefd0ecfe33fc5
com.oracle.svm.reflect.GreetingResource_constructor_b3346ead27ea9edb25c8888b6552e019f2e6a89b
com.oracle.svm.reflect.GreetingResource_getMetaClass_41a92f4cbf6b78124cc23706b4ab445b557b6fdd
com.oracle.svm.reflect.GreetingResource_greeting_099bc5866c02b0c4209f8637147b2de7e7487cb4
com.oracle.svm.reflect.GreetingResource_hello_ebc839f3ee08a32ab438ab0d4f9573c70e0a9de8
com.oracle.svm.reflect.GreetingResource_setMetaClass_17782947a69eeba017ed88239efdca77bf125499
org.acme.getting.started.GreetingResource
org.acme.getting.started.GreetingResource_Bean

getting-started-quickstart/target/getting-started-1.0.0-SNAPSHOT-native-image-source-jar via ☕ v16.0.2
❯ cat reports/used_classes_getting-started-1.0.0-SNAPSHOT-runner_20210718_155908.txt | grep GreetingService
org.acme.getting.started.GreetingService
org.acme.getting.started.GreetingService_Bean
org.acme.getting.started.GreetingService_ClientProxy

Used Methods

getting-started-quickstart/target/getting-started-1.0.0-SNAPSHOT-native-image-source-jar via ☕ v16.0.2
❯ cat reports/used_methods_getting-started-1.0.0-SNAPSHOT-runner_20210718_155907.txt | grep GreetingResource
com.oracle.svm.reflect.GreetingResource_$getStaticMetaClass_671f17df54ec52ccd062cada2deefd0ecfe33fc5.equals(Object):boolean
com.oracle.svm.reflect.GreetingResource_$getStaticMetaClass_671f17df54ec52ccd062cada2deefd0ecfe33fc5.hashCode():int
com.oracle.svm.reflect.GreetingResource_$getStaticMetaClass_671f17df54ec52ccd062cada2deefd0ecfe33fc5.invoke(Object, Object[]):Object
com.oracle.svm.reflect.GreetingResource_$getStaticMetaClass_671f17df54ec52ccd062cada2deefd0ecfe33fc5.invokeSpecial(Object, Object[]):Object
com.oracle.svm.reflect.GreetingResource_$getStaticMetaClass_671f17df54ec52ccd062cada2deefd0ecfe33fc5.toString():String
com.oracle.svm.reflect.GreetingResource_constructor_b3346ead27ea9edb25c8888b6552e019f2e6a89b.equals(Object):boolean
com.oracle.svm.reflect.GreetingResource_constructor_b3346ead27ea9edb25c8888b6552e019f2e6a89b.hashCode():int
com.oracle.svm.reflect.GreetingResource_constructor_b3346ead27ea9edb25c8888b6552e019f2e6a89b.newInstance(Object[]):Object
com.oracle.svm.reflect.GreetingResource_constructor_b3346ead27ea9edb25c8888b6552e019f2e6a89b.toString():String
com.oracle.svm.reflect.GreetingResource_getMetaClass_41a92f4cbf6b78124cc23706b4ab445b557b6fdd.equals(Object):boolean
com.oracle.svm.reflect.GreetingResource_getMetaClass_41a92f4cbf6b78124cc23706b4ab445b557b6fdd.hashCode():int
com.oracle.svm.reflect.GreetingResource_getMetaClass_41a92f4cbf6b78124cc23706b4ab445b557b6fdd.invoke(Object, Object[]):Object
com.oracle.svm.reflect.GreetingResource_getMetaClass_41a92f4cbf6b78124cc23706b4ab445b557b6fdd.invokeSpecial(Object, Object[]):Object
com.oracle.svm.reflect.GreetingResource_getMetaClass_41a92f4cbf6b78124cc23706b4ab445b557b6fdd.toString():String
com.oracle.svm.reflect.GreetingResource_greeting_099bc5866c02b0c4209f8637147b2de7e7487cb4.equals(Object):boolean
com.oracle.svm.reflect.GreetingResource_greeting_099bc5866c02b0c4209f8637147b2de7e7487cb4.hashCode():int
com.oracle.svm.reflect.GreetingResource_greeting_099bc5866c02b0c4209f8637147b2de7e7487cb4.invoke(Object, Object[]):Object
com.oracle.svm.reflect.GreetingResource_greeting_099bc5866c02b0c4209f8637147b2de7e7487cb4.invokeSpecial(Object, Object[]):Object
com.oracle.svm.reflect.GreetingResource_greeting_099bc5866c02b0c4209f8637147b2de7e7487cb4.toString():String
com.oracle.svm.reflect.GreetingResource_hello_ebc839f3ee08a32ab438ab0d4f9573c70e0a9de8.equals(Object):boolean
com.oracle.svm.reflect.GreetingResource_hello_ebc839f3ee08a32ab438ab0d4f9573c70e0a9de8.hashCode():int
com.oracle.svm.reflect.GreetingResource_hello_ebc839f3ee08a32ab438ab0d4f9573c70e0a9de8.invoke(Object, Object[]):Object
com.oracle.svm.reflect.GreetingResource_hello_ebc839f3ee08a32ab438ab0d4f9573c70e0a9de8.invokeSpecial(Object, Object[]):Object
com.oracle.svm.reflect.GreetingResource_hello_ebc839f3ee08a32ab438ab0d4f9573c70e0a9de8.toString():String
com.oracle.svm.reflect.GreetingResource_setMetaClass_17782947a69eeba017ed88239efdca77bf125499.equals(Object):boolean
com.oracle.svm.reflect.GreetingResource_setMetaClass_17782947a69eeba017ed88239efdca77bf125499.hashCode():int
com.oracle.svm.reflect.GreetingResource_setMetaClass_17782947a69eeba017ed88239efdca77bf125499.invoke(Object, Object[]):Object
com.oracle.svm.reflect.GreetingResource_setMetaClass_17782947a69eeba017ed88239efdca77bf125499.invokeSpecial(Object, Object[]):Object
com.oracle.svm.reflect.GreetingResource_setMetaClass_17782947a69eeba017ed88239efdca77bf125499.toString():String
org.acme.getting.started.GreetingResource.$getStaticMetaClass():MetaClass
org.acme.getting.started.GreetingResource.<init>():void
org.acme.getting.started.GreetingResource.getMetaClass():MetaClass
org.acme.getting.started.GreetingResource.greeting(String):String
org.acme.getting.started.GreetingResource.hello():String
org.acme.getting.started.GreetingResource.setMetaClass(MetaClass):void
org.acme.getting.started.GreetingResource_Bean.create(CreationalContext):GreetingResource
org.acme.getting.started.GreetingResource_Bean.create(CreationalContext):Object
org.acme.getting.started.GreetingResource_Bean.equals(Object):boolean
org.acme.getting.started.GreetingResource_Bean.get():Object
org.acme.getting.started.GreetingResource_Bean.get(CreationalContext):GreetingResource
org.acme.getting.started.GreetingResource_Bean.get(CreationalContext):Object
org.acme.getting.started.GreetingResource_Bean.getBeanClass():Class
org.acme.getting.started.GreetingResource_Bean.getIdentifier():String
org.acme.getting.started.GreetingResource_Bean.getScope():Class
org.acme.getting.started.GreetingResource_Bean.getTypes():Set
org.acme.getting.started.GreetingResource_Bean.hashCode():int
​
getting-started-quickstart/target/getting-started-1.0.0-SNAPSHOT-native-image-source-jar via ☕ v16.0.2
❯ cat reports/used_methods_getting-started-1.0.0-SNAPSHOT-runner_20210718_155907.txt | grep GreetingService
org.acme.getting.started.GreetingService.$getStaticMetaClass():MetaClass
org.acme.getting.started.GreetingService.<init>():void
org.acme.getting.started.GreetingService.getMetaClass():MetaClass
org.acme.getting.started.GreetingService.setMetaClass(MetaClass):void
org.acme.getting.started.GreetingService_Bean.create(CreationalContext):GreetingService
org.acme.getting.started.GreetingService_Bean.create(CreationalContext):Object
org.acme.getting.started.GreetingService_Bean.equals(Object):boolean
org.acme.getting.started.GreetingService_Bean.get():Object
org.acme.getting.started.GreetingService_Bean.get(CreationalContext):GreetingService
org.acme.getting.started.GreetingService_Bean.get(CreationalContext):Object
org.acme.getting.started.GreetingService_Bean.getBeanClass():Class
org.acme.getting.started.GreetingService_Bean.getIdentifier():String
org.acme.getting.started.GreetingService_Bean.getScope():Class
org.acme.getting.started.GreetingService_Bean.getTypes():Set
org.acme.getting.started.GreetingService_Bean.hashCode():int
org.acme.getting.started.GreetingService_Bean.proxy():GreetingService_ClientProxy
org.acme.getting.started.GreetingService_ClientProxy.$getStaticMetaClass():MetaClass
org.acme.getting.started.GreetingService_ClientProxy.<init>(GreetingService_Bean):void
org.acme.getting.started.GreetingService_ClientProxy.arc$delegate():GreetingService
org.acme.getting.started.GreetingService_ClientProxy.arc_contextualInstance():Object
org.acme.getting.started.GreetingService_ClientProxy.getMetaClass():MetaClass
org.acme.getting.started.GreetingService_ClientProxy.getProperty(String):Object
org.acme.getting.started.GreetingService_ClientProxy.invokeMethod(String, Object):Object
org.acme.getting.started.GreetingService_ClientProxy.setMetaClass(MetaClass):void
org.acme.getting.started.GreetingService_ClientProxy.setProperty(String, Object):void
org.acme.getting.started.GreetingService_ClientProxy.toString():String
geoand commented 3 years ago

Thanks for the status update!

Unfortunately the need for --allow-incomplete-classpath, --report-unsupported-elements-at-runtime which are global settings that are completely antithetical to what we do in Quarkus when it comes to building a native-image, is a complete showstopper.

GavinRay97 commented 3 years ago

Thanks for the status update!

Unfortunately the need for --allow-incomplete-classpath, --report-unsupported-elements-at-runtime which are global settings that are completely antithetical to what we do in Quarkus when it comes to building a native-image, is a complete showstopper.

Ah damn. Welp, that's likely the end of any hope for full Groovy support on Quarkus.

I can check to see if it runs it without those, but I am fairly certain it doesn't.

Suppose worst case I can publish the plugin artifact for anyone who doesn't need to run as a native image and wants Groovy as a JVM process, then at least it wasn't all for nothing.

(And this way, it works perfectly fine)

geoand commented 3 years ago

Makes sense.

Thanks a lot for your effort on this

GavinRay97 commented 3 years ago

No problem, thanks for your personal time as well, appreciate you =)

aaloise commented 3 years ago

+1 for the plugin artifact, if native image is not needed. Eventually Groovy might have a better support for it, but meanwhile would be nice to see Quarkus + Groovy + "Regular" JVM

geoand commented 3 years ago

Suppose worst case I can publish the plugin artifact for anyone who doesn't need to run as a native image and wants Groovy as a JVM process, then at least it wasn't all for nothing.

This would be a good candidate for a Quarkiverse extension

GavinRay97 commented 3 years ago

Okay sure, I will put it up on the Quarkiverse with some notes in the README about the little idiosyncrasies it has (like requiring @PathParam to have named arg) and then folks can use it if they like =)

mkavalecz commented 2 years ago

@GavinRay97 Did you make that Quarkiverse extension in the end? Where can we find it?

GavinRay97 commented 2 years ago

I had someone message me on Twitter about this I'll put it on my Todo list to re-create the extension code and put the code up somewhere, possibly even on the Quarkiverse

zhfeng commented 1 year ago

Hi @GavinRay97, is there any update?

aaloise commented 1 year ago

Any news about this?

tombensve commented 1 year ago

Note that Groovy is up to version 4 now, and in version 4 you can specify what bytecode level should be produced.

Also note that you don't need to put all your code in the Quarkus project! I'm new to Quarkus myself, and have fought a lot with it, until I got the idea to make a parent maven module and then muliple child modules. One of these modules are the Quarkus project. It basically only contain Quarkus code like receiving a request, calling other service, providing response. All "business" logic i put in other pure Java modules that the Quarkus module then depend on. This works very well, and minimizes the issues with Quarkus. The logic modules are just plain and simple java. They can also be Groovy! Don't even think you would need @CompileStatic it you don't want.

maxandersen commented 1 year ago

@tombensve that sounds like a decent pragmatic approach. Does annotations just work?

Would you be interested in writing up an example showing this working that others can use to start from?

tombensve commented 1 year ago

Not entirely sure what you are askimg here.

Here is a page that shows how to use maven modules:https://www.codetab.org/tutorial/apache-maven/multi-module/multi-module-project/

The @CompileStatic is just a Groovy annotation that compiles groovy code to JVM bytecode. Otherwise Groovy will be interpreting method contents. If you want script looseness then don't use this annotation.

My point was just that if you keep the Quarkus stuff in a Quarkus maven project as a maven module and add other java or groovy modules and just add them as dependencies to the quarkus module then none of the code outside of the quarkus module will be affected by Quarkus or affect Quarkus. They will just be dependencies like any other dependencies.

Since Quarkus do look at the code in the quarkus project anything there will affect quarkus. After you have built a quarkus project go to the class files under target and decompile them and compare to your original code under src (IDEA will do that for you if you dubbel-click a .class file). That will make it clearer what Quarkus does.

essobedo commented 1 year ago

The Quarkus Groovy extension for Quarkus 3 and Groovy 4 has been released more details https://github.com/quarkiverse/quarkus-groovy/releases/tag/3.0.0

geoand commented 1 year ago

Closing this as we have a Quarkiverse extension