Groovy default method parameters - groovy

How to call the below method def to pass only interactionId, transactionId, awResponseFile, testMethodName and expectedNumberOfConsumers?
method def
void verifyPersistence(String interactionId, String transactionId,
File rawResponseFile, String testMethodName,
int expectedNumberOfDatasourceProductResponseRaws=1,
String dsProductName=datasourceSpec['creditreport.name'],
int expectedNumberOfDatasourceProductResponses=1,
int expectedNumberOfConsumers=1,
int expectedNumberOfAddresses=1 )
method call
verifyPersistence interactionId.persistedVersion(), transactionId,
results, testName.methodName, expectedNumberOfConsumers:8
Exception
groovy.lang.MissingMethodException: No signature of method: verifyPersistence() is applicable for argument types: (java.util.LinkedHashMap, java.lang.String, java.lang.String, java.io.File, java.lang.String) values: [[expectedNumberOfConsumers:8], 3130001030065, 10003000000890059, C:\results, multiple consumers contracts]
Possible solutions:
verifyPersistence(java.lang.String, java.lang.String, java.io.File, java.lang.String),
verifyPersistence(java.lang.String, java.lang.String, java.io.File, java.lang.String, int),
verifyPersistence(java.lang.String, java.lang.String, java.io.File, java.lang.String, int, java.lang.String),
verifyPersistence(java.lang.String, java.lang.String, java.io.File, java.lang.String, int, java.lang.String, int), verifyPersistence(java.lang.String, java.lang.String, java.io.File, java.lang.String, int, java.lang.String, int, int)
at HitmultipleconsumersPersistSpec.groovy:151)

When you include a map entry (key:value), they get automatically collected, put into a hashmap and passed as the first parameter. Groovy, right now, doesn't have named parameters. For that specific case, i think you are better using a map for that method:
def verifyPersistence(Map map) {
String interactionId = map.interactionId
String transactionId = map.transactionId
File rawResponseFile = map.rawResponseFile
String testMethodName = map.testMethodName
int expectedNumberOfDatasourceProductResponseRaws = map.expectedNumberOfDatasourceProductResponseRaws ?: 1
String dsProductName = map.dsProductName ?: datasourceSpec['creditreport.name']
int expectedNumberOfDatasourceProductResponses = map.expectedNumberOfDatasourceProductResponses ?: 1
int expectedNumberOfConsumers = map.expectedNumberOfConsumers ?: 1
int expectedNumberOfAddresses = map.expectedNumberOfAddresses ?: 1
}
verifyPersistence(
interactionId : interactionId.persistedVersion(),
transactionId : transactionId,
rawResponseFile : results,
expectedNumberOfDatasourceProductResponseRaws : 14,
expectedNumberOfConsumers:8
)
You obviously don't need to assign every parameter to a variable, you can simply use the map.field syntax. If you want it to be type checked, then i think you are better using an object to encapsulate the parameters.

Related

How to invoke a kotlin function when given the function name as a string?

I'm making a project with many functions, each named prx, x being a number up to 200, is it possible to create a call from a string like this
var ="pr" + x
You can do this using reflection
class MyTestClass {
fun pr1(): Int = 5
fun pr2(value: Int) = value.toString()
}
class SomeOtherClass{
fun main(){
val myTestClassObj = MyTestClass()
// Find pr1 by name (function without arguments)
val pr1 = myTestClassObj::class.java.getMethod("pr1").kotlinFunction
// call pr1, pass class object as argument, used to call the function
val pr1Result = pr1?.call(myTestClassObj)
// Find function with arguments, pass function name and type of arguments
val pr2 = MyTestClass::class.java.getMethod("pr2", Int::class.java).kotlinFunction
// Call pr2, pass class reference and the function parameter
val pr2Result = pr2?.call(myTestClassObj, 100)
}
}
Be carefull when working with reflection, its easy to create untraceable bugs using it and often it is only a workaround for bad design.

Supplying context for Spark UDF execution

I am working in Scala programming language. I want to hash the entire column of dataframe with sha2 and salt. I have implemented the following UDF which should take MessageDigest and input string which will be hashed.
val md = MessageDigest.getInstance("SHA-256")
val random = new SecureRandom();
val salt: Array[Byte] = new Array[Byte](16)
random.nextBytes(salt)
md.update(salt)
dataFrame.withColumn("ColumnName", Sqlfunc(md, col("ColumnName")))
....some other code....
val HashValue: ((MessageDigest, String) => String) = (md: MessageDigest, input: String) =>
{
val hashedPassword: Array[Byte] = md.digest(input.getBytes(StandardCharsets.UTF_8))
val sb: StringBuilder = new StringBuilder
for (b <- hashedPassword) {sb.append(String.format("%02x", Byte.box(b)))}
sb.toString();
}
val Sqlfunc = udf(HashValue)
However the above code does not compile, because I dont know how to pass messageDigest to this function so I am running into following error
<<< ERROR!
java.lang.ClassCastException: com...................$$anonfun$9 cannot be cast to scala.Function1
Can someone tell me what am I doing wrong?
Also I am novice on cryptography so feel free to suggest anything you can. We have to use Sha2 and salt.
What do you think about the performance here?
Thanks
The MessageDigest is not in your data. It's just context for the UDF evaluation. This type of context is provided via closures.
There are many ways to achieve the desired effect. The following is a useful pattern that uses function currying:
object X extends Serializable {
import org.apache.spark.sql.expressions.UserDefinedFunction
import org.apache.spark.sql.functions.udf
def foo(context: String)(arg1: Int, arg2: Int): String =
context.slice(arg1, arg2)
def udfFoo(context: String): UserDefinedFunction =
udf(foo(context) _)
}
Trying it out:
spark.range(1).toDF
.select(X.udfFoo("Hello, there!")('id, 'id + 5))
.show(false)
generates
+-----------------+
|UDF(id, (id + 5))|
+-----------------+
|Hello |
+-----------------+

groovy.lang.MissingMethodException while trying to pass a closure as a parameter

I am new to groovy and am trying to pass a closure as a parameter to a method , below is my code , I am using Groovy 2.4
class Test
{
def testMethod()
{
def cl = {a,b -> println "a = "+${a}+" b = "+${b}}
testClosure(cl);
}
def testClosure(closure)
{
closure(5,2);
}
}
I am getting the below exception when i am trying to execute it ,
Caught: groovy.lang.MissingMethodException: No signature of method:
com.gr.practice.Test.$() is applicable for argument types:
(com.gr.practice.Test$_testMethod_closure1$_closure2) values:
[com.gr.practice.Test$_testMethod_closure1$_closure2#3e92efc3]
Possible solutions:
is(java.lang.Object),
any(),
any(groovy.lang.Closure),
use([Ljava.lang.Object;),
wait(),
dump()
groovy.lang.MissingMethodException: No signature of method:
com.gr.practice.Test.$() is applicable for argument types:
(com.gr.practice.Test$_testMethod_closure1$_closure2) values:
[com.gr.practice.Test$_testMethod_closure1$_closure2#3e92efc3]
Possible solutions:
is(java.lang.Object),
any(),
any(groovy.lang.Closure),
use([Ljava.lang.Object;),
wait(),
dump()
at com.gr.practice.Test$_testMethod_closure1.doCall(Test.groovy:10)
at com.gr.practice.Test.testClosure(Test.groovy:16)
at com.gr.practice.Test$testClosure$0.callCurrent(Unknown Source)
at com.gr.practice.Test.testMethod(Test.groovy:11)
at com.gr.practice.Test$testMethod.call(Unknown Source)
at com.gr.practice.main.run(main.groovy:7)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Could anyone please help ?
Your problem is println "a = "+${a}+" b = "+${b}. You probably want this:
println "a = ${a} b = ${b}"
Or:
println "a = " + a + " b = " + b
(the former is a better idea)

java.lang.IllegalArgumentException: wrong number of arguments at javax.faces.component.UIComponentBase.isRendered [duplicate]

I'm using JSF 2.
I have a method that checks for matching values from a list of values:
#ManagedBean(name="webUtilMB")
#ApplicationScoped
public class WebUtilManagedBean implements Serializable{ ...
public static boolean isValueIn(Integer value, Integer ... options){
if(value != null){
for(Integer option: options){
if(option.equals(value)){
return true;
}
}
}
return false;
}
...
}
To call this method in EL I tried:
#{webUtilMB.isValueIn(OtherBean.category.id, 2,3,5)}
But it gave me a:
SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http-localhost/127.0.0.1:8080-5) java.lang.IllegalArgumentException: wrong number of arguments
Is there a way to execute such a method from EL?
No, it is not possible to use variable arguments in EL method expressions, let alone EL functions.
Your best bet is to create multiple different named methods with a different amount of fixed arguments.
public static boolean isValueIn2(Integer value, Integer option1, Integer option2) {}
public static boolean isValueIn3(Integer value, Integer option1, Integer option2, Integer option3) {}
public static boolean isValueIn4(Integer value, Integer option1, Integer option2, Integer option3, Integer option4) {}
// ...
As a dubious alternative, you could pass a commaseparated string and split it inside the method
#{webUtilMB.isValueIn(OtherBean.category.id, '2,3,5')}
or even a string array which is created by fn:split() on a commaseparated string
#{webUtilMB.isValueIn(OtherBean.category.id, fn:split('2,3,5', ','))}
but either way, you'd still need to parse them as integer, or to convert the passed-in integer to string.
In case you're already on EL 3.0, you could also use the new EL 3.0 collection syntax without the need for the whole EL function.
#{[2,3,5].contains(OtherBean.category.id)}

JSR-303 bean validation with Groovy traits (Hibernate Validator)

I run into a problem with JSR-303 bean validation with a Groovy class that implements Traits with additional fields (plus their constraints). Let me show you a simple example. I have a class called ClientInfo which looks like this:
class ClientInfo implements AddressInfo, ContactInfo, BusinessEntity { }
It implements 3 traits that provides additional information. AddressInfo may look like this:
trait AddressInfo {
#Size(max = 128)
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE)
String contactName
#Size(max = 255)
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE)
String addressLine1
#Size(max = 255)
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE)
String addressLine2
#Size(max = 32)
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE)
String postalCode
#Size(max = 64)
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE)
String city
#Size(max = 3)
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE)
String countryCode
}
So far everything looks good. The problem shows up when the constraint validation fails. For example, if countryCode field fails during ClientInfo instance validation, it holds error message under the AddressInfo__countryCode field name:
{"AddressInfo__countryCode":"size must be between 0 and 3"}
It is caused by the fact that the fields that come from the trait are compiled into e.g. AddressInfo__countryCode, AddressInfo__addressLine1 and so one, providing getters and setters for those fields.
I tried to use Jackson annotations like #JsonProperty('countryCode') over the countryCode field in the AddressInfo trait, but it didn't help (the annotation was added to compiled class).
My question is: is it possible to use e.g. Jackson property mappers to render field names provided in #JsonProperty('...') annotation for the fields provided by implemented trait? I will really appreciate your help.
PS: I'm using 'org.hibernate:hibernate-validator:5.1.3.Final' bean validation implementation (maybe this one should be change).

Resources