17

I encountered the following javac compilation failure where javac did not recognize annotations on a static nested class that had a public enum. Once I moved the enum out of the static nested class the compilation errors were resolved. Does anyone know why javac failed? Is this a java compiler bug? Or is there a java nuance that I am unaware of?

Below is a standalone test case.

Fails to compile:

package test;

import test.AnnotationBug.NestedClassWithEnum.ParticipantType;

import lombok.Data;
import lombok.NoArgsConstructor;

import com.googlecode.objectify.annotation.Embed;

public class AnnotationBug {

  ParticipantType type;

  @Embed
  @Data
  @NoArgsConstructor
  public static final class NestedClassNoEnum {
  }

  @Embed
  @Data
  @NoArgsConstructor
  public static final class NestedClassWithEnum {
    ParticipantType type;

    public enum ParticipantType {
      ORGANIZER,
      REGISTERED,
      WAIT_LISTED
    }
  }
}

Compilation output:

$ javac -classpath /home/avaliani/projects/jars/objectify-4.0b2.jar:/home/avaliani/projects/jars/lombok.jar  test/AnnotationBug.java
test/AnnotationBug.java:20: error: cannot find symbol
  @Embed
   ^
  symbol:   class Embed
  location: class AnnotationBug
test/AnnotationBug.java:21: error: cannot find symbol
  @Data
   ^
  symbol:   class Data
  location: class AnnotationBug
test/AnnotationBug.java:22: error: cannot find symbol
  @NoArgsConstructor
   ^
  symbol:   class NoArgsConstructor
  location: class AnnotationBug

Compiles:

package test;

// import test.AnnotationBug.NestedClassWithEnum.ParticipantType;

import lombok.Data;
import lombok.NoArgsConstructor;

import com.googlecode.objectify.annotation.Embed;

public class AnnotationBug {

  ParticipantType type;

  @Embed
  @Data
  @NoArgsConstructor
  public static final class NestedClassNoEnum {
  }

  @Embed
  @Data
  @NoArgsConstructor
  public static final class NestedClassWithEnum {
    ParticipantType type;

  }

  public enum ParticipantType {
    ORGANIZER,
    REGISTERED,
    WAIT_LISTED
  }
}

Compiles without errors:

$ javac -classpath /home/avaliani/projects/jars/objectify-4.0b2.jar:/home/avaliani/projects/jars/lombok.jar  test/AnnotationBug.java

Things to point out:

1) Note the line number of the compilation failure. There is no problem parsing NestedClassNoEnum's annotation.

2) Java version:

$ java -version
java version "1.7.0_21"
OpenJDK Runtime Environment (IcedTea 2.3.9) (7u21-2.3.9-0ubuntu0.12.10.1)
OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)
Gili
  • 86,244
  • 97
  • 390
  • 689
Amir
  • 720
  • 8
  • 18
  • 3
    Have you tried removing one/some/all of the annotations to see if you can isolate it to one of them? For instance, this seems to be your only use of `@Embed` and `@NoArgsConstructor` in your linked code, maybe it's something with them. Can you reproduce it in a much smaller, simpler class? – ajp15243 May 21 '13 at 21:22
  • Hi @ajp15243. Thanks for your note. I've changed the test case to a stand-alone test case. Note that I did try removing the Embed annotation and the compiler failed to compile the NoArgsConstructor and Data annotations. So I'm fairly certain the problem is not with the annotations. – Amir May 21 '13 at 22:30
  • @Amir Indeed, my mistake - I recreated your first example, copying the code of the annotations of the libraries you are referring to and it compiled fine on oracle jdk 7u10. Looks like a bug. – assylias May 21 '13 at 23:05
  • You might try playing with the annotation retention policy (@Retention). (i.e., I'm wondering if the problem is to the compiler generating a different class file for the nested class.) – Turix May 21 '13 at 23:24
  • My guess is, without default constructor, annotations wont work. – Siddharth May 23 '13 at 05:09
  • Seems to be related to importing any inner static class (or any inner class?). Lokesh's solution works for me. – Kevin Peterson May 19 '15 at 23:41

2 Answers2

13

If you remove the import of static class, the code compiles fine, see the below code[Note: i have not used @Embed annotation as i was not having jar for it but it will not make any difference]:

//import NestedClassWithEnum.ParticipantType;
import lombok.Data;
import lombok.NoArgsConstructor;


public class AnnotationBug {

    NestedClassWithEnum.ParticipantType type;


    @Data
    @NoArgsConstructor
    public static final class NestedClassNoEnum {
    }


    @Data
    @NoArgsConstructor
    public static final class NestedClassWithEnum {
        ParticipantType type;

        public enum ParticipantType {
            ORGANIZER,
            REGISTERED,
            WAIT_LISTED
        }
    }
}

Reason seems to be related to classloading of enumns and static classes. Enums are eagerly loaded where as static classes are loaded lazily. So java might be trying to stop at compile time itself, but its a guess.

EDIT: As per discussion with paul, above guess is not correct.

Community
  • 1
  • 1
Lokesh
  • 7,810
  • 6
  • 48
  • 78
  • Classloading happens at runtime, and this is a compile-time issue. +1 for the observation though. – Paul Bellora May 23 '13 at 04:34
  • @PaulBellora: what i mean to say is that enums are eagerly loaded [http://stackoverflow.com/questions/9408322/java-lazy-loading-of-enum-instances] where as static classes are loaded lazily. So java might be trying to stop at compile time itself, but its a guess. – Lokesh May 23 '13 at 04:42
  • You might be misunderstanding that post. Enum *constants* are eagerly loaded once the enum class is loaded (they're part of static init). But an enum class itself is loaded no differently that other classes. – Paul Bellora May 23 '13 at 05:18
  • 1
    That's not just any static import. It's some kind of weird import from the same file. Definitely seems to be that line causing the issue. I'm surprised the error isn't on that line instead of later. I can confirm that this change still works with all the jars OP is using. – jpmc26 May 23 '13 at 06:08
4

This is a Lombok bug. See https://github.com/rzwitserloot/lombok/issues/1249 for the official bug report.

Gili
  • 86,244
  • 97
  • 390
  • 689