From 1ce57efb122133a744270ac31ba8d8df7288c3a9 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Mon, 10 Jul 2017 23:24:42 -0400 Subject: [PATCH] Initial commit with full minimal test case --- ParameterPrintingProcessor.java | 41 +++++++++++++++++++++++++++++++++ Person.java | 3 +++ PersonDao.java | 6 +++++ readme.md | 31 +++++++++++++++++++++++++ show_bug.sh | 30 ++++++++++++++++++++++++ 5 files changed, 111 insertions(+) create mode 100644 ParameterPrintingProcessor.java create mode 100644 Person.java create mode 100644 PersonDao.java create mode 100644 readme.md create mode 100755 show_bug.sh diff --git a/ParameterPrintingProcessor.java b/ParameterPrintingProcessor.java new file mode 100644 index 0000000..c9ebd8d --- /dev/null +++ b/ParameterPrintingProcessor.java @@ -0,0 +1,41 @@ +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.*; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.tools.Diagnostic; +import java.util.List; +import java.util.Set; + +@SupportedAnnotationTypes("javax.annotation.processing.SupportedSourceVersion") +public class ParameterPrintingProcessor extends AbstractProcessor { + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + + @Override + public boolean process(final Set annotations, final RoundEnvironment roundEnv) { + if (annotations.isEmpty() || roundEnv.processingOver()) + return false; // done + for (final Element element : roundEnv.getElementsAnnotatedWith(SupportedSourceVersion.class)) { + for(final Element method : ((TypeElement) element).getEnclosedElements()) { + if(method.getKind() != ElementKind.METHOD) + continue; + final TypeMirror returnType = ((ExecutableElement)method).getReturnType(); + if(returnType.getKind() != TypeKind.DECLARED) + continue; + final List methodsAndConstructors = ((TypeElement) ((DeclaredType) returnType).asElement()).getEnclosedElements(); + processingEnv.getMessager().printMessage(Diagnostic.Kind.MANDATORY_WARNING, + methodsAndConstructors.stream().filter(e -> e.getKind() == ElementKind.CONSTRUCTOR && e.getModifiers().contains(Modifier.PUBLIC)).map(e -> e.toString() + + ": '" + ((ExecutableElement) e).getParameters().stream().map(param -> param.asType() + " " + param.getSimpleName().toString()).collect(java.util.stream.Collectors.joining(", ")) + "'" + ).collect(java.util.stream.Collectors.joining(", "))); + } + } + return false; + } +} diff --git a/Person.java b/Person.java new file mode 100644 index 0000000..b7ee4f4 --- /dev/null +++ b/Person.java @@ -0,0 +1,3 @@ +public class Person { + public Person(long personNo, java.util.Date birthDate, String firstName, String lastName) {} +} \ No newline at end of file diff --git a/PersonDao.java b/PersonDao.java new file mode 100644 index 0000000..9dc6b93 --- /dev/null +++ b/PersonDao.java @@ -0,0 +1,6 @@ +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +@SupportedSourceVersion(SourceVersion.RELEASE_0) +public interface PersonDao { + Person getPerson(); +} \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..854f4f3 --- /dev/null +++ b/readme.md @@ -0,0 +1,31 @@ +JDK-8184051 : jdk8 -parameters breaks annotation processor parameter names +---------------------------------------------------------------------- + +This is the test case showing the broken javac behavior reported in [JDK-8184051](http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8184051) + + $ ./show_bug.sh + javac 1.8.0_131 + these are the correct argument names, compiled with and without -parameters argument, compiling both classes in a single invocation: + warning: Person(long,java.util.Date,java.lang.String,java.lang.String): 'long personNo, java.util.Date birthDate, java.lang.String firstName, java.lang.String lastName' + warning: Person(long,java.util.Date,java.lang.String,java.lang.String): 'long personNo, java.util.Date birthDate, java.lang.String firstName, java.lang.String lastName' + + this shows expected missing parameter names when compiled in 2 steps, like in the case of libraries or multiple module projects, without -parameters: + warning: Person(long,java.util.Date,java.lang.String,java.lang.String): 'long arg0, java.util.Date arg1, java.lang.String arg2, java.lang.String arg3' + + and finally the bug, same two step compilation as above, but -parameters passed into first step, shows shifted/incorrect parameter names: + warning: Person(long,java.util.Date,java.lang.String,java.lang.String): 'long personNo, java.util.Date firstName, java.lang.String lastName, java.lang.String arg3' + +This was discovered by Travis Burtrum on June 19th, 2017, when writing test cases for [JdbcMapper](https://code.moparisthebest.com/moparisthebest/JdbcMapper/src/68c1c0482e56c1a2a3ea842a6a71fea3e4444738/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/CompileTimeRowToObjectMapper.java#L88) + +it looks like the bug currently doesn't affect javac 9b177: + + javac 9 + these are the correct argument names, compiled with and without -parameters argument, compiling both classes in a single invocation: + warning: Person(long,java.util.Date,java.lang.String,java.lang.String): 'long personNo, java.util.Date birthDate, java.lang.String firstName, java.lang.String lastName' + warning: Person(long,java.util.Date,java.lang.String,java.lang.String): 'long personNo, java.util.Date birthDate, java.lang.String firstName, java.lang.String lastName' + + this shows expected missing parameter names when compiled in 2 steps, like in the case of libraries or multiple module projects, without -parameters: + warning: Person(long,java.util.Date,java.lang.String,java.lang.String): 'long arg0, java.util.Date arg1, java.lang.String arg2, java.lang.String arg3' + + and finally the bug, same two step compilation as above, but -parameters passed into first step, shows shifted/incorrect parameter names: + warning: Person(long,java.util.Date,java.lang.String,java.lang.String): 'long personNo, java.util.Date birthDate, java.lang.String firstName, java.lang.String lastName' diff --git a/show_bug.sh b/show_bug.sh new file mode 100755 index 0000000..eb5e689 --- /dev/null +++ b/show_bug.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# delete all classes +rm -f *.class + +javac -version 2>&1 + +# compile our annotation processor once +javac ParameterPrintingProcessor.java + +echo 'these are the correct argument names, compiled with and without -parameters argument, compiling both classes in a single invocation:' +javac -parameters -processor ParameterPrintingProcessor Person.java PersonDao.java 2>&1 | head -n1 +rm Person.class PersonDao.class +javac -processor ParameterPrintingProcessor Person.java PersonDao.java 2>&1 | head -n1 + +echo +echo 'this shows expected missing parameter names when compiled in 2 steps, like in the case of libraries or multiple module projects, without -parameters:' +rm Person.class PersonDao.class +javac Person.java +javac -processor ParameterPrintingProcessor PersonDao.java 2>&1 | head -n1 + +echo +echo 'and finally the bug, same two step compilation as above, but -parameters passed into first step, shows shifted/incorrect parameter names:' +rm Person.class PersonDao.class +javac -parameters Person.java +# below is the actual invocation of javac where the bug lives, somehow reads saved parameter names from step above incorrectly +# they are saved correctly above, because you can read them at runtime correctly +javac -processor ParameterPrintingProcessor PersonDao.java 2>&1 | head -n1 + +# clean up by deleting all classes +rm -f *.class