Annotation processing question: Is there a way to...
# announcements
b
Annotation processing question: Is there a way to preserve variable names (in particular, method parameter names) when compiling kotlin so the annotation processor can pull the original name out of the .class files?
d
You can either use the Kotlin reflection API (
KParameter.name
) or you can tell the compiler to also generate the parameter metadata for the Java reflection API (
Parameter.getName
) using
javaParameters = true
inside
kotlinOptions
of your
build.gradle
.
Actually, never mind the reflection part, since you are using the annotation processor API, you need the latter option (generate Java compatible parameter names).
b
yeah, so javaParameters=true sounds promising. What's the equivalent place to plop that in a maven pom?
b
Thanks!
Ok so I've been playing with this and I'm still not seeing actual parameter names. This is my kotlin compiler configuration: <plugin> <artifactId>kotlin-maven-plugin</artifactId> <groupId>org.jetbrains.kotlin</groupId> <version>${kotlin.version}</version> <configuration> <javaParameters>true</javaParameters> </configuration> <executions> <execution> <id>compile</id> <phase>process-sources</phase> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>test-compile</id> <phase>process-test-sources</phase> <goals> <goal>test-compile</goal> </goals> </execution> </executions> </plugin>
Is there something special I need to do within the annotation processing code to fetch the original name?
@diesieben07
d
You shouldn't have to. What are you doing currently to retrieve them? Also have you checked the .class files (e.g. with javap) to see if they contain the parameters?
b
I use VariableElement.getSimpleName().toString()
it's coming back as arg0
(etc)
d
Yeah, that should work. What does javap say?
b
I don't think I've ever used javap directly, but I do see names on params if I open a .class file in intellij now
I mean, I wrote up a method that will give a "sane default" based on the @RequestHeader.value and @RequestParam.value fields, but that's not ideal
Running the debugger I see there's a savedParameterNames List on the method that does contain the necessary info, but it's only available if I either cast the ExecutableElement to a Symbol.methodSymbol or dig into it using reflection. Where it's not available is on VariableElement.getSimpleName(). Playing around I did figure out I could directly assign one to the other in the debugger code evaluator but it's pretty ugly
d
That sounds like a problem with the annotation processor API then. Does it work with a Java-generated class?
b
I don't know - for java I'm working directly with the source code, I've never had to run it over the .class files
d
Right. The annotation processor API probably cannot read the parameter names from the class files for some reason. You either have to hack into the internals like you did or you parse the class file yourself using ASM.
b
Yeah I don't want to go that far, that sounds painful. Maybe something to file a bug report about I guess
Here's what I ended up doing - Tracking down in the debugger, I figured out I could just change the name field to the saved parameter names. It's a little ugly, but I'm running in a separate compile phase so no side effects to worry about private void attemptToReflectivelyRecoverMethodParameterNamesIfNeeded(ExecutableElement method) { try { List<String> savedParameterNames = (List<String>) method.getClass().getDeclaredField("savedParameterNames").get(method); //No savedParameters if (CollectionUtils.isEmpty(savedParameterNames)) { return; } List<? extends VariableElement> params = method.getParameters(); IntStream.range(0, params.size()).forEach(idx -> { VariableElement param = params.get(idx); if(param.getSimpleName().toString().matches("arg[0-9]+")) { try { param.getClass().getField("name").set(param, savedParameterNames.get(idx)); } catch (Exception e) { throw new RuntimeException("Exception setting param", e); } } }); } catch (Exception e) { processingEnv.getMessager().printMessage(Kind.WARNING, Util.getFormattedStackTrace(e)); } }