4 Replies Latest reply on Jul 30, 2008 1:11 AM by 843793

    A specific question concerning a statement from the Filer.

      "Note that some of the effect of overwriting a file can be achieved by using a decorator-style pattern. Instead of modifying a class directly, the class is designed so that either its superclass is generated by annotation processing or subclasses of the class are generated by annotation processing. If the subclasses are generated, the parent class may be designed to use factories instead of public constructors so that only subclass instances would be presented to clients of the parent class."

      How could the annotation processor handle generation of a super class? Specifically, how does the compiler become informed that the super class is generated and that it should process GeneratorClass in order to resolve GeneratedClass? I have a case where ClassA extends GeneratedClass. GeneratedClass is generated as source from GeneratorClass. I have tried letting the compiler simply compile GeneratorClass later in the same round, but the result is that the parse tree still returns <any> as the superclass of ClassA on subsequent rounds. I am guessing here that the compiler isn't trying to resolve the unknown once resolution fails.

      Will simply changing the compile order in the same batch of source files help here or is there some magic cookie thing I can do?
        • 1. Re: A specific question concerning a statement from the Filer.
          Don't overthink this one. It just works.

          Annotation processing is a separate step that javac does before compiling.

          Each .class and .java generated in a round of the processor becomes the input for another round of annotation processing, until there are no more source/binary files generated. You don't have to explicitly tell it to do that, it just does because Filer knows what has been generated. After that everything (both source specified on command line, and all generated code) is used as input to the actual compile process.

          All you need to do is
          javac ClassA
          and either specify the processor on the command line, or use the ServiceLoader mechanism so javac can find it automatically.

          Your Annotation Processor will generate GeneratedClass in the first round.

          There will then be another round to run any annotation processors against GeneratedClass (usually none but it is possible)

          Then javac does the actual compile, compiling ClassA and GeneratedClass all at once, and everything just works (unless you've got bugs).

          The only "build sequencing" you need to worry about is to make sure the annotation processor is compiled and visible to the compiler before using it in a compilation step. If you are using an annotation to trigger the processor, then for simple "home grown" stuff, just put the annotation and the processor in the same jar file. That way if it's not on the classpath, the compiler will complain that it can't find the symbol (eg MyAnnotation). If it can find the annotation, then it can find the processor.

          • 2. Re: A specific question concerning a statement from the Filer.
            It should be working. :) I had the above compilation setup but javac (1.6 on Mac -- latest version available from Apple) wasn't entirely happy.

            I should clarify however. The situation is (was) one step more convoluted:

            ClassGenerator (produces GeneratedClass)

            ClassA extends GeneratedClass (ClassA is another generator)


            ClassA generates GeneratedFromA

            ClassB extends GeneratedFromA.

            I've had a lot of different things causing problems, so something may have gotten lost in the mix here. sigh I'll restore inheritance and see if this was just an operator error thing.
            • 3. Re: A specific question concerning a statement from the Filer.
              I've reverted the code to reference generated classes. It isn't working. The second generated file that relies on the first is no longer being generated. If this is supposed to work, what could be breaking it?

              Now I remember there are some comments about retaining elements across rounds and I may be breaking the rules here. Over the rounds I retain the previous round's element references. The "skipping" debug is a printout in response to the fact that the original parsed element would have an unresolved parent class "Generated1". If I am indeed breaking the rules, the solution would be to throw out the references and reprocess them, and catch a new version that reflects the fact the parent class now exists. The revamped parse tree should show up in the next round's env.getElementsAnnotatedWith( ..), right?

              [edited errors]
              Compiling 22 source files to /build
              [javac] packagename/Generator2.java:25: cannot find symbol
              [javac] symbol: class packagename/Generated1
              [javac]           Generated1<T>
              [javac]           ^
              [javac] Generator2.java:25: a generic class may not extend java.lang.Throwable
              [javac]           Generated1<T>
              [javac]           ^
              [javac] Skipping: packagename/Generator2
              [javac] Evaluating:packagename/Generator1
              [javac] round: 1
              [javac] Skipping: packagename/Generator2
              [javac] round: 2
              [javac] Skipping: packagename/Generator2
              [javac] round: 3

              Edited by: teacup775 on Jul 29, 2008 4:04 PM

              Edited by: teacup775 on Jul 29, 2008 4:14 PM
              • 4. Re: A specific question concerning a statement from the Filer.
                Answered my own question. It was a matter of deferring any setup till the class name came back with a clean bill of ancestry. A bunch of slopping of names into unresolved lists and re-fetching and testing of elements on subsequent rounds.