https://groovy-lang.org/ logo
Join Slack
Powered by
# groovy
  • p

    Paolo

    05/04/2026, 4:04 PM
    Hi team! I’ve identified a significant shift in Groovy 5 regarding “file truth” semantics (GROOVY-10949). In the new version, a
    File
    object evaluates to
    false
    if the file does not physically exist, whereas previously it only required the reference to be non-null. While this change impacts the Nextflow codebase, our primary concern is the broader ecosystem: • Critical External Impact: This change is a “silent breaker” for the thousands of third-party scripts and applications running on Nextflow. Users expecting legacy Groovy behavior will encounter unexpected logic failures that are notoriously difficult to debug in a pipeline context. • Internal Management: While we can refactor our own core codebase to accommodate the new semantics, we cannot realistically control or force a synchronized update across the entire community of external plugins and user-maintained pipelines. To mitigate this, I’ve submitted this PR to introduce a system option that allows reverting to the previous behavior. This ensures backward compatibility and provides a necessary safety net for the community as they transition. Hope you will consider this for merge!
    👏 1
  • p

    paulk_asert

    05/05/2026, 2:15 AM
    Sounds like a useful flag to have. I left some comments on the PR.
  • g

    glaforge

    05/31/2026, 8:08 PM
    @paulk_asert Groovy website struggles to load for me right now
  • p

    paulk_asert

    05/31/2026, 9:20 PM
    let me take a look
  • p

    paulk_asert

    05/31/2026, 9:22 PM
    should be okay now
    v
    • 2
    • 1
  • g

    glaforge

    06/01/2026, 5:49 AM
    👍
  • j

    Jefferoson Hilario

    07/11/2026, 1:15 AM
    Hello everybody, I need your help, There is a compatibility issue between IntelliJ and Groovy 5. You can read about the issue here: youtrack.jetbrains.com/issue/IDEA-386167. Please vote so that the IntelliJ team will prioritize it.
    👍 1
  • s

    Sean Williams

    07/21/2026, 12:15 AM
    Hey folks - I'm trying to implement a client for a RESTful API based on
    <http://groovyx.net|groovyx.net>.http.RESTClient
    . Is there some guidance for matching some of the config patterns (combo closure+dictionary support, etc.) seen with
    get()
    ,
    post()
    ,
    request()
    , and so on?
  • s

    Sean Williams

    07/21/2026, 12:17 AM
    I could possibly derive from RESTClient and override the different methods, but that feels overkill/unwise - the thing I'm trying to solve w/ encapsulation is: • avoiding path-traversal (i.e. can't navigate the client outside of the API base URL) • nuance atop the REST layer (e.g. pagination)
  • p

    paulk_asert

    07/21/2026, 1:51 AM
    @Sean Williams Have you looked at the declarative http client in groovy 6?
  • s

    Sean Williams

    07/21/2026, 1:52 AM
    To my knowledge, we're not on Groovy 6 and upgrading isn't within our control (this is in Scriptrunner for Jira - they're the ones shipping groovy classes into the JRE)
  • o

    Octavia Togami

    07/22/2026, 2:44 AM
    Gradle would like to request a backport of the ASM 9.10.1 bump to Groovy 4, so we can support Java 27 in full: https://issues.apache.org/jira/browse/GROOVY-12167
    p
    • 2
    • 3
  • s

    Sujith

    08/14/2026, 7:44 PM
    If you are attending Beer City Code this year, please come to my talk Prototype to Production: Finding Flow on the JVM with Groovy and provide your support and feedback. https://www.beercitycode.com/
  • v

    Vampire

    08/21/2026, 5:11 PM
    Is there a situation where one would prefer
    @CompileDynamic
    over
    @TypeChecked(SKIP)
    ? From what I tested,
    @TypeChecked(SKIP)
    implies
    @CompileDynamic
    but not the other way around. So if the code in general is caused to be type-checked due to
    @TypeChecked
    or a compiler config script doing it, you can only use
    @TypeChecked(SKIP)
    to not type-check some code. If the cause for type-checking is
    @CompileStatic
    or a compiler config script doing it, then both can be used. So I really wonder when I ever would want to use
    @CompileDynamic
    .
  • p

    paulk_asert

    08/21/2026, 9:29 PM
    @TypeChecked(SKIP)
    opts out of type checking, and since the type info gathered during checking is what static compilation is built on, it opts out of that too.
    @CompileDynamic
    means the code needs dynamic dispatch. It would make sense on a method requiring dynamic features but still checkable - type checking could then be toggled at the class level via
    @TypeChecked
    . If the dynamic features also mean that checking is not possible, then the
    SKIP
    path shows that intent.
  • v

    Vampire

    08/22/2026, 11:40 AM
    Ah, right, if type-checking is successful but still the dynamic dispatch would cause a different result, makes sense, thanks. Btw. is it expected or a bug if something that is successful under type-checked fails with static-compile?
  • p

    paulk_asert

    08/22/2026, 10:41 PM
    The general rule would be runtime divergence could be expected (good to document), compile-time is generally a bug. There are obvious ways to make it happen (never a good idea), e.g. create a type checking extension that "ignores some error about missing type info" and proceeds. Two places AI just found where Groovy itself breaks the rule (I'll investigate these separately):
    1. Duplicate case labels in a switch expression (both int and String reproduce): @TypeChecked compiles fine (dynamically legal — first match wins, second is dead code), but @CompileStatic fails with "Duplicate case label"
    2. @CompileStatic on a constructor inside a non-statically-compiled class that has fields, properties, or instance initializers → "Cannot statically compile constructor implicitly including non-static elements…"
    AI Advice for framework code:
    If this is happening in third-party framework code, the usual cause is an AST transform or type-checking extension rather than your code. Check whether the framework applies transforms that generate/rewrite code after type checking — the static compiler needs each call annotated with its resolved target (DIRECT_METHOD_CALL_TARGET / INFERRED_TYPE node metadata), and code injected post-STC won't have it, so it compiles fine dynamically and under @TypeChecked but fails under @CompileStatic. Errors like "Target method … hasn't been set", or VerifyErrors only under static compilation, are the tell. If the framework ships a type-checking extension, it should be using makeDynamic() (or resolving real method targets) for the calls it vouches for.
  • v

    Vampire

    08/23/2026, 3:33 AM
    There are obvious ways to make it happen (never a good idea), e.g. create a type checking extension that "ignores some error about missing type info" and proceeds.
    That's only obvious if you are aware of type checking extensions, which I was not up to now, so thanks for mentioning them, I could actually right now need to use them. 😄
    Two places AI just found where Groovy itself breaks the rule (I'll investigate these separately):
    In my case it was access to a
    private static final Map
    . Type-check was happy with that, compile-static was not. A call to a
    private static
    method was already complained about by the Type-checker. So here it also seems obvious to me that the type-checker should complain, just wanted to know the general rule.
  • p

    paulk_asert

    08/23/2026, 6:05 AM
    AI read on such a case:
    Why the asymmetry exists: STC's method selection filters candidates by visibility, so a private static method of another class is rejected up front in both modes. But its property/field resolution doesn't enforce visibility — it happily resolves P.M and infers Map. Under @TypeChecked that goes unnoticed because runtime dispatch is dynamic and Groovy is historically lenient about private access, so the code even runs. Under @CompileStatic, StaticTypesCallSiteWriter has to emit a direct GETSTATIC, re-checks accessibility at codegen time, finds no bridge method (those only exist for nestmate-style relationships — same class, closures, inner classes), and refuses with the late, non-STC-flavored "Access to P#M is forbidden". The workaround (@PackageScope, or exposing a getter) is straightforward.
    Probably should be fixed - probably a breaking change for some edge case.
    v
    • 2
    • 1
  • p

    paulk_asert

    08/23/2026, 6:11 AM
    I created GROOVY-12290
  • v

    Vampire

    08/23/2026, 8:27 AM
    Great, thanks, saves me from doing it :-). The issue says you can use
    .@
    to work-around. Is there also something similar for calling a private method? If not (or anyway) is there some way to doing something ad-hoc dynamically like
    makeDynamic
    in stc extension but in the actual code? Like
    dynamic { foo.privateMethod() as String }
    besides moving it to a helper method and marking that with
    SKIP
    I mean.
    p
    • 2
    • 5
  • j

    jonnybot

    08/24/2026, 8:26 PM
    Seems like the website's down again. I know there was some effort in the past to see if we could get the page to be a bit more reliable. Any word on that?
  • v

    Vampire

    08/27/2026, 2:52 AM
    Is it expected, that under static-compilation the arguments given to a closure differ? Given
    Copy code
    class Foo {
      def foo() {
        { Object[] foo -> println(foo) }.call(new Object[] { 'foo' })
      }
    }
    new Foo().foo()
    it prints
    [foo]
    . Adding
    @groovy.transform.CompileStatic
    , it prints
    [[foo]]
    . Removing the
    Object[]
    with added static-compilation it again prints
    [foo]
    .
    • 1
    • 1
  • v

    Vampire

    08/27/2026, 9:11 AM
    Given the following snippet:
    Copy code
    @Grab('jakarta.faces:jakarta.faces-api:4.0.1')
    import jakarta.faces.component.UIInput
    
    @groovy.transform.CompileStatic
    class Foo {
      def foo() {
        println(UIInput.PropertyKeys)
        println(UIInput.PropertyKeys['localValueSet'])
        println(UIInput.PropertyKeys.localValueSet)
      }
    }
    new Foo().foo()
    this fails at runtime at the third
    println
    (issues.apache.org/jira/browse/GROOVY-12310) with message
    Copy code
    java.lang.IllegalAccessError: failed to access class jakarta.faces.component.UIInput$PropertyKeys from class Foo
    Besides that STC should probably already fail (hence the issue), the first two `println`s work currently. Is there there some syntax trick (like
    .@
    for private properties and
    .&...()
    for private methods) that would make this work while keeping the IDE reference to
    localValueSet
    intact instead of the String-y access without using a dynamic helper method?
  • v

    Vampire

    09/01/2026, 6:10 AM
    Anyone any idea?
    p
    • 2
    • 4
  • v

    Vampire

    09/11/2026, 1:53 PM
    I opened the Spock project in a freshly installed Eclipse with a freshly installed greclipse. I found this in the Eclipse log, how can this happen?
    Copy code
    ava.lang.NoSuchMethodError: 'org.codehaus.groovy.ast.stmt.TryCatchStatement org.codehaus.groovy.ast.stmt.TryCatchStatement.addCatch(org.codehaus.groovy.ast.stmt.CatchStatement)'
    	at org.spockframework.compiler.ConditionRewriter.surroundWithTryCatch(ConditionRewriter.java:796)
    	at org.spockframework.compiler.ConditionRewriter.rewriteOtherCondition(ConditionRewriter.java:739)
    	at org.spockframework.compiler.ConditionRewriter.rewriteCondition(ConditionRewriter.java:654)
    	at org.spockframework.compiler.ConditionRewriter.rewriteCondition(ConditionRewriter.java:626)
    	at org.spockframework.compiler.ConditionRewriter.rewriteImplicitCondition(ConditionRewriter.java:102)
    	at org.spockframework.compiler.DeepBlockRewriter.handleImplicitCondition(DeepBlockRewriter.java:234)
    	at org.spockframework.compiler.DeepBlockRewriter.doVisitExpressionStatement(DeepBlockRewriter.java:89)
    	at org.spockframework.compiler.AbstractDeepBlockRewriter.visitExpressionStatement(AbstractDeepBlockRewriter.java:105)
    	at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:41)
    	at org.spockframework.compiler.StatementReplacingVisitorSupport.replace(StatementReplacingVisitorSupport.java:44)
    	at org.spockframework.compiler.AbstractDeepBlockRewriter.visit(AbstractDeepBlockRewriter.java:89)
    	at org.spockframework.compiler.DeepBlockRewriter.visit(DeepBlockRewriter.java:60)
    	at org.spockframework.compiler.SpecRewriter.visitAnyBlock(SpecRewriter.java:485)
    	at org.spockframework.compiler.model.ExpectBlock.accept(ExpectBlock.java:31)
    	at org.spockframework.compiler.model.Method.accept(Method.java:70)
    	at org.spockframework.compiler.model.Spec.accept(Spec.java:112)
    	at org.spockframework.compiler.SpockTransform$Impl.processSpec(SpockTransform.java:73)
    	at org.spockframework.compiler.SpockTransform$Impl.visit(SpockTransform.java:62)
    	at org.spockframework.compiler.SpockTransform.visit(SpockTransform.java:48)
    	at org.codehaus.groovy.transform.ASTTransformationVisitor.lambda$5(ASTTransformationVisitor.java:453)
    	at org.codehaus.groovy.control.CompilationUnit$ISourceUnitOperation.doPhaseOperation(CompilationUnit.java:939)
    	at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:678)
    	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:652)
    	at org.codehaus.jdt.groovy.internal.compiler.ast.GroovyCompilationUnitDeclaration.processToPhase(GroovyCompilationUnitDeclaration.java:243)
    	at org.codehaus.jdt.groovy.internal.compiler.ast.GroovyCompilationUnitDeclaration.resolve(GroovyCompilationUnitDeclaration.java:639)
    	at org.eclipse.jdt.internal.compiler.Compiler.process(Compiler.java:833)
    	at org.eclipse.jdt.internal.compiler.ProcessTaskManager.processing(ProcessTaskManager.java:135)
    	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:545)
    	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:328)
    	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
    	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
    	at java.base/java.lang.Thread.run(Thread.java:1474)
    I'm debugging Eclipse right now and sitting at a breakpoint where it happened. Both instances come from the same class loader. Also, doing
    tryCatchStatement.addCatch(catchStatement)
    in the debugger evaluation works just fine without exception. But the breakpoint is in the constructor of the
    NoSuchMethodError
    , so it just happened at that exact place. 😕 It even happens consistently and reproducibly. If I recompile
    GuiceMultiModules
    when it tries to transform the
    assert service1 instanceof IService1
    . Or also any of the other 5 explicit and implicit assertions. Even if I have only one
    expect: true
    it happens. Even if I boil down the whole class to just
    Copy code
    package org.spockframework.guice
    
    import spock.lang.Specification
    
    class Foo extends Specification {
      def foo() {
        expect: true
      }
    }
    I even took out the debugger evaluation out of the loop, writing those 5 expressions to a text-file and when the breakpoint in the exception hit looked at the text file, still the classloader is the same.
    ✅ 1
    b
    • 2
    • 2
  • y

    ysb33r

    09/20/2026, 8:26 AM
    Are these fair statements about
    @POJO
    ? • Should also have an accompanying
    @CompileStatic
    • Extending a Groovy class that is not
    @POJO
    extended will always have the GroovyObject methods even in the derived class are annotated with
    @POJO
    . • It is not neccessary to annotate interfaces in Groovy with
    @POJO
    .
  • p

    paulk_asert

    09/24/2026, 8:32 PM
    Yes, mostly. @POJO only has the no-GroovyObject effect when paired with @CompileStatic. A @POJO subclass of a normal Groovy superclass still inherits the superclass’s GroovyObject methods, so it won’t become a true plain POJO. And annotating interfaces with @POJO is unnecessary/redundant.
    👍 1
  • v

    Vampire

    10/06/2026, 5:39 PM
    Is it expected or a bug, that if you use
    VariableExpression.THIS_EXPRESSION
    the STC and thus static-compile gets confused. We use this at some places in the Spock transform. While trying to make Spock specs compatible with STC and SC, it was observed that STC stores type information at the current node and using
    VariableExpression.THIS_EXPRESSION
    then causes conflicting casts when used inside and outside a closure. As a work-around we can instead use
    new VariableExpression("this")
    , but is this expected, or should it work properly and I should report a bug? As an example.
    Copy code
    class ASpec extends Specification {
      def "mock init closure"() {
        given:
        List<String> list = Mock(List) {
          size() >> 3
        }
    
        when:
        int size = list.size()
    
        then:
        size == 3
      }
    }
    compiles in semantic analysis to
    Copy code
    import spock.lang.*
    
    @org.spockframework.runtime.model.SpecMetadata(filename = 'script.groovy', line = 1)
    public class ASpec extends spock.lang.Specification {
    
        @org.spockframework.runtime.model.FeatureMetadata(name = 'mock init closure', ordinal = 0, line = 2, blocks = [@org.spockframework.runtime.model.BlockMetadata(kind = org.spockframework.runtime.model.BlockKind.SETUP, texts = []), @org.spockframework.runtime.model.BlockMetadata(kind = org.spockframework.runtime.model.BlockKind.WHEN, texts = []), @org.spockframework.runtime.model.BlockMetadata(kind = org.spockframework.runtime.model.BlockKind.THEN, texts = [])], parameterNames = [])
        public void $spock_feature_0_0() {
            org.spockframework.runtime.ValueRecorder $spock_valueRecorder = new org.spockframework.runtime.ValueRecorder()
            org.spockframework.runtime.ErrorCollector $spock_errorCollector = org.spockframework.runtime.ErrorRethrower.INSTANCE
            org.spockframework.runtime.SpockRuntime.callBlockEntered(this, 0)
            java.util.List<String> list = org.spockframework.runtime.SpecInternals.MockImpl(this, 'list', java.util.List, java.util.List, { ->
                this.getSpecificationContext().getMockController().addInteraction(new org.spockframework.mock.runtime.InteractionBuilder(5, 7, 'size() >> 3').addEqualTarget(it).addEqualMethodName('size').setArgListKind(true, false).addConstantResponse(3).build())
            })
            org.spockframework.runtime.SpockRuntime.callBlockExited(this, 0)
            org.spockframework.runtime.SpockRuntime.callBlockEntered(this, 1)
            java.lang.Integer size = list.size()
            org.spockframework.runtime.SpockRuntime.callBlockExited(this, 1)
            org.spockframework.runtime.SpockRuntime.callBlockEntered(this, 2)
            try {
                org.spockframework.runtime.SpockRuntime.verifyCondition($spock_errorCollector, $spock_valueRecorder.reset(), 'size == 3', 12, 5, null, $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(2), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(0), size) == $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(1), 3)))
            }
            catch (java.lang.Throwable $spock_condition_throwable) {
                org.spockframework.runtime.SpockRuntime.conditionFailedWithException($spock_errorCollector, $spock_valueRecorder, 'size == 3', 12, 5, null, $spock_condition_throwable)}
            finally {
            }
            org.spockframework.runtime.SpockRuntime.callBlockExited(this, 2)
            this.getSpecificationContext().getMockController().leaveScope()
        }
    
    }
    The important part here is the two
    getSpecificationContext()
    calls, one inside the mock init closure, one as last line in the feature method, both added by the Spock transform. If those use
    VariableExpression._THIS_EXPRESSION_
    then at runtime you get
    java.lang.ClassCastException: apackage.ASpec cannot be cast to apackage.ASpec$__spock_feature_0_0_closure1
    . If you use
    new VariableExpression("this")
    instead, it works as intended.
    • 1
    • 1
  • j

    Jefferoson Hilario

    10/09/2026, 12:46 AM
    I just posted this wish; when you have time, feel free to take a look if you'd like. issues.apache.org/jira/browse/GROOVY-12442 @paulk_asert Thank you!