Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BiPredicate Unit Test Failed: module jdk.proxy2 does not open jdk.proxy2 to unnamed module #1412

Closed
moqimoqidea opened this issue Jan 8, 2022 · 13 comments
Labels

Comments

@moqimoqidea
Copy link

moqimoqidea commented Jan 8, 2022

Describe the bug

java.lang.reflect.InvocationTargetException
	at org.codehaus.groovy.vmplugin.v9.Java9.of(Java9.java:160)
	at org.codehaus.groovy.vmplugin.v9.Java9.getInvokeSpecialHandle(Java9.java:179)
	at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
	at com.moqi.archive.in20210711.BiPredicateDemoTest.test a domain with or syntax should return right result(BiPredicateDemoTest.groovy:60)
Caused by: java.lang.IllegalAccessException: module jdk.proxy2 does not open jdk.proxy2 to unnamed module @7eac9008
	at java.base/java.lang.invoke.MethodHandles.privateLookupIn(MethodHandles.java:259)
	... 4 more

To Reproduce

Preview:

package com.moqi


import spock.lang.Specification

import java.util.function.BiPredicate
import java.util.stream.Collectors

/**
 * Java 8 BiPredicate Examples:
 * https://mkyong.com/java8/java-8-bipredicate-examples/
 *
 * @author moqi* On 2021/7/11 16:05
 */
class BiPredicateDemoTest extends Specification {

    def "test a domain with or syntax should return right result"() {
        given:
        def domainList = Arrays.asList(new Domain("google.com", 1),
                new Domain("i-am-spammer.com", 10),
                new Domain("mkyong.com", 0),
                new Domain("microsoft.com", 2))
        BiPredicate<String, Integer> bi = (domain, score) -> (domain.equalsIgnoreCase("google.com") || score == 0)

        when:
        def result = filterBadDomain(domainList, bi | (domain, x) -> domain.equalsIgnoreCase("MICROSOFT.COM"))

        then:
        result == [["google.com", 1] as Domain, ["mkyong.com", 0] as Domain, ["microsoft.com", 2] as Domain]
    }

    static <T extends Domain> List<T> filterBadDomain(
            List<T> list, BiPredicate<String, Integer> biPredicate
    ) {
        return list.stream()
                .filter(x -> biPredicate.test(x.name, x.score))
                .collect(Collectors.toList())
    }

}

class Domain {
    String name
    Integer score

    Domain(String name, Integer score) {
        this.name = name
        this.score = score
    }

    boolean equals(o) {
        if (this.is(o)) return true
        if (getClass() != o.class) return false

        Domain domain = (Domain) o

        if (name != domain.name) return false
        if (score != domain.score) return false

        return true
    }

    int hashCode() {
        int result
        result = (name != null ? name.hashCode() : 0)
        result = 31 * result + (score != null ? score.hashCode() : 0)
        return result
    }

    @Override
    String toString() {
        return "Domain{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}'
    }
}

Expected behavior

The code should not fail.

Actual behavior

The code fails with the given exception.

Java version

openjdk version "17.0.1" 2021-10-19 LTS
OpenJDK Runtime Environment Corretto-17.0.1.12.1 (build 17.0.1+12-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.1.12.1 (build 17.0.1+12-LTS, mixed mode, sharing)

Buildtool version


Gradle 7.3.3

Build time: 2021-12-22 12:37:54 UTC
Revision: 6f556c80f945dc54b50e0be633da6c62dbe8dc71

Kotlin: 1.5.31
Groovy: 3.0.9
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 17.0.1 (Amazon.com Inc. 17.0.1+12-LTS)
OS: Mac OS X 12.1 x86_64

What operating system are you using

Mac

Dependencies

------------------------------------------------------------
Root project 'moqi-tool-java' - moqi-tool-java
------------------------------------------------------------

testRuntimeClasspath - Runtime classpath of source set 'test'.
+--- org.slf4j:slf4j-api:1.7.32
+--- org.slf4j:slf4j-log4j12:1.7.32
|    +--- org.slf4j:slf4j-api:1.7.32
|    \--- log4j:log4j:1.2.17
+--- org.projectlombok:lombok:1.18.20
+--- org.codehaus.groovy:groovy:3.0.9
+--- org.codehaus.groovy:groovy-sql:3.0.9
|    \--- org.codehaus.groovy:groovy:3.0.9
+--- commons-beanutils:commons-beanutils:1.9.4
|    +--- commons-logging:commons-logging:1.2
|    \--- commons-collections:commons-collections:3.2.2
+--- net.sourceforge.plantuml:plantuml:1.2021.8
+--- org.apache.commons:commons-lang3:3.12.0
+--- com.alibaba:fastjson:1.2.78
+--- com.google.guava:guava:31.0-jre
|    +--- com.google.guava:failureaccess:1.0.1
|    +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|    +--- com.google.code.findbugs:jsr305:3.0.2
|    +--- org.checkerframework:checker-qual:3.12.0 -> 3.18.0
|    +--- com.google.errorprone:error_prone_annotations:2.7.1
|    \--- com.google.j2objc:j2objc-annotations:1.3
+--- org.openjdk.jmh:jmh-core:1.32
|    +--- net.sf.jopt-simple:jopt-simple:4.6 -> 5.0.2
|    \--- org.apache.commons:commons-math3:3.2
+--- com.google.code.gson:gson:2.8.7
+--- com.fasterxml.jackson.core:jackson-databind:2.12.4
|    +--- com.fasterxml.jackson.core:jackson-annotations:2.12.4
|    |    \--- com.fasterxml.jackson:jackson-bom:2.12.4
|    |         +--- com.fasterxml.jackson.core:jackson-annotations:2.12.4 (c)
|    |         +--- com.fasterxml.jackson.core:jackson-core:2.12.4 (c)
|    |         +--- com.fasterxml.jackson.core:jackson-databind:2.12.4 (c)
|    |         +--- com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.12.4 (c)
|    |         +--- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.12.4 (c)
|    |         \--- com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.12.4 (c)
|    +--- com.fasterxml.jackson.core:jackson-core:2.12.4
|    |    \--- com.fasterxml.jackson:jackson-bom:2.12.4 (*)
|    \--- com.fasterxml.jackson:jackson-bom:2.12.4 (*)
+--- com.fasterxml.jackson.core:jackson-core:2.12.4 (*)
+--- com.fasterxml.jackson.core:jackson-annotations:2.12.4 (*)
+--- org.mybatis:mybatis:3.5.7
+--- org.mapstruct:mapstruct:1.4.2.Final
+--- io.sentry:sentry:5.0.1
|    \--- com.google.code.gson:gson:2.8.5 -> 2.8.7
+--- org.elasticsearch.client:elasticsearch-rest-high-level-client:7.16.1
|    +--- org.elasticsearch:elasticsearch:7.16.1
|    |    +--- org.elasticsearch:elasticsearch-core:7.16.1
|    |    +--- org.elasticsearch:elasticsearch-secure-sm:7.16.1
|    |    +--- org.elasticsearch:elasticsearch-x-content:7.16.1
|    |    |    +--- org.elasticsearch:elasticsearch-core:7.16.1
|    |    |    +--- org.yaml:snakeyaml:1.26
|    |    |    +--- com.fasterxml.jackson.core:jackson-core:2.10.4 -> 2.12.4 (*)
|    |    |    +--- com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.10.4 -> 2.12.4
|    |    |    +--- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.10.4 -> 2.12.4
|    |    |    \--- com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.10.4 -> 2.12.4
|    |    +--- org.elasticsearch:elasticsearch-geo:7.16.1
|    |    +--- org.elasticsearch:elasticsearch-lz4:7.16.1
|    |    |    +--- org.lz4:lz4-java:1.8.0
|    |    |    \--- org.elasticsearch:elasticsearch-core:7.16.1
|    |    +--- org.apache.lucene:lucene-core:8.10.1
|    |    +--- org.apache.lucene:lucene-analyzers-common:8.10.1
|    |    +--- org.apache.lucene:lucene-backward-codecs:8.10.1
|    |    +--- org.apache.lucene:lucene-grouping:8.10.1
|    |    +--- org.apache.lucene:lucene-highlighter:8.10.1
|    |    +--- org.apache.lucene:lucene-join:8.10.1
|    |    +--- org.apache.lucene:lucene-memory:8.10.1
|    |    +--- org.apache.lucene:lucene-misc:8.10.1
|    |    +--- org.apache.lucene:lucene-queries:8.10.1
|    |    +--- org.apache.lucene:lucene-queryparser:8.10.1
|    |    +--- org.apache.lucene:lucene-sandbox:8.10.1
|    |    +--- org.apache.lucene:lucene-spatial3d:8.10.1
|    |    +--- org.apache.lucene:lucene-suggest:8.10.1
|    |    +--- org.elasticsearch:elasticsearch-cli:7.16.1
|    |    |    +--- net.sf.jopt-simple:jopt-simple:5.0.2
|    |    |    \--- org.elasticsearch:elasticsearch-core:7.16.1
|    |    +--- com.carrotsearch:hppc:0.8.1
|    |    +--- joda-time:joda-time:2.10.10
|    |    +--- com.tdunning:t-digest:3.2
|    |    +--- org.hdrhistogram:HdrHistogram:2.1.9
|    |    +--- org.apache.logging.log4j:log4j-api:2.11.1 -> 2.14.1
|    |    +--- net.java.dev.jna:jna:5.10.0
|    |    \--- org.elasticsearch:elasticsearch-plugin-classloader:7.16.1
|    +--- org.elasticsearch.client:elasticsearch-rest-client:7.16.1
|    |    +--- org.apache.httpcomponents:httpclient:4.5.10
|    |    +--- org.apache.httpcomponents:httpcore:4.4.12
|    |    +--- org.apache.httpcomponents:httpasyncclient:4.1.4
|    |    +--- org.apache.httpcomponents:httpcore-nio:4.4.12
|    |    +--- commons-codec:commons-codec:1.11 -> 1.15
|    |    \--- commons-logging:commons-logging:1.1.3 -> 1.2
|    +--- org.elasticsearch.plugin:mapper-extras-client:7.16.1
|    +--- org.elasticsearch.plugin:parent-join-client:7.16.1
|    +--- org.elasticsearch.plugin:aggs-matrix-stats-client:7.16.1
|    +--- org.elasticsearch.plugin:rank-eval-client:7.16.1
|    \--- org.elasticsearch.plugin:lang-mustache-client:7.16.1
|         \--- com.github.spullara.mustache.java:compiler:0.9.6
+--- org.apache.logging.log4j:log4j-core:2.14.1
|    \--- org.apache.logging.log4j:log4j-api:2.14.1
+--- com.sparkjava:spark-core:2.9.3
|    +--- org.slf4j:slf4j-api:1.7.25 -> 1.7.32
|    +--- org.eclipse.jetty:jetty-server:9.4.31.v20200723
|    |    +--- javax.servlet:javax.servlet-api:3.1.0
|    |    +--- org.eclipse.jetty:jetty-http:9.4.31.v20200723
|    |    |    +--- org.eclipse.jetty:jetty-util:9.4.31.v20200723
|    |    |    \--- org.eclipse.jetty:jetty-io:9.4.31.v20200723
|    |    |         \--- org.eclipse.jetty:jetty-util:9.4.31.v20200723
|    |    \--- org.eclipse.jetty:jetty-io:9.4.31.v20200723 (*)
|    +--- org.eclipse.jetty:jetty-webapp:9.4.31.v20200723
|    |    +--- org.eclipse.jetty:jetty-xml:9.4.31.v20200723
|    |    |    \--- org.eclipse.jetty:jetty-util:9.4.31.v20200723
|    |    \--- org.eclipse.jetty:jetty-servlet:9.4.31.v20200723
|    |         \--- org.eclipse.jetty:jetty-security:9.4.31.v20200723
|    |              \--- org.eclipse.jetty:jetty-server:9.4.31.v20200723 (*)
|    +--- org.eclipse.jetty.websocket:websocket-server:9.4.31.v20200723
|    |    +--- org.eclipse.jetty.websocket:websocket-common:9.4.31.v20200723
|    |    |    +--- org.eclipse.jetty.websocket:websocket-api:9.4.31.v20200723
|    |    |    +--- org.eclipse.jetty:jetty-util:9.4.31.v20200723
|    |    |    \--- org.eclipse.jetty:jetty-io:9.4.31.v20200723 (*)
|    |    +--- org.eclipse.jetty.websocket:websocket-client:9.4.31.v20200723
|    |    |    +--- org.eclipse.jetty:jetty-client:9.4.31.v20200723
|    |    |    |    +--- org.eclipse.jetty:jetty-http:9.4.31.v20200723 (*)
|    |    |    |    \--- org.eclipse.jetty:jetty-io:9.4.31.v20200723 (*)
|    |    |    +--- org.eclipse.jetty:jetty-xml:9.4.31.v20200723 (*)
|    |    |    +--- org.eclipse.jetty:jetty-util:9.4.31.v20200723
|    |    |    +--- org.eclipse.jetty:jetty-io:9.4.31.v20200723 (*)
|    |    |    \--- org.eclipse.jetty.websocket:websocket-common:9.4.31.v20200723 (*)
|    |    +--- org.eclipse.jetty.websocket:websocket-servlet:9.4.31.v20200723
|    |    |    +--- org.eclipse.jetty.websocket:websocket-api:9.4.31.v20200723
|    |    |    \--- javax.servlet:javax.servlet-api:3.1.0
|    |    +--- org.eclipse.jetty:jetty-servlet:9.4.31.v20200723 (*)
|    |    \--- org.eclipse.jetty:jetty-http:9.4.31.v20200723 (*)
|    \--- org.eclipse.jetty.websocket:websocket-servlet:9.4.31.v20200723 (*)
+--- com.googlecode.aviator:aviator:5.2.7
+--- com.sun.mail:javax.mail:1.6.2
|    \--- javax.activation:activation:1.1
+--- org.ow2.asm:asm:9.2
+--- org.ow2.asm:asm-commons:9.2
|    +--- org.ow2.asm:asm:9.2
|    +--- org.ow2.asm:asm-tree:9.2
|    |    \--- org.ow2.asm:asm:9.2
|    \--- org.ow2.asm:asm-analysis:9.2
|         \--- org.ow2.asm:asm-tree:9.2 (*)
+--- org.apache.httpcomponents.client5:httpclient5:5.1
|    +--- org.apache.httpcomponents.core5:httpcore5:5.1.1
|    +--- org.apache.httpcomponents.core5:httpcore5-h2:5.1.1
|    |    \--- org.apache.httpcomponents.core5:httpcore5:5.1.1
|    +--- org.slf4j:slf4j-api:1.7.25 -> 1.7.32
|    \--- commons-codec:commons-codec:1.15
+--- org.apache.httpcomponents.client5:httpclient5-fluent:5.1
|    +--- org.apache.httpcomponents.client5:httpclient5:5.1 (*)
|    \--- org.slf4j:slf4j-api:1.7.25 -> 1.7.32
+--- org.checkerframework:checker-qual:3.18.0
+--- org.spockframework:spock-bom:2.0-groovy-3.0
|    \--- org.spockframework:spock-core:2.0-groovy-3.0 (c)
+--- org.spockframework:spock-core:2.0-groovy-3.0
|    +--- org.junit:junit-bom:5.7.2
|    |    +--- org.junit.platform:junit-platform-engine:1.7.2 (c)
|    |    +--- org.junit.platform:junit-platform-testkit:1.7.2 (c)
|    |    +--- org.junit.platform:junit-platform-commons:1.7.2 (c)
|    |    \--- org.junit.platform:junit-platform-launcher:1.7.2 (c)
|    +--- org.codehaus.groovy:groovy:3.0.8 -> 3.0.9
|    +--- org.junit.platform:junit-platform-engine -> 1.7.2
|    |    +--- org.junit:junit-bom:5.7.2 (*)
|    |    +--- org.apiguardian:apiguardian-api:1.1.0
|    |    +--- org.opentest4j:opentest4j:1.2.0
|    |    \--- org.junit.platform:junit-platform-commons:1.7.2
|    |         +--- org.junit:junit-bom:5.7.2 (*)
|    |         \--- org.apiguardian:apiguardian-api:1.1.0
|    +--- org.junit.platform:junit-platform-testkit -> 1.7.2
|    |    +--- org.junit:junit-bom:5.7.2 (*)
|    |    +--- org.apiguardian:apiguardian-api:1.1.0
|    |    +--- org.assertj:assertj-core:3.16.1
|    |    +--- org.opentest4j:opentest4j:1.2.0
|    |    \--- org.junit.platform:junit-platform-launcher:1.7.2
|    |         +--- org.junit:junit-bom:5.7.2 (*)
|    |         +--- org.apiguardian:apiguardian-api:1.1.0
|    |         \--- org.junit.platform:junit-platform-engine:1.7.2 (*)
|    +--- org.hamcrest:hamcrest:2.2
|    +--- org.jetbrains:annotations:20.1.0
|    +--- org.ow2.asm:asm:9.1 -> 9.2
|    +--- net.bytebuddy:byte-buddy:1.11.0 -> 1.11.12
|    +--- cglib:cglib-nodep:3.3.0
|    \--- org.objenesis:objenesis:3.2
+--- org.hamcrest:hamcrest-core:2.2
|    \--- org.hamcrest:hamcrest:2.2
+--- cglib:cglib-nodep:3.3.0
+--- com.h2database:h2:2.0.204
+--- net.bytebuddy:byte-buddy:1.11.12
+--- org.objenesis:objenesis:3.2
\--- com.h2database:h2:1.4.200 -> 2.0.204

(c) - dependency constraint
(*) - dependencies omitted (listed previously)

A web-based, searchable dependency report is available by adding the --scan option.

Additional context

No response

@moqimoqidea moqimoqidea added the bug label Jan 8, 2022
@leonard84
Copy link
Member

Related to #1406 but different, I have the suspicion this is actually caused by groovy as you are not trying to create a Mock but use closure conversion. Could you try the same in a JUnit 4/5 Test?

@moqimoqidea
Copy link
Author

Related to #1406 but different, I have the suspicion this is actually caused by groovy as you are not trying to create a Mock but use closure conversion. Could you try the same in a JUnit 4/5 Test?

thank you, I will try it later.

@kriegaex
Copy link
Contributor

What is bi | (domain, x) -> domain.equalsIgnoreCase("MICROSOFT.COM") supposed to do? Should it not be either bi or the inline closure? What are you trying to achieve by trying a bitwise OR of those two closures? If you simply use one of them, the spec will run normally and fail because the condition is violated. If then you also fix the filter condition, the test passes:

  def "test a domain with or syntax should return right result"() {
    given:
    def domainList = [
      new Domain("google.com", 1),
      new Domain("i-am-spammer.com", 10),
      new Domain("mkyong.com", 0),
      new Domain("microsoft.com", 2)
    ]

    when:
    def result = filterBadDomain(domainList, (domain, score) -> !domain.equalsIgnoreCase("I-AM-SPAMMER.COM"))

    then:
    result == [["google.com", 1] as Domain, ["mkyong.com", 0] as Domain, ["microsoft.com", 2] as Domain]
  }

@kriegaex
Copy link
Contributor

kriegaex commented Jan 15, 2022

Hm, I see that Groovy seems to permit chaining of bi-predicates and/or closures using bitwise logical operators. As a Groovy non-expert, I had no idea that was possible. I also did not find any relevant documentation about this. Maybe I searched for the wrong keywords.

Anyway, without Spock, this works in JDK <16, while it fails the way you described above in JDK 16+. This holds true independent of whether we use Java lambda or Groovy closure syntax.

package org.acme

import java.util.function.BiPredicate

class CombineBiPredicatesAndClosures {
  static void main(String[] args) {
    println System.properties["java.version"]

    // Lambda syntax only works in Groovy 3.0
    // BiPredicate<String, Integer> bi = (domain, score) -> domain.equalsIgnoreCase("google.com")
    // def bi2 = (domain, score) -> score == 11

    // Closure syntax works in Groovy 2.5, too
    BiPredicate<String, Integer> bi = { domain, score -> domain.equalsIgnoreCase("google.com") }
    def bi2 = { domain, score -> score == 11 }

    def logicalOr = bi | bi2
    assert logicalOr.test("google.com", 11)
    assert logicalOr.test("google.com", 0)
    assert logicalOr.test("x", 11)
    assert !logicalOr.test("x", 0)

    def logicalAnd = bi & bi2
    assert logicalAnd.test("google.com", 11)
    assert !logicalAnd.test("google.com", 0)
    assert !logicalAnd.test("x", 11)
    assert !logicalAnd.test("x", 0)
  }
}

Try it in the Groovy Web Console, where it always works, because GWC runs on JRE 11.

So we are dealing with a Groovy issue, as it seems. As usual, @leonard84 is right in such things.

@moqimoqidea
Copy link
Author

moqimoqidea commented Jan 16, 2022

Thank you for your awesome work.

As To Reproduce said, the code is from Java 8 BiPredicate Examples, I just tested it with Spock. And after upgrading to Java17 I found that it doesn't work properly.

I'm happy to see this bug show on the table, should I go to Groovy Project to open the issue, or is there a better way? thank you.

@kriegaex
Copy link
Contributor

kriegaex commented Jan 16, 2022

As To Reproduce said, the code is from Java 8 BiPredicate Examples, I just tested it with Spock.

Thanks for bringing the original Java code to my attention again. Java functional interfaces are not my strong suit. Now I understand that BiPredicate simply has methods called or, and, negate which are meant to logically combine bi-predicates. Groovy therefore also accepts bitwise logical operators in this case, because when overloading them they happen to have the same method names, at least for bitwise AND and OR. There is however no overloading for !, only for ~ (bitwise negate, method name bitwiseNegate and therefore different from the BiPredicate method name).

Somehow Groovy has problems if the first of the two chained bi-predicates is a closure or lambda. Even without chaining, it is impossible to call bi.negate() upon it on JVM 16+. If however we change the code to read

// Use old-school anonymous class instead of closure or lambda
BiPredicate<String, Integer> bi = new BiPredicate<String, Integer>() {
  @Override
  boolean test(String domain, Integer score) {
    return domain.equalsIgnoreCase("google.com")
  }
}
def bi2 = { domain, score -> score == 11 }

it runs smoothly.

@kriegaex
Copy link
Contributor

kriegaex commented Jan 16, 2022

Sorry to spam this issue, but I was curious and tried Groovy 4.0.0-rc-2: It works! So this seems to be a Groovy 3 problem. Maybe we really open an issue and have this fix backported, if possible. Here is my Maven project which works without Surefire, JUnit or Spock. It simply uses Exec Maven Plugin to automatically run the example class during the test phase. This way we can exclude any test tools or plugins as root causes.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>Spock_GH_1412</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <java.version>1.8</java.version>
  </properties>
  
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.apache.groovy</groupId>
        <artifactId>groovy-bom</artifactId>
        <version>4.0.0-rc-2</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.apache.groovy</groupId>
      <artifactId>groovy</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.groovy</groupId>
      <artifactId>groovy-json</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.groovy</groupId>
      <artifactId>groovy-xml</artifactId>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.gmavenplus</groupId>
        <artifactId>gmavenplus-plugin</artifactId>
        <version>1.13.0</version>
        <configuration>
          <targetBytecode>${java.version}</targetBytecode>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>3.0.0</version>
        <executions>
          <execution>
            <id>run-groovy-example</id>
            <phase>test</phase>
            <goals>
              <goal>java</goal>
            </goals>
            <configuration>
              <mainClass>CombineBiPredicatesAndClosures</mainClass>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

</project>

src/main/groovy/CombineBiPredicatesAndClosures.groovy

import java.util.function.BiPredicate

class CombineBiPredicatesAndClosures {
  static void main(String[] args) {
    println "Java version: ${System.properties['java.version']}"

    // Old-school anonymous class instead of closure or lambda
    /*
    BiPredicate<String, Integer> bi = new BiPredicate<String, Integer>() {
      @Override
      boolean test(String domain, Integer score) {
        return domain.equalsIgnoreCase("google.com")
      }
    }
    */

    // Lambda syntax only works in Groovy 3+
    //BiPredicate<String, Integer> bi = (domain, score) -> domain.equalsIgnoreCase("google.com")
    //def bi2 = (domain, score) -> score == 11

    // Closure syntax works in Groovy 2.5, too
    BiPredicate<String, Integer> bi = { domain, score -> domain.equalsIgnoreCase("google.com") }
    def bi2 = { domain, score -> score == 11 }

    def logicalNot = bi.negate()
    assert logicalNot.test("acme.org", 11)
    assert !logicalNot.test("google.com", 11)

    def logicalOr = bi | bi2
    assert logicalOr.test("google.com", 11)
    assert logicalOr.test("google.com", 0)
    assert logicalOr.test("x", 11)
    assert !logicalOr.test("x", 0)

    def logicalAnd = bi & bi2
    assert logicalAnd.test("google.com", 11)
    assert !logicalAnd.test("google.com", 0)
    assert !logicalAnd.test("x", 11)
    assert !logicalAnd.test("x", 0)
  }
}

@kriegaex
Copy link
Contributor

I created GROOVY-10450. Let's see what the maintainers say.

@moqimoqidea
Copy link
Author

Thank you for your awesome work again!

I aleady remove the unnecessary full quote.

It looks like this was a Groovy issue and was fixed in version 4.0.0.

@moqimoqidea
Copy link
Author

Thank you for your great work, if this issue has fulfilled its historic mission, you can close it.

@leonard84
Copy link
Member

Closing as the issue is with Groovy.

@kriegaex
Copy link
Contributor

kriegaex commented Feb 11, 2023

FYI, the upstream Groovy issue was fixed in an incomplete way for 3.0.15. The commit adding the last bit was added after the release (I just retested it successfully with the latest snapshot), so unfortunately, we will have to wait for 3.0.16 for it to be fixed for good. But at least, after more than a year, there are some good news.

@kriegaex
Copy link
Contributor

kriegaex commented Mar 15, 2023

@leonard84, Groovy 3.0.16 has been released a couple of days ago, i.e. this issue is now fixed upstream. Maybe it makes sense to also bump Spock 3.x to that release. If you want to somehow refactor my sample code into a regression test, is up to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants