Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 324931

Summary: Annotations: static fields are allowed - different to javac
Product: [Eclipse Project] JDT Reporter: Andrey Loskutov <loskutov>
Component: CoreAssignee: Srikanth Sankaran <srikanth_sankaran>
Status: VERIFIED NOT_ECLIPSE QA Contact: Srikanth Sankaran <srikanth_sankaran>
Severity: major    
Priority: P3 CC: amj87.iitr, jarthana
Version: 3.6   
Target Milestone: 3.8 M5   
Hardware: PC   
OS: Linux   
Whiteboard:
Attachments:
Description Flags
Project with ant build file and class files generated by javac
none
Bytecode diff for ejc/javac code none

Description Andrey Loskutov CLA 2010-09-10 04:51:42 EDT
Tested with Eclipse 3.6.0 / sun JDK 1.6.0_20 on Linux x86_64.

The annotation below and another class using it compiles without any warning as Eclipse project with ejc but does NOT compile at all with javac.

The problem seems to be the definition of static fields inside the annotation, for which ejc creates <cinit> method, but javac doesn't.

javac reports:

     [echo] compiling findbugs
    [javac] Compiling 1053 source files to /home/andrei/workspace/findbugs/build/classes
    [javac] /home/andrei/workspace/findbugs/src/java/edu/umd/cs/findbugs/util/ClassName.java:38: annotation edu.umd.cs.findbugs.internalAnnotations.SlashedClassName is missing <clinit>
    [javac] 	public static String toSignature(@SlashedClassName String className) {
    [javac] 	                                 ^
    [javac] /home/andrei/workspace/findbugs/src/java/edu/umd/cs/findbugs/util/ClassName.java:46: annotation edu.umd.cs.findbugs.internalAnnotations.SlashedClassName is missing <clinit>
    [javac] 	public static @CheckForNull @SlashedClassName String fromFieldSignature(String signature) {
    [javac] 	                            ^
    [javac] /home/andrei/workspace/findbugs/src/java/edu/umd/cs/findbugs/util/ClassName.java:84: annotation edu.umd.cs.findbugs.internalAnnotations.SlashedClassName is missing <clinit>
    [javac] 			@SlashedClassName(when=When.UNKNOWN) String className) {
    [javac] 			^
    [javac] /home/andrei/workspace/findbugs/src/java/edu/umd/cs/findbugs/util/ClassName.java:83: annotation edu.umd.cs.findbugs.internalAnnotations.SlashedClassName is missing <clinit>
    [javac] 	public static @SlashedClassName String toSlashedClassName(
    [javac] 	              ^
    [javac] /home/andrei/workspace/findbugs/src/java/edu/umd/cs/findbugs/util/ClassName.java:99: annotation edu.umd.cs.findbugs.internalAnnotations.SlashedClassName is missing <clinit>
    [javac] 	public static @DottedClassName String toDottedClassName(@SlashedClassName(when=When.UNKNOWN) String className) {
    [javac] 	                                                        ^
    [javac] /home/andrei/workspace/findbugs/src/java/edu/umd/cs/findbugs/util/ClassName.java:164: annotation edu.umd.cs.findbugs.internalAnnotations.SlashedClassName is missing <clinit>
    [javac] 	public static @SlashedClassName String extractClassName(String originalName) {
    [javac] 	


Original code:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import javax.annotation.RegEx;
import javax.annotation.meta.TypeQualifier;
import javax.annotation.meta.TypeQualifierValidator;
import javax.annotation.meta.When;

/**
 * * Denotes a class name or package name where the / character is used to separate package/class name components. 
 * @author pugh
 */
@Documented
@TypeQualifier(applicableTo=CharSequence.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface SlashedClassName {
	final static String simpleName = "(\\p{javaJavaIdentifierStart}(\\p{javaJavaIdentifierPart}|\\$)*)";
	final static String slashedClassName = simpleName + "(/" + simpleName +")*";
	final static Pattern simplePattern = Pattern.compile(simpleName);
	final static Pattern pattern = Pattern.compile(slashedClassName);
				
	When when() default When.ALWAYS;
	 static class Checker implements TypeQualifierValidator<SlashedClassName> {

	        public When forConstantValue(SlashedClassName annotation, Object value) {
	            if (!(value instanceof String))
	                return When.NEVER;

	          if (pattern.matcher((String) value).matches())
	        	  	return When.ALWAYS;
	          
	          return When.NEVER;

	        }

	    }
}
Comment 1 Ayushman Jain CLA 2010-09-10 05:31:47 EDT
Can you please provide a minimal test case without dependencies which would help us reproduce this issue?
An annotation with static fields works fine with both ecj and javac, so dont think thats the problem here.

Srikanth, please follow up. Thanks!
Comment 2 Andrey Loskutov CLA 2010-09-11 16:17:12 EDT
Created attachment 178687 [details]
Project with ant build file and class files generated by javac

I've tried to strip down all unneeded stuff, but it seems that it is important to have annotations and classes using them in different packages.

You can import zip as java project - all settings are local, and also there are already *.class files generated by my Eclipse and by the ant.

Ant build script is also included. 

Ant target is bin2 directory.

In Eclipse everything is compilable.

Running ant (using javac) I see those compile errors:

Buildfile: /home/andrei/workspace/Annotations/build.xml
init:
    [mkdir] Created dir: /home/andrei/workspace/Annotations/bin2
build:
     [echo] Annotations: /home/andrei/workspace/Annotations/build.xml
    [javac] Compiling 6 source files to /home/andrei/workspace/Annotations/bin2
    [javac] /home/andrei/workspace/Annotations/src/c/ClassName.java:14: annotation a.SlashedClassName is missing <clinit>
    [javac] 	public static String toSignature(@SlashedClassName String className) {
    [javac] 	                                 ^
    [javac] /home/andrei/workspace/Annotations/src/c/ClassName.java:25: annotation a.SlashedClassName is missing <clinit>
    [javac] 	public static @SlashedClassName String fromFieldSignature(String signature) {
    [javac] 	              ^
    [javac] /home/andrei/workspace/Annotations/src/c/ClassName.java:41: annotation a.SlashedClassName is missing <clinit>
    [javac] 			@SlashedClassName(when=When.UNKNOWN) String className) {
    [javac] 			^
    [javac] /home/andrei/workspace/Annotations/src/c/ClassName.java:40: annotation a.SlashedClassName is missing <clinit>
    [javac] 	public static @SlashedClassName String toSlashedClassName(
    [javac] 	              ^
    [javac] /home/andrei/workspace/Annotations/src/c/ClassName.java:56: annotation a.SlashedClassName is missing <clinit>
    [javac] 	public static @DottedClassName String toDottedClassName(@SlashedClassName(when=When.UNKNOWN) String className) {
    [javac] 	                                                        ^
    [javac] /home/andrei/workspace/Annotations/src/c/ClassName.java:69: annotation a.SlashedClassName is missing <clinit>
    [javac] 	public static @SlashedClassName String extractClassName(String originalName) {
    [javac] 	              ^
    [javac] 6 errors

BUILD FAILED
/home/andrei/workspace/Annotations/build.xml:19: Compile failed; see the compiler error output for details.
Comment 3 Andrey Loskutov CLA 2010-09-11 16:18:54 EDT
Created attachment 178688 [details]
Bytecode diff for ejc/javac code

Additionally here is the visual diff between the generated SlashedClassName.class files.
Comment 4 Srikanth Sankaran CLA 2012-01-11 01:43:50 EST
Hello Andrey,

I think this is the Sun compiler bug:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6857918

See also 
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6982543

Here is a slightly modified test case from comment#0 that shows the
problem:

// ------
import java.util.regex.Pattern;
public @interface X {
    final static String simpleName =
"(\\p{javaJavaIdentifierStart}(\\p{javaJavaIdentifierPart}|\\$)*)";
    final static String slashedClassName = simpleName + "(/" + simpleName
+")*";
    final static Pattern simplePattern = Pattern.compile(simpleName);
    final static Pattern pattern = Pattern.compile(slashedClassName);
}

class Y {
	private @X int a;
}
// ----

Please report this to Sun or track the above bugs.
Comment 5 Jay Arthanareeswaran CLA 2012-01-23 05:09:54 EST
Verified for 3.8M5