JDK-6499119 : Created package-info class file modeled improperly
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 6u1,7
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2006-11-30
  • Updated: 2012-03-22
  • Resolved: 2012-01-13
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 7
7 b84Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
CCC 6392177 introduced new capability for javax.annotation.processing.Filer interface. Filer has methods createSourceFile() and createClassFile(). The specification states that it is possible to create package entities:
--- Excerpt from the spec for createSourceFile() ---
           A source file can also be created to hold information about a package, including package annotations.
--- End of excerpt ---

--- Excerpt from the spec for for createClassFile() ---
           A class file can also be created to hold information about a package, including package annotations.
--- End of excerpt ---

The spec doesn't state that a package Element received by roundEnvironment.getRootElements() on next round of processing is exactly of PACKAGE element type without modifiers. However someone may suppose that it is implemented in that way since the preceding method getSpecifiedTypeElements() method of RoundEnvironment class returned a list of TypeElements while new method getRootElements() returns a list of Elements. Perhaps that this change was made to return PackageElement as a member of returned list.

In fact JDK 6 b104 works a bit ambiguously. While Filer.createSourceFile leads to passing PackageElement as root element in next round,
Filer.createClassFile creates a package class and Element given on next round of processing has package-info simple name, INTERFACE element type and ABSTRACT modifier. javap decompiler describes a package class as an interface with package-info name as well.

I believe that behavior should be described in the spec for Filer.createClassFile() more detailed.


The source java file to get package-info.class file is following:
---
@A package foo;

@interface A {}
---

You may reproduce the behavior using following processor class:

package jsr269;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.Filer;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.Element;
import javax.lang.model.SourceVersion;
import java.util.Set;
import java.util.HashSet;
import java.io.IOException;
import java.io.OutputStream;

public class ClassProcessor extends AbstractProcessor {
    int round = 1;
    int[] clazz = {
0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x32, 0x00, 0x09, 0x07, 0x00, 0x07, 0x07, 0x00, 0x08,
0x01, 0x00, 0x0A, 0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6C, 0x65, 0x01, 0x00, 0x11,
0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x2D, 0x69, 0x6E, 0x66, 0x6F, 0x2E, 0x6A, 0x61, 0x76,
0x61, 0x01, 0x00, 0x1B, 0x52, 0x75, 0x6E, 0x74, 0x69, 0x6D, 0x65, 0x49, 0x6E, 0x76, 0x69, 0x73,
0x69, 0x62, 0x6C, 0x65, 0x41, 0x6E, 0x6E, 0x6F, 0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x01,
0x00, 0x07, 0x4C, 0x66, 0x6F, 0x6F, 0x2F, 0x41, 0x3B, 0x01, 0x00, 0x10, 0x66, 0x6F, 0x6F, 0x2F,
0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x2D, 0x69, 0x6E, 0x66, 0x6F, 0x01, 0x00, 0x10, 0x6A,
0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F, 0x4F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x16,
0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00,
0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x06, 0x00,
0x00,
    };

    public Set<String> getSupportedAnnotationTypes() {
        return new HashSet<String>() {{add("*");}};
    }


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

    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (round == 1) {
            System.out.println("-- Round 1 --");
            createPackageClass();
        } else if (round == 2) {
            System.out.println("-- Round 2 --");
            for(Element e: roundEnv.getRootElements()) {
                System.out.println("ElementKind: " + e.getKind());
                System.out.println("Modifiers:   " + e.getModifiers());
                System.out.println("Annotations: " + e.getAnnotationMirrors());
            }
        }
        round++;
        return true;
    }

    private void createPackageClass() {
        Filer filer = processingEnv.getFiler();

        OutputStream out = null;
        try {
            out = filer.createClassFile("foo.package-info").openOutputStream();
            for(int ch: clazz) {
                out.write(ch);
            }
        } catch (IOException ioe) {
            System.out.println("Couldn't create package class file");
        } finally {
            if(out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    System.out.println("Writer closing is failed");
                }
            }
        }
    }
}


The processing may looks like following:
% javac.exe -cp . -processor jsr269.ClassProcessor java.lang.Object
-- Round 1 --
-- Round 2 --
ElementKind: INTERFACE
Modifiers:   [abstract]
Annotations: @foo.A

Comments
EVALUATION Yes. Need to detect and handle specially when generated classes are package-info
30-01-2010