9

The following code in Groovy adds GStrings to the list:

List<String> args = [ 'cmd', "-Dopt=${value}" ]

When I create a ProcessBuilder with this list, I get a ClassCastException. What's a groovy way to coerce the list elements to the correct type?

Aaron Digulla
  • 297,790
  • 101
  • 558
  • 777
  • I added a comment about avoiding ProcessBuilder altogether to my answer (I am posting this incase you missed it)... It might save you some work :-) – tim_yates Jul 06 '11 at 08:04
  • One of my biggest peeves with Groovy is that it doesn't convert the type for you in this specific situation. The compiler knows the types, so it should be able to deal with this just as easily as if you'd assigned it to a String. :( – Trejkaz May 27 '19 at 01:24

3 Answers3

18

Or, you can do:

List<String> args = [ 'cmd', "-Dopt=${value}"] as String[]

or

List<String> args = [ 'cmd', "-Dopt=${value}"]*.toString()

actually, why are you using ProcessBuilder out of interest? Groovy adds ways to do process management, and even adds three execute methods to List

You can do (this is on OS X or Linux):

def opt = '-a'

println( [ 'ls', "$opt" ].execute( null, new File( '/tmp' ) ).text )

which prints out the files in my /tmp folder

tim_yates
  • 154,107
  • 23
  • 313
  • 320
  • Note that both do a bit too much work: The first one converts the initial `List` to a `String[]` and that back to a `List`, the second one creates a copy of the `List` as well and calls `toString()` on every element. – Joachim Sauer Jul 06 '11 at 07:26
  • 1
    @Joachim Yeah, but they both look cleaner (IMHO) than embedding `toString` inside the list on specific elements (and it makes it less likely that you missed an element) – tim_yates Jul 06 '11 at 07:37
  • very true. Also this is *highly* unlikely to be the critical element on any code-path. – Joachim Sauer Jul 06 '11 at 07:40
  • `ProcessBuilder` also accepts a `String[]` - so the first alternative can be replaced to be: `String[] args = [ 'cmd', "-Dopt=${value}"] as String[]` – RonK Jul 06 '11 at 08:13
  • Re `execute`: I need to call `redirectErrorStream()` but thanks for the suggestion. I could use it in a different place. – Aaron Digulla Jul 06 '11 at 08:24
  • 1
    @Aaron you can call `consumeProcessOutput(OutputStream output, OutputStream error)` on the [`Process`](http://groovy.codehaus.org/groovy-jdk/java/lang/Process.html) object returned by `execute()` – tim_yates Jul 06 '11 at 08:27
  • tim_yates: +1 but it's not 100% the same. For example, output and error are no longer in sync when I do it this way. – Aaron Digulla Jul 06 '11 at 14:50
2

Try

List<String> args = [ 'cmd', "-Dopt=${value}".toString() ]

because the later is a GString.

Joachim Sauer
  • 278,207
  • 54
  • 523
  • 586
Erich Kitzmueller
  • 34,314
  • 6
  • 72
  • 98
1

I did a test:

def value = "abc"
List<String> args = [ 'cmd', "-Dopt=${value}"];

System.out.println (args.getClass());

System.out.println (args.get(0).getClass());
System.out.println (args.get(1).getClass());

The output was:

class java.util.ArrayList
class java.lang.String
class org.codehaus.groovy.runtime.GStringImpl

Changing the code a bit to be:

def value = "abc"
List<String> args = [ 'cmd', "-Dopt=${value}".toString()];

System.out.println (args.getClass());

System.out.println (args.get(0).getClass());
System.out.println (args.get(1).getClass());

produced this:

class java.util.ArrayList
class java.lang.String
class java.lang.String

Should do the trick, but I'm not 100% sure this is the best way to do it.

RonK
  • 8,946
  • 7
  • 44
  • 82