Fix for a reflection issue with generic types.

git-svn-id: file:///humgen/gsa-scr1/gsa-engineering/svn_contents/trunk@3565 348d0f76-0448-11de-a6fe-93d51630548a
This commit is contained in:
kshakir 2010-06-16 15:58:38 +00:00
parent 7a91dbd490
commit c44fd05aa1
4 changed files with 29 additions and 15 deletions

View File

@ -27,8 +27,7 @@ package org.broadinstitute.sting.queue.util;
import java.lang.annotation.*;
/**
* Specifies the type of an input our output field.
* Retains it during runtime to work around type erasure.
* Specifies the type of an input or output field.
* Written in java because scala doesn't support RetentionPolicy.RUNTIME
*/
@Documented

View File

@ -1,10 +1,9 @@
package org.broadinstitute.sting.queue.function
import org.broadinstitute.sting.queue.util.{Input, Optional, ClassType}
import org.broadinstitute.sting.queue.util.{Input, Optional}
trait MemoryLimitedFunction {
@Input
@Optional
@ClassType(classOf[Int])
var memoryLimit: Option[Int] = None
}

View File

@ -1,7 +1,7 @@
package org.broadinstitute.sting.queue.function.gatk
import java.io.File
import org.broadinstitute.sting.queue.util.{ClassType, Input, Optional}
import org.broadinstitute.sting.queue.util.{Input, Optional}
import org.broadinstitute.sting.queue.function.{MemoryLimitedFunction, IntervalFunction, CommandLineFunction}
trait GatkFunction extends CommandLineFunction with MemoryLimitedFunction with IntervalFunction {
@ -17,7 +17,6 @@ trait GatkFunction extends CommandLineFunction with MemoryLimitedFunction with I
@Input
@Optional
@ClassType(classOf[File])
var bamFiles: List[File] = Nil
@Input

View File

@ -1,11 +1,11 @@
package org.broadinstitute.sting.queue.util
import java.lang.reflect.Field
import org.broadinstitute.sting.queue.QException
import java.lang.annotation.Annotation
import scala.concurrent.JavaConversions
import scala.concurrent.JavaConversions._
import scala.collection.immutable.ListMap
import java.lang.reflect.{ParameterizedType, Field}
object ReflectionUtils {
def getField(obj: AnyRef, name: String) = getAllFields(obj.getClass).find(_.getName == name)
@ -41,10 +41,7 @@ object ReflectionUtils {
if (classOf[Seq[_]].isAssignableFrom(field.getType)) {
if (!field.isAnnotationPresent(classOf[ClassType]))
throw new QException("@ClassType must be specified due to type erasure for field: " + field)
val fieldType = field.getAnnotation(classOf[ClassType]).asInstanceOf[ClassType].value
val fieldType = getCollectionType(field)
val typeValue = coerce(fieldType, value)
var list = getter.invoke(obj).asInstanceOf[Seq[_]]
@ -53,10 +50,7 @@ object ReflectionUtils {
} else if (classOf[Option[_]].isAssignableFrom(field.getType)) {
if (!field.isAnnotationPresent(classOf[ClassType]))
throw new QException("@ClassType must be specified due to type erasure for field: " + field)
val fieldType = field.getAnnotation(classOf[ClassType]).asInstanceOf[ClassType].value
val fieldType = getCollectionType(field)
val typeValue = coerce(fieldType, value)
setter.invoke(obj, Some(typeValue))
@ -70,6 +64,29 @@ object ReflectionUtils {
}
}
private def getCollectionType(field: Field) = {
getGenericTypes(field) match {
case Some(classes) =>
if (classes.length > 1)
throw new IllegalArgumentException("Field contains more than one generic type: " + field)
classes(0)
case None =>
if (!field.isAnnotationPresent(classOf[ClassType]))
throw new QException("@ClassType must be specified for unparameterized field: " + field)
field.getAnnotation(classOf[ClassType]).asInstanceOf[ClassType].value
}
}
private def getGenericTypes(field: Field) = {
// TODO: Refactor: based on java code in org.broadinstitute.sting.commandline.ArgumentTypeDescriptor
// If this is a parameterized collection, find the contained type. If blow up if only one type exists.
if (field.getGenericType.isInstanceOf[ParameterizedType]) {
val parameterizedType = field.getGenericType.asInstanceOf[ParameterizedType]
Some(parameterizedType.getActualTypeArguments.map(_.asInstanceOf[Class[_]]))
}
else None
}
private[util] def fieldGetter(field: Field) = field.getDeclaringClass.getMethod(field.getName)
private[util] def fieldSetter(field: Field) = field.getDeclaringClass.getMethod(field.getName+"_$eq", field.getType)