2

We have a habit of overriding the toString method so that we can just get fields value just by calling

println "Object details-->$object"

We thought to write test cases for our build as a good practice and to follow TDD.

My test case failed with some missing lines of data. Test case looks like below:

void "test method:toString"() {
        given:
        CSV csv = new CSV(accountId: '1', accountName: 'testName')

        when:
        String exp = "[accountId=" + csv.accountId + ", groupId)" + csv.groupId + ", accountName=" + csv.accountName +"]"
        String string = csv.toString()

        then:
        string == exp
    }

Below is my class:

public class CSV   {
     String accountId
     String groupId
     String accountName
     String chargeMode
     String invoiceId
     String date

    @Override
    public String toString() {
        return "ChargingCsvLine [accountId=" 
               + accountId + ", groupId)" + groupId + ",      accountName="+
                 accountName + " "]"
    }
}

Test case fails abruptly. Then I gave a careful look and tried with appending '+' in end of line break and not at start of line.

And test case worked properly.

Can anyone tell me whether it's a bug or groovy just accepted both the above cases but case of appending '+' in end of line is the only correct way.

To me it seems that correct way of concatenating using '+' is

"abc"+
"def"

and not

"abc"
+"def"

But why did groovy silently broke in that case and didn't throw any errors. At least operator level exception should be thrown.

Thanks!

tim_yates
  • 167,322
  • 27
  • 342
  • 338
Vinay Prajapati
  • 7,199
  • 9
  • 45
  • 86
  • Offtopic: why not use @ToString annotation? – Jayan Dec 28 '15 at 14:05
  • Hey! Would @ToString annotation allow me a highly customised output which might contain some constant string which has nothing to do with domain or class but is part of our business logic. Using annotations don't help out always. – Vinay Prajapati Dec 28 '15 at 23:50

2 Answers2

8

Groovy takes your first line (without the ending +) and uses this a return statement and does not execute any further code.

String add1() {
    return "1"
    + "2" // never gets executed
}
assert add1()=="1"

If there wheren't a return it would give you a runtime error:

String add1() {
    "1" // one statement
    + "2" // another statement - this is the implicit return
}
assert add1()=="12"

And this fails with:

Caught: groovy.lang.MissingMethodException: No signature of method: java.lang.String.positive() is applicable for argument types: () values: []
Possible solutions: notify(), tokenize(), size(), size()
groovy.lang.MissingMethodException: No signature of method: java.lang.String.positive() is applicable for argument types: () values: []
Possible solutions: notify(), tokenize(), size(), size()
        at tos.add1(tos.groovy:3)
        at tos$add1.callCurrent(Unknown Source)
        at tos.run(tos.groovy:6)

shell returned 1

The reason here is, that groovy sees two lines, and strings don't override the positive operator.

It also fails to compile, if static compilation is used:

@groovy.transform.CompileStatic
String add1() {
    return "1"
    + "2"
}
assert add1()=="1"

Yields:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
test.groovy: 4: [Static type checking] - Cannot find matching method java.lang.String#positive(). Please check if the declared type is right and if the method exists.
 @ line 4, column 2.
        + "2"
    ^

1 error

Takeaways:

  • groovy has differences to java
  • don't generate toString in your IDE, when there is @ToString in groovy
  • don't bang strings together with + in groovy, when there are GStrings.
cfrick
  • 35,203
  • 6
  • 56
  • 68
1

You can use triple single quotes for multi-lined commands in groovy.

http://www.groovy-lang.org/syntax.html#_string_concatenation

Triple single quoted strings are multiline. You can span the content of
the string across line boundaries without the need to split the string
in several pieces, without contatenation or newline escape characters:

def aMultilineString = '''line one
line two
line three'''
monty_bean
  • 494
  • 5
  • 25