Groovy - How to overload '+=' operator in a Map with compile static? - groovy

In Groovy, I can overload operator '+' plus as follow:
class MutableInt {
int val
MutableInt(int val) { this.val = val }
MutableInt plus(int val) {
return new MutableInt(this.val += val)
}
}
The above class works fine for the following test cases:
def m1 = new MutableInt(1);
assert (m1 + 1).val == 2;
However, if I need to use it together with Map like this and compile it with static
#groovy.transform.CompileStatic
void compileItWithStatic() {
Map<Long, MutableInt> mutMap = [:].withDefault{ new MutableInt(0) }
assert (mutMap[1L] += 20).val == 20;
}
compileItWithStatic()
I got the following error:
*Script1.groovy: 17: [Static type checking] -
Cannot call <K,V> java.util.Map <java.lang.Long, MutableInt>#putAt(java.lang.Long, MutableInt) with arguments [long, int]*
How can I override the '+=' operator and compile it with static without error?
EDIT:
If I am doing like this without compile static it works fine:
def m1 = new MutableInt(1);
assert (m1 += 1).val == 2 // <----- caution: '+=' not '+' as in previous case
However, if it was inside the method like this:
#groovy.transform.CompileStatic
void compileItWithStatic_2() {
def m1 = new MutableInt(1);
assert (m1 += 1).val == 2
}
The error will be:
Script1.groovy: -1: Access to java.lang.Object#val is forbidden # line -1, column -1.
1 error
P.S. It won't work with static compilation not with dynamic compilation.

The assignment part is throwing the error. A simple + works:
class MutableInt {
int val
MutableInt(int val) { this.val = val }
MutableInt plus(int val) {
return new MutableInt(this.val += val)
}
}
def m1 = new MutableInt(1);
assert (m1 + 1).val == 2;
#groovy.transform.CompileStatic
def compileItWithStatic() {
Map<Long, MutableInt> mutMap = [:].withDefault{ new MutableInt(0) }
mutMap[1L] + 20
mutMap
}
assert compileItWithStatic()[1L].val == 20
Groovy is parsing mutMap[1L] += 20 as mutMap.putAt(1L, 20). This looks like a bug to me. This works: mutMap[1L] = mutMap[1L] + 20, albeit more verbose.
Edit: the second error seems related to the result of the expression (m1 + 1) being parsed as Object. This should work:
#groovy.transform.CompileStatic
void compileItWithStatic_2() {
def m1 = new MutableInt(1) + 1;
assert m1.val == 2
}

Related

In Groovy/Spock assert call methods are not executed

In Groovy Unit Test with Spock the following task is quite common:
assert myResult == calculateExpectedResult() (With or without the assert keyword.)
The groovy assert prints out lots of infomation on what is going on here and why my assertion failed. But when the compared objects are very complex and deep it can be tricky go get the concrete property that failed the test.
For this I found the Javers Framework that does an excellent Job comparing the objects and producing an exact diff. I created a trait to do this:
trait DiffTrait {
Javers javers = JaversBuilder.javers().build()
String diff(result, expected) {
Diff diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
}
Now I can use it in my Unit Tests like this:
def expected = calculateExpectedResult()
assert myResult == expected, diff(myResult, expected)
This way I get a nicely printed list of differences.
But this is kind of verbose because I have to specify the values two times.
So I have changed the trait like this:
trait DiffTrait {
Javers javers = JaversBuilder.javers().build()
def result
def expected
String diff(result, expected) {
Diff diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
String diff() {
diff(result, expected)
}
def result(result) {
this.result = result
return result
}
def expected(expected) {
this.expected = expected
return expected
}
}
The idea was to use it like this:
def result = callTheSystemToProduceTheRealResult()
def expected = calculateExpectedResult()
assert result(myResult) == expected(expected), diff()
But surprisingly this does not work! The two attributes are null and the diff Method fails with a NotNull-Exception. If I debug this code the expected/result methods are never called!
If I rewrite the code like this
def result = result(callTheSystemToProduceTheRealResult())
def expected = expected(calculateExpectedResult())
assert myResult == expected, diff()
everything works as expected. The methods get called correctly and the attributes are set.
My question is: Why can't I call these methods in the assert statement? What is the difference from the Groovy/Spock perspective of these two code fragements?
Here is a gist containing all the code as running example.
It is quite easy to explain. Assertion message is evaluated before the assertion itself. The following piece of code works perfectly, however it displays static diff message:
import org.javers.core.Javers
import org.javers.core.JaversBuilder
import org.javers.core.diff.Diff
import org.javers.core.diff.changetype.ValueChange
import spock.lang.Specification
class LolSpec extends Specification implements DiffTrait {
def 'lol'() {
expect:
def whatIGot = new Lol(l: 'a')
def whatIExpected = new Lol(l: 'b')
assert result(whatIGot) == expected(whatIExpected), 'diff'
}
}
trait DiffTrait {
Javers javers = JaversBuilder.javers().build()
def result
def expected
String diff() {
diff(result, expected)
}
String diff(result, expected) {
Diff diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
def result(result) {
this.result = result
return result
}
def expected(expected) {
this.expected = expected
return expected
}
}
class Lol {
String l
}
You need to pass the arguments twice or change the implementation, e.g.:
import groovy.transform.EqualsAndHashCode
import org.javers.core.Javers
import org.javers.core.JaversBuilder
import org.javers.core.diff.changetype.ValueChange
import spock.lang.Specification
class LolSpec extends Specification {
def 'lol'() {
expect:
def whatIGot = new Lol(l: 'a')
def whatIExpected = new Lol(l: 'b')
def diff = new Diff(result: whatIGot, expected: whatIExpected)
assert diff.check(), diff.message()
}
}
class Diff {
Javers javers = JaversBuilder.javers().build()
def result
def expected
String message() {
def diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
boolean check() {
result.equals(expected)
}
}
#EqualsAndHashCode
class Lol {
String l
}

Groovy int vs integer function resolving

I recently started to learn Groovy and found not a natural behavior.
class BasicRouter {
int method_(first){
return 1;
}
int method_(int first){
return 2;
}
int method_(short second){
return 3;
}
int method_(Integer first){
return 4;
}
}
br = new BasicRouter()
int x = 1
assert br.method_(x) == 4
assert br.method_((int)29) == 2
Why in the first case we are passing a variable of type int, we get 4 and not 2?
I expect that method int method_(int) will be called.
Thanks.
The answer is here - http://docs.groovy-lang.org/latest/html/documentation/core-differences-java.html#_primitives_and_wrappers
Groovy uses objects for everything
This changes if you use CompileStatic
#groovy.transform.CompileStatic
def fInt(int x) {new BasicRouter().method_(x)}
assert fInt(1) == 2

Assigning values dynamically from a groovy config file

As I am reading values from a file in my Groovy code, I want to assign these values to the equivalent properties in my object as i am iterating through the map values!
code:
new ConfigSlurper().parse(new File(configManager.config.myFile.filepath)
.toURI().toURL()).each { k,v ->
if (k == 'something') {
v.each {
myObject.$it =v.$it
// so here i want this dynamic assignment to occur
}
}
}
You code there would already work like this, if you would use the form:
myObject."$it.key" = it.value
Here is a slightly more protective version:
class MyObject {
Long x,y
}
def obj = new MyObject()
def cfg = new ConfigSlurper().parse('''\
a {
x = 42
y = 666
}
b {
x = 93
y = 23
}''')
cfg.b.findAll{ obj.hasProperty(it.key) }.each{
obj.setProperty(it.key,it.value)
}
assert obj.x==93 && obj.y==23

Unexpected behavior with overloaded methods

I'm a bit confused about groovys method overloading behavior: Given the class
and tests below, I am pretty okay with testAStringNull and testBStringNull
throwing ambiguous method call exceptions, but why is that not the case for
testANull and testBNull then?
And, much more importantly: why does testBNull(null)
call String foo(A arg)? I guess the object doesn't know about the type of the variable it's bound to, but why is that call not ambiguous to groovy while the others are?
(I hope I explained well enough, my head hurts from generating this minimal
example.)
class Foo {
static class A {}
static class B {}
String foo(A arg) { return 'a' }
String foo(String s, A a) { return 'a' }
String foo(B arg) { return 'b' }
String foo(String s, B b) { return 'b' }
}
Tests:
import org.junit.Test
import Foo.A
import Foo.B
class FooTest {
Foo foo = new Foo()
#Test
void testA() {
A a = new A()
assert foo.foo(a) == 'a'
}
#Test
void testAString() {
A a = new A()
assert foo.foo('foo', a) == 'a'
}
#Test()
void testANull() {
A a = null
assert foo.foo(a) == 'a'
}
#Test
void testAStringNull() {
A a = null
assert foo.foo('foo', a) == 'a'
}
#Test
void testB() {
B b = new B()
assert foo.foo(b) == 'b'
}
#Test
void testBString() {
B b = new B()
assert foo.foo('foo', b) == 'b'
}
#Test
void testBNull() {
B b = null
assert foo.foo(b) == 'b'
}
#Test
void testBStringNull() {
B b = null
assert foo.foo('foo', b) == 'b'
}
}
It's a (somewhat little-known) oddity of Groovy's multi-dispatch mechanism, which as attempting to invoke the "most appropriate" method, in combination with the fact that the provided static type (in your case A or B) is not used as part of the dispatch mechanism. When you declare A a = null, what you get is not a null reference of type A, but a reference to NullObject.
Ultimately, to safely handle possibly null parameters to overloaded methods, the caller must cast the argument, as in
A a = null
assert foo.foo('foo', a as A) == 'a'
This discussion on "Groovy Isn't A Superset of Java" may shed some light on the issue.

Groovy InputStream reading closure hanging

I'm trying to make a Java program more "Groovy". The java code reads an InputStream like so:
static int myFunction(InputStream is) throws IOException {
int b=is.read();
if (b==0) return b;
StringBuffer sb=new StringBuffer();
int c;
boolean done = false;
while(!done) {
c=is.read();
sb.append((char)c);
if(c == '\n') {
done=true;
}
}
System.out.println(sb.toString());
if (b == 1) throw new IOException("blah");
return b;
}
My Groovy version looks like this:
def myFunction(InputStream is) throws IOException {
int b=is.read()
if (b==0) return b
def reader = new BufferedReader(new InputStreamReader(is))
reader.eachLine { println(it) }
println("DONE")
if (b == 1) throw new IOException("blah")
return b
}
It prints the contents of the stream and then just hangs as if it's trying to read more. It never prints "DONE" (added for debugging). Next I tried it using is.eachByte and passing a closure with an explicit "if (c == '\n') return" but I found that return inside a closure acts more like a continue and doesn't actually break out of the closure. Any idea what I'm doing wrong?
Instead of
reader.eachLine { println(it) }
Can you try
println reader.readLine()

Resources