Skip to content
Prev Previous commit
Next Next commit
Convert args in place when matching a method.
  • Loading branch information
Sun Rui committed Sep 9, 2015
commit adde91f3e4539249e1d0f94c722a386c7d24ec80
72 changes: 42 additions & 30 deletions core/src/main/scala/org/apache/spark/api/r/RBackendHandler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ private[r] class RBackendHandler(server: RBackend)
val methods = cls.getMethods
val selectedMethods = methods.filter(m => m.getName == methodName)
if (selectedMethods.length > 0) {
val (index, convertedArgs) = matchMethod(
val index = matchMethod(
selectedMethods.map(_.getParameterTypes),
args)

Expand All @@ -138,15 +138,15 @@ private[r] class RBackendHandler(server: RBackend)
throw new Exception(s"No matched method found for $cls.$methodName")
}

val ret = selectedMethods(index.get).invoke(obj, convertedArgs : _*)
val ret = selectedMethods(index.get).invoke(obj, args : _*)

// Write status bit
writeInt(dos, 0)
writeObject(dos, ret.asInstanceOf[AnyRef])
} else if (methodName == "<init>") {
// methodName should be "<init>" for constructor
val ctors = cls.getConstructors
val (index, convertedArgs) = matchMethod(
val index = matchMethod(
ctors.map(_.getParameterTypes),
args)

Expand All @@ -159,7 +159,7 @@ private[r] class RBackendHandler(server: RBackend)
throw new Exception(s"No matched constructor found for $cls")
}

val obj = ctors(index.get).newInstance(convertedArgs : _*)
val obj = ctors(index.get).newInstance(args : _*)

writeInt(dos, 0)
writeObject(dos, obj.asInstanceOf[AnyRef])
Expand All @@ -178,7 +178,7 @@ private[r] class RBackendHandler(server: RBackend)

// Read a number of arguments from the data input stream
def readArgs(numArgs: Int, dis: DataInputStream): Array[java.lang.Object] = {
(0 until numArgs).map { arg =>
(0 until numArgs).map { _ =>
readObject(dis)
}.toArray
}
Expand All @@ -187,54 +187,66 @@ private[r] class RBackendHandler(server: RBackend)
// according to the passed arguments. Arguments may be converted in
// order to match a method.
//
// Returns a two-element tuple. The first element is the index of
// the matched method in the list of the methods of the same name.
// The second element is the list of converted arguments.
// Returns an Option[Int] which is the index of the matched method in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does not return the found method directly, instead of index? Since we change the semantics of this function, we should also rename it, for example, findMethodByArgs ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In java reflection, constructors and normal methods are of different classes, and share no parent class that provides methods for reflection uses. I can't find a unified way to handle them in this function, so I have to pass in parameterTypes: Array[Array[Class[_]]] and return an index.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Maybe findMatchedSignature?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

// the list of the methods of the same name.
def matchMethod(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also document what the returned objects are for this method ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure. will add.

parameterTypesOfMethods: Array[Array[Class[_]]],
args: Array[Object]): (Option[Int], Array[Object]) = {
args: Array[Object]): Option[Int] = {
val numArgs = args.length

for (index <- 0 to parameterTypesOfMethods.length - 1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 until xxx

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

val parameterTypes = parameterTypesOfMethods(index)

if (parameterTypes.length == numArgs) {
val convertedArgs = new Array[Object](numArgs)
Array.copy(args, 0, convertedArgs, 0, numArgs)

var argMatched = true
var i = 0
while (i < numArgs && argMatched) {
val parameterType = parameterTypes(i)
var parameterWrapperType = parameterType

// Convert native parameters to Object types as args is Array[Object] here
if (parameterType.isPrimitive) {
parameterWrapperType = parameterType match {
case java.lang.Integer.TYPE => classOf[java.lang.Integer]
case java.lang.Long.TYPE => classOf[java.lang.Integer]
case java.lang.Double.TYPE => classOf[java.lang.Double]
case java.lang.Boolean.TYPE => classOf[java.lang.Boolean]
case _ => parameterType

if (parameterType == classOf[Seq[Any]] && args(i).getClass.isArray) {
// The case that the parameter type is a Scala Seq and the argument
// is a Java array is considered matching. The array will be converted
// to a Seq later if this method is matched.
} else {
var parameterWrapperType = parameterType

// Convert native parameters to Object types as args is Array[Object] here
if (parameterType.isPrimitive) {
parameterWrapperType = parameterType match {
case java.lang.Integer.TYPE => classOf[java.lang.Integer]
case java.lang.Long.TYPE => classOf[java.lang.Integer]
case java.lang.Double.TYPE => classOf[java.lang.Double]
case java.lang.Boolean.TYPE => classOf[java.lang.Boolean]
case _ => parameterType
}
}
if (!parameterWrapperType.isInstance(args(i))) {
argMatched = false
}
} else if (parameterType == classOf[Seq[Any]] && args(i).getClass.isArray) {
// Convert a Java array to scala Seq
convertedArgs(i) = args(i).asInstanceOf[Array[_]].toSeq
}
if (!parameterWrapperType.isInstance(convertedArgs(i))) {
argMatched = false
}

i = i + 1
}

if (argMatched) {
// For now, we return the first matching method.
// TODO: find best method in matching methods.
return (Some(index), convertedArgs)

// Convert args if needed
val parameterTypes = parameterTypesOfMethods(index)

(0 until numArgs).map { i =>
if (parameterTypes(i) == classOf[Seq[Any]] && args(i).getClass.isArray) {
// Convert a Java array to scala Seq
args(i) = args(i).asInstanceOf[Array[_]].toSeq
}
}

return Some(index)
}
}
}
(None, args)
None
}
}

Expand Down