4

We started getting this error on our tests about a week ago. It has been on and off - sometimes people will get it and other times they won't.

/.../product/integration/src/test/java/com/acme/integration/code/CodeTestUtils.java:74: error: invalid use of @throws
         * @throws Exception if an error occurs.

I guess the error message is just a bit vague. Invalid how? The code looks OK to me:

    /**
     * Iterates to find modules and then calls
     * {@link #checkModule(Path, String, DirectoryStream.Filter, CheckFile)} for each.
     *
     * @param subPath the path within each module to start checks from.
     * @param filter the filter to apply to choose which files to check.
     * @param checkFile the checks to perform on each file.
     * @throws Exception if an error occurs.
     */
    public static void checkProject(String subPath, DirectoryStream.Filter<Path> filter, CheckFile checkFile) throws Exception
    {
        for (Path file : listFiles(EnvironmentUtils.getDevelopmentRoot().toPath()))
        {
            if (FileUtils.isDirectory(file) && FileUtils.exists(file.resolve("src/java")))
            {
                checkModule(file, subPath, filter, checkFile);
            }
        }
    }

We do turn on doclint during the compile because we want to find about about Javadoc errors without having to separately run Javadoc.

What exactly is this error supposed to mean? Is there anything invalid about what we're doing here? Are we looking at a compiler bug? Surely a bug like this would hit the first person who tried to declare that a method throws an exception... :(

The investigation so far...

  • I managed to cut the example down to a simple project which gives the same error. Aside from Travis CI being able to reproduce it on Linux, I can reproduce it here on macOS, starting today (no idea why this is time-dependent!) and other users on Windows have been talking about it for a couple days now.
  • From this project I looked at the command-line Gradle was using for javac and managed to get the same error to appear calling javac directly.
  • Cutting down the javac command-line further:

    javac -source 1.8 -target 1.8 -d build/classes/test \
      -classpath build/classes/main:build/resources/main:$HOME/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-core/2.8.2/979fc0cf8460302e4ffbfe38c1b66a99450b0bb7/log4j-core-2.8.2.jar:$HOME/.gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-api/2.8.2/e590eeb783348ce8ddef205b82127f9084d82bf3/log4j-api-2.8.2.jar \
      -Xdoclint:all,-missing \
      src/test/java/com/acme/CodeTestUtils.java
    

    This shows that the problem still occurs without Gradle in the picture. (Gradle had added -processorpath and -g too.)

eis
  • 51,991
  • 13
  • 150
  • 199
Hakanai
  • 12,010
  • 10
  • 62
  • 132
  • Well, there is an issue sending a `Exception` to start with, as you can't manage properly the exception since you can't know what exception it is really ( I see `Path`, so there will be `IOException`, maybe more in `checkModule`). So it should be at least a warning ;) As your real problem, have you notice any pattern about the user getting this error ? (OS, IDE encoding, JDK version ... ) I never get anything like this so I would bet on the file itself. – AxelH May 31 '17 at 05:18
  • Could not regenerate the issue with the same documentation as yours. – Amber Beriwal May 31 '17 at 05:38
  • We're now seeing it across both Windows and macOS and are waiting for our single Linux user to hit it. It seems like it started out with only one person seeing it but now multiple people can reproduce it. I've managed to cut my own example down further so that there is now only one test file and no actual code, and I still get the error when compiling the tests. – Hakanai May 31 '17 at 06:00
  • Linux does it too, added the link to the Travis CI build result. Nice. – Hakanai May 31 '17 at 06:22
  • @AmberBeriwal apparently Travis CI was able to reproduce it. I put a link to the build log in the main question. We also had a couple of different environments at work reproduce it off my cut-down example. – Hakanai May 31 '17 at 06:32
  • Can reproduce your problem. I tested with javac, javadoc and Maven, and it does not happen for your example, but for gradle it does. – eis May 31 '17 at 06:40
  • @eis Interesting. I got it to happen with javac, all I had to do was provide the exact same command-line Gradle provided. – Hakanai May 31 '17 at 06:41
  • @Trejkaz cool, might want to add that to your question or to the github repo. I did try a naive approach, didn't go through verifying the command line was identical. – eis May 31 '17 at 06:44
  • I can indeed reproduce the problem now with just `javac -classpath .;log4j-core-2.8.2.jar -Xdoclint:all,-missing com\acme\CodeTestUtils.java` and having those two files. (windows machine, as you see from separators) – eis Jun 01 '17 at 05:41
  • could you provide hint how to regenerate the problem? I downloaded your project and run `gradlew.bat build` but the problem didn't occur. I removed the log4j dependency as it was not being used. – Amber Beriwal Jun 01 '17 at 06:40
  • @AmberBeriwal put the log4j dependency back and try again. Or run the without_gradle.sh script instead of the gradle build. – Hakanai Jun 01 '17 at 06:49
  • @AmberBeriwal please re-read the thread; log4j dependency is key in reproducing the issue – eis Jun 01 '17 at 06:55

3 Answers3

3

I eventually filed a ticket against Log4j, figuring that even if it were a bug in javac, Oracle never fix the critical bugs we report anyway.

Evidently Log4j's custom annotation processing is somehow causing the problem - the comment in there suggested adding -proc:none to the javac command-line to turn off all annotation processing, and indeed, with annotation processing turned off, compilation now works!

Exactly why its annotation processor causes this is still a mystery. I read the code, but it didn't seem to modify any existing classes.

Hakanai
  • 12,010
  • 10
  • 62
  • 132
  • Annotation processors generally seem to be problematic, particularly when used with build tools which look at dependencies in order to do incremental builds. I have a project which uses JMH and I have to do a full rebuild every time i run mvn otherwise i get a "endPosTable already set" error. – jon hanson Jun 01 '17 at 14:11
  • @jon-hanson they're a bit interesting. I was under the impression that because I removed -processor-path, it wouldn't be putting it on the path for annotation processors, and had no idea that merely being on the compile classpath was enough to do some really evil stuff. Gives me new ideas for an evil class library. – Hakanai Jun 02 '17 at 01:52
2

According to the DocLint OpenJDK source code, this message is associated with a "dc.invalid.throws" property, and that property message is output as an error if you use a @throws tag either with a non-Exception type or if you use it on something other than a constructor or a method.

Neither of these seem to apply in your case. However I've seen a few people complain they get this message with inconsistent builds - the response is usually to do a full rebuild.

E.g. this Lucene Jira which relates to the same error message, the response is:

Those errors generally happen (especially on Solr's build), if there are outdated class files still in around output folder or if a previous compile run failed.

jon hanson
  • 8,722
  • 2
  • 37
  • 61
  • It's funny you mention that Lucene build. I had commented on there myself to ask whether they ever found anything about the underlying cause. The only other reference to the error I ever found was some other project which seemed to recommend turning off failures on error, but in their case it was coming from javadoc instead of javac, which could be a difference. – Hakanai May 31 '17 at 06:01
  • @Trejkaz My guess would be that this related to using Gradle. Perhaps it's not managing the dependencies correctly and is failing to recompile Java files. The code itself looks fine to me. – jon hanson May 31 '17 at 06:42
  • Gradle has now been ruled out. The only stuff involved is javac and a couple of log4j2 jars. Removing the log4j2 jars seems to avoid it, but if we did that in the real project we wouldn't be able to do any logging. XD – Hakanai May 31 '17 at 06:52
  • @Trejkaz Are there any package/class name clashes between log4j2 and anything in your project or its dependencies. Clutching at straws to be honest... – jon hanson May 31 '17 at 09:28
  • The example I posted includes only one library, log4j-core from log4j2. So I mean, it could be clashing... with itself... but if it is, maybe that's a bug in their stuff. – Hakanai May 31 '17 at 10:02
  • @Trejkaz If you create a similar project which just has the above method and the log4j dependency does the error still occur? – jon hanson May 31 '17 at 10:09
  • The GitHub project linked in the question has only the log4j dependency. It does have three methods which all show the error, but originally did have only one method, and of course showed it then too. I just added the two additional examples to show that it isn't just "@throws Exception". Apparently "@throws _anything_" is not OK. – Hakanai May 31 '17 at 23:04
1

I have duplicated this problem without Log4j. The project is at https://github.com/rgoers/LOG4J2-1925. From what I can tell it will occur with any annotation processor.

This bug has been filed with Oracle at http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8186647.

rgoers
  • 8,696
  • 1
  • 22
  • 24