How can I find the generic type of method parameter?

22 views
Skip to first unread message

Christian Vogel

unread,
Aug 15, 2016, 9:10:16 AM8/15/16
to Xtend Programming Language
I am trying to create an Active Annotation that takes methods in a class and wraps them with an operation.

My approach is like this:

def doTransform(MutableClassDeclaration cls, MethodDeclaration method, TypeReference originalCls, extension TransformationContext context) {

cls.addMethod(method.simpleName) [

val newMethod = it

static = method.static

final = method.final

varArgs = method.varArgs

visibility = method.visibility

deprecated = method.deprecated

docComment = method.docComment

exceptions = method.exceptions

synchronized = method.synchronized

returnType = method.returnType

val types = method.typeParameters.map [ newMethod.addTypeParameter(simpleName, upperBounds) ].toList

for(parameter : method.parameters) {

addParameter(parameter.simpleName, parameter.type)

}

body = ['''

«IF !method.returnType.isVoid»return «ENDIF»«originalCls.name».«method.simpleName»(«FOR parameter : method.parameters SEPARATOR ', '»«parameter.simpleName»«ENDFOR»);

''']

]

}


This works for normal methods, but not for generic ones.

For example, this code:

def static <IN> complete(IN from) {

new Deferred<IN, Boolean> => [

value(from, true)

]

}


Will be translated to this Java code:

  public static <IN extends Object> Deferred<?, Boolean> complete(final ? from) {

    return nl.kii.async.promise.PromiseExtensions.complete(from);

  }


Also, methods parameters that have generic types will not work:


def static <IN, OUT> Task start(Promise<IN, OUT> promise) {

promise.next

promise.asTask

}


Becomes:

  public static <IN extends Object, OUT extends Object> Task start(final Promise<?, ?> promise) {

    return nl.kii.async.promise.PromiseExtensions.start(promise);

  }


How can I also copy the generic types? I could not find any property in a parameter type to find if it is generic.

Christian Vogel

unread,
Aug 21, 2016, 7:09:12 AM8/21/16
to Xtend Programming Language
I found a solution:

First copy all generic type parameters from the method and storing them:

val newMethodTypeParams = originalMethod.typeParameters

.map [ newMethod.addTypeParameter(simpleName, upperBounds) ]

.toList


Then by converting each parameter and return type using this recursive static method:

def static TypeReference newGenericTypeReference(TypeReference originalType, List<MutableTypeParameterDeclaration> newMethodTypeParams, extension TransformationContext context) {

// is it a direct type reference?

val t = newMethodTypeParams.findFirst [ simpleName == originalType.simpleName ]

if(t != null) return t.newTypeReference

// try subtype reference

val subtypes = originalType.actualTypeArguments.map [ newGenericTypeReference(newMethodTypeParams, context) ]

originalType.type.newTypeReference(subtypes)

}


Doing so like this: 

for(parameter : originalMethod.parameters) {

addParameter(parameter.simpleName, parameter.type.newGenericTypeReference(newMethodTypeParams, context))

}


returnType = originalMethod.returnType.newGenericTypeReference(newMethodTypeParams, context)


It does require one 'cheat', since I found no way to see if a parameter type or return type is a direct generic type, I had to match the simpleName of the parameter with the name of the type. Not the most elegant solution. It would be better if a type could have a property isGenericType or something like that.

Christian Vogel

unread,
Aug 21, 2016, 7:48:25 AM8/21/16
to Xtend Programming Language
A small caveat, I forgot wildcard types, so I added a check for that:

def static TypeReference newGenericTypeReference(TypeReference originalType, List<MutableTypeParameterDeclaration> newMethodTypeParams, extension TransformationContext context) {

// is it a wildcard?

if(originalType.isWildCard) return originalType

Reply all
Reply to author
Forward
0 new messages