Groovy how to multi line GStrings for exception messages - groovy

What is the standard (or best practice) for Groovy error messages that that shouldn't span over a certain number of characters/line, e.g., 80 characters?
Consider the following (which is working fine)
throw new IOException("""\
A Jenkins configuration for the given version control
system (${vcs.name}) does not exist."""
.stripIndent()
.replaceAll('\n', ' '))
This will result in a one-line error message with no indention characters (what I want). But is there some other way ("the Groovy way of doing it") how to achieve this? If not, how could you add such a method to the GString class in a standalone Groovy application (if found hints regarding a Bootstrap.groovy file but it seems to be related to Grails)?
Example: """Consider a multi line string as shown above""".toSingleLine()

You could use the String continuation character then strip multiple spaces:
throw new IOException( "A Jenkins configuration for the given version control \
system (${vcs.name}) does not exist.".replaceAll( /( )\1+/, '$1' ) )
Or you could wrap this in a function and add it to the String.metaClass as I believe the answers you've seen point to.
You're right in thinking that Bootstrap.groovy is a Grails thing, but if you just set the metaClass early on in your applications lifecycle, you should get the same result...
String.metaClass.stripRepeatedWhitespace = { delegate.replaceAll( /( )\1+/, '$1' ) }
In saying all this however, I'd probably just keep the message on a single line

Related

Call groovy script dynamically in Apache Camel using doTry-doCatch

I'm building a route which calls a groovy script whose path is dynamically computed and, if the script can't be found, defaults to a generic, static script:
.doTry()
.toD("language://groovy:resource:classpath:scripts/${exchangeProperty.consumerType}ResponseHandler.groovy")
.doCatch(FileNotFoundException.class)
.script().groovy("resource:classpath:scripts/defaultResponseHandler.groovy")
.end()
The problem is that the exchange property consumerType is not resolved since the uri string parameter of toD is evaluated using groovy and not simple.
MultipleCompilationErrorsException -> startup failed:
Script_09b4150584d9e2c979353feee06897b5.groovy: 1: Unexpected input: 'scripts/${exchangeProperty.consumerType}' # line 1, column 20.
resource:classpath:scripts/${exchangeProperty.consumerType}ResponseHandler.groovy
^
1 error
How can I obtain the desired behavior?
According to the error shown there, it seems Camel is not able to resolve the string you provided in the toD().
By default, the expression you pass to a dynamic to is evaluated as Simple language but, as described in To Dynamic Camel documentation, you can specify other languages for the dynamic evaluation.
In your case, you are trying to evaluate the endpoint with groovy language but then you're using Simple language to substitute a piece of the name of the script.
One solution I've found (yet not the best) would be to specify the language for the interpretation of the string as simple and then use language:groovy to specify the endpoint that will need to be called.
You could write something like this:
.doTry()
.toD("language:simple:language://groovy:resource:classpath:scripts/${exchangeProperty.consumerType}ResponseHandler.groovy")
.doCatch(FileNotFoundException.class)
.script().groovy("resource:classpath:scripts/defaultResponseHandler.groovy")
.end()
It seems to work, but I hope someone else comes up with a better solution.

What $() syntax means for Groovy language?

I found this in Groovy Syntax documentation at 4.6.1. Special cases:
As slashy strings were mostly designed to make regexp easier so a few
things that are errors in GStrings like $() or $5 will work with
slashy strings.
What $() syntax means? give some usage examples please
I also found it at Define the Contract Locally in the Repository of the Fraud Detection Service:
body([ // (4)
"client.id": $(regex('[0-9]{10}')),
loanAmount : 99999
])
but I don't understand what $() means when used with regex('[0-9]{10}').
It means nothing (or what you make of it). There are two places, you
are addressing, but they have nothing to do with each other.
The docs just mention this as "you can use slashy strings to write
things, that would give you an error with a GString" - the same is true
for just using '-Strings.
E.g.
"hello $()"
Gives this error:
unknown recognition error type: groovyjarjarantlr4.v4.runtime.LexerNoViableAltException
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
/tmp/x.groovy: 1: token recognition error at: '(' # line 1, column 9.
"hello $()"
The parser either wants a { or any char, that is a valid first char
for a variable (neither ( nor 5 is).
The other place you encountered $() (in Spring cloud contract), this
is just a function with the name $.
Form the docs 8. Contract DSL:
You can set the properties inside the body either with the value method or, if you use the Groovy map notation, with $()
So this is just a function, with a very short name.
E.g. you can try this yourself:
void $(x) { println x }
$("Hello")

Can ArchUnit check for certain string patterns in method calls?

In our code we again and again have the issue that somebody forgot to adapt the usage of placeholders when switching between the use of the logger and String.format(...) methods.
For log statements one has to use '{}' as placeholders, like so:
logger.info("File {} successfully opened: {} bytes read, {} objects created", file, nrBytes, nrObjects);
But when using String.format(...) to compose a message one has to use '%s' as placeholders for strings and the statement has to read:
logger.info(String.format("File %s successfully opened: %s bytes read, %s objects created", file, nrBytes, nrObjects));
The second form is often used, when logging an error where the second argument is the Throwable that one wants to log.
Too often people forget about this details and then we end up with wrong log statements that output nothing reasonable.
I know and agree that this is absolutely not an architecture issue but rather a simple programming error, but it would be great if one could (ab-)use ArchUnit to check for the use of '%s' (or the absence of '{}') in the first String argument of the String.format()-method. Is something like that possible?
The ArchUnit, currently in version 0.16.0, does not analyze parameter values for method calls.
The sonar rule "Printf-style format strings should be used correctly" might however catch these bugs.
As already noted ArchUnit can't do this - PMD's [invalidlogmessageformat][1] rule is useful though (and I find PMD easier to deal with than sonar).

Why can't groovy deal with curly braces?

In an Android Studio (and presumably ANY) gradle file, the following code works:
task build {
}
And one minor change causes a complete meltdown:
task build
{
}
This has come up in other threads before, but in the context of fixing the build files. My question is why can't gradle/groovy be made to deal with either bracing style? Many other languages cope just fine with it, so what's the big deal here?
It's actually all right there in the error message:
build file '.../build.gradle': 80: Ambiguous expression could be a parameterless closure expression, an isolated open code block, or it may continue a previous statement;
solution: Add an explicit parameter list, e.g. {it -> ...}, or force it to be treated as an open block by giving it a label, e.g. L:{...}, and also either remove the previous newline, or add an explicit semicolon ';' # line 80, column 1.
Because of a Groovy syntax sugar to make methods with a lambda as the last parameter look line language constructs, the following code blocks:
task build {}
task build2(type: Copy) {}
are equal to their more regular form:
task build({})
task build(type: Copy, {})
Now, you do not really want those curly braces there to delimit a regular code block, but a Groovy lambda, which should be passed as a parameter to the build method.
Yet from the looks of it, Groovy can't really decide if it really is a lambda being passed as a parameter to the method in the previous line or an unrelated code block when you put a newline in between. And there you go, an ambiguousness as described in the error message, right there.
Following the advice in the error message, you can also use the following syntax instead of the one where you are escaping the new-line character:
task build
{ ->
}
Finally, the task keyword used to invoke the dynamic method (named build in your example) is not Groovy specific, but a Gradle DSL feature.
In case anyone reading this is wondering, the work-around is simple enough.
task build \
{
}
I was just wondering as to the "why"...

String.Contains doesn't work on web exception because it has a small dots between the words

I am checking if a web exception message contains a string I have.
My string is: "The remote name could not be resolved"
The web exception message is:"The remote name could not be resolved:"
You would expect it to work, but if you copy-paste and enlarge the web exception here you will notice tiny dots between every word.
Those dots apparently ruins the contains function I use.
If exWeb.Message.Contains("The remote name could not be resolved") Then
'Do something...
End If
How can I compare those strings without the dots or ignore the dots or any other solution?
Relying on the message string isn't very future proof, as the framework developers may decide to change the message in the future for various reasons (to make it more explanatory, change grammar .etc.) or your code could be running in a different locale with a different language causing the error message to be different.
I suggest you check the Status property instead.
See the documentation of the Enum. I think you're looking for a WebException with a Status of NameResolutionFailure
https://msdn.microsoft.com/en-us/library/system.net.webexceptionstatus(v=vs.110).aspx

Resources