JDK-8040822 : Duplicated notifications can be sent to TaskListener
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2014-04-17
  • Updated: 2014-07-29
  • Resolved: 2014-05-09
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u20Fixed 9 b14Fixed
Description
FULL PRODUCT VERSION :
java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]

A DESCRIPTION OF THE PROBLEM :
End of compilation stage analyze can be reported twice to listener implementing com.sun.source.util.TaskListener in some cases.

In the example annotation processor is modified to process TaskListener notifications and print information about events.

Annotation processor is used for compilation of two classes, one of which extends other. If extending class is mentioned first in command line additional notification about analyze stage completion is reported for other class.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Modify any annotation processor to process TaskListener  notifications:

public class Processor extends AbstractProcessor implements TaskListener {
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        JavacTask.instance(processingEnv).setTaskListener(this);
   }

    public void finished(TaskEvent event) {
        System.out.print(event.getKind());
        System.out.print(" - ");
        System.out.print(event.getTypeElement());
        System.out.print(" - ");
        System.out.println(Trees.instance(processingEnv).getPath(event.getTypeElement()));
    }

    public void started(TaskEvent arg0) {}
    ...
}

Create source files A.java and B.java:

public abstract class A {}
public class B extends A {} 

Compile using modified annotation processor:

javac -processorpath plugin.jar B.java A.java

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
ANNOTATION_PROCESSING_ROUND - null - null
ENTER - null - null
ENTER - null - null
ANNOTATION_PROCESSING_ROUND - null - null
ANNOTATION_PROCESSING - null - null
ENTER - null - null
ENTER - null - null
ANALYZE - B - com.sun.source.util.TreePath@5a61f5df
ANALYZE - A - com.sun.source.util.TreePath@52af6cff
GENERATE - B - null
GENERATE - A - null
ACTUAL -
ANNOTATION_PROCESSING_ROUND - null - null
ENTER - null - null
ENTER - null - null
ANNOTATION_PROCESSING_ROUND - null - null
ANNOTATION_PROCESSING - null - null
ENTER - null - null
ENTER - null - null
ANALYZE - B - com.sun.source.util.TreePath@5a61f5df
ANALYZE - A - com.sun.source.util.TreePath@52af6cff
GENERATE - B - null
ANALYZE - A - null
GENERATE - A - null

Note additional line "ANALYZE - A - null".

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
Annotation processor processor.java:
---------------------------
package test;

import java.util.Set;
import javax.annotation.processing.*;
import javax.lang.model.element.TypeElement;
import javax.lang.model.SourceVersion;
import com.sun.source.util.*;

@SupportedAnnotationTypes("*")
public class Processor extends AbstractProcessor implements TaskListener {

    boolean debug;

    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        JavacTask.instance(processingEnv).setTaskListener(this);
   }

    public boolean process(Set<? extends TypeElement> annotations,
            RoundEnvironment roundEnv) {
        return false;
    }

    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    public void finished(TaskEvent event) {
        System.out.print(event.getKind());
        System.out.print(" - ");
        System.out.print(event.getTypeElement());
        System.out.print(" - ");
        System.out.println(Trees.instance(processingEnv).getPath(event.getTypeElement()));
    }

    public void started(TaskEvent arg0) {}
}
---------------------------

A.java:
---------------------------
public abstract class A {} 
---------------------------

B.java:
---------------------------
public class B extends A {} 
---------------------------
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Receiver of notification can filter out duplicated notifications.