JDK-8181201 : Retrieve FileObject from Element feature request
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: javax.lang.model
  • Affected Version: 8,9
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2017-05-29
  • Updated: 2021-08-04
  • Resolved: 2021-08-04
Related Reports
Duplicate :  
Description
A DESCRIPTION OF THE REQUEST :
During annotation processing, given an Element instance, one cannot retrieve the corresponding FileObject in which the Element resides. May it be a source file, or class file.

JUSTIFICATION :
The annotation processor can collect different information based on the file in which the Element resides. This information can be useful for further examination, or to implement incremental build features to the Java Compiler.
This feature can be implemented in the javax.lang.model.util.Elements interface, adding a method which returns with the enclosing FileObject.
FileObject getEnclosingFile(Element element);
As the Elements documentation says: "Compatibility Note: Methods may be added to this interface in future releases of the platform.", this method can be an acceptable feature, while not taking implementations by surprise.
The implementation of this feature should traverse the element tree to the topmost TypeElement, and return with it's enclosing FileObject. The Java Compiler API already has this internal information, in the class com.sun.tools.javac.code.Symbol$ClassSymbol in the fields 'classfile' and 'sourcefile'. (JDK 1.8.0_121)
The returned file can also be a JavaFileObject.
The returned FileObject might or might not enable all the features it's interface provides, e.g. delete() could return false.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
javax.lang.module.util.Elements interface should declare a method that retrieves the FileObject corresponding to the Element parameter.
ACTUAL -
No such functionality exists.

---------- BEGIN SOURCE ----------
package bence.sipka.compiler.java.test;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.annotation.processing.Completion;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.tools.FileObject;

public class ElementTestProcessor implements Processor {

	@Override
	public Set<String> getSupportedOptions() {
		return Collections.emptySet();
	}

	@Override
	public Set<String> getSupportedAnnotationTypes() {
		HashSet<String> result = new HashSet<>();
		result.add("*");
		return result;
	}

	@Override
	public SourceVersion getSupportedSourceVersion() {
		return SourceVersion.latest();
	}

	private Elements elements;

	@Override
	public void init(ProcessingEnvironment processingEnv) {
		this.elements = processingEnv.getElementUtils();
	}

	@Override
	public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
		for (Element elem : roundEnv.getRootElements()) {
			FileObject file = elements.getEnclosingFile(elem);
			// consume information from file...
		}
		return false;
	}

	@Override
	public Iterable<? extends Completion> getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) {
		return Collections.emptyList();
	}

}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Through internal Java Compiler API, casting to ClassSymbol and accessing public field.