26

I am trying out Java 7 for one project and getting warnings from annotation processors (Bindgen and Hibernate JPA modelgen) of this sort:

warning: Supported source version 'RELEASE_6' from annotation processor 'org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor' less than -source '1.7'

This is caused by the @SupportedSourceVersion(SourceVersion.RELEASE_6) annotation on the annotation processor classes. Since they are compiled with Java 6, the highest value of SourceVersion available to them is RELEASE_6. The Java 7 version of SourceVersion introduces RELEASE_7.

My questions: How are annotation processors supposed to handle forward compatibility? Will there have to be separate jdk6 and jdk7 binary versions of them? Am I not understanding something else here?

I only found the following information regarding this concern:

Querdydsl bug report which used

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

Oracle blog in which a commentor recommends supporting latest source version

bernie
  • 9,820
  • 5
  • 62
  • 92

1 Answers1

19

Forward compatibility is handled by processing unknown language constructs appropriately, for example by implementing ElementVisitor.visitUnknown.

There is another entry in the mentioned Oracle blog, which suggests two policies regarding forward compatibility:

  • Write the processor to only work with the current language version.
  • Write the processor to cope with unknown future constructs.

The second one is done by returning SourceVersion.latest() as already posted in the question.

I think it's ok to do this in most cases, when you are sure additional language elements won't break anything. Of course you shouldn't just assume that everything will be fine even with newer versions, you should test it too.


Ok, I guess processing unknown language constructs appropriately sounds a bit vague, so here are some examples.

Supposed you have a processor that checks for a custom type of annotations on known language constructs (annotations on a class for example) and creates a simple documentation of what it has found. You are probably safe to assume it will also work in newer versions. Restricting it to a particular version would not be a good decision in my opinion.

Supposed you have a processor that checks every element it can find and analyses the code structure to generate a graph out of it. You may get problems with newer versions. You may be able to handle unknown language constructs somehow (like by adding a unknown node to the graph) but only do this if that makes sense - and if it's worth the trouble. If the processor just wouldn't be useful any more when confronted with something unknown, it should probably stick to a particular java version.

Regardless of the policy used, the best way in my opinion would be to monitor upcoming changes to the language and update the processor accordingly. In Java 7 for example, project coin introduced some new language features, which are most likely not even visible to a processor. Java 8 on the other hand does have new constructs that will affect processing, for example type annotations. New language features don't happen that often though, so Chances are that you don't even need to change anything for a long time.

kapex
  • 28,903
  • 6
  • 107
  • 121
  • 1
    Thanks for your initial post and the update. I haven't accepted your answer yet because I'm still (very part-time) in the process of converting an annotation processor to Java 7. I want to see if something else pops-up. – bernie Nov 29 '11 at 23:18
  • It seems to me there is a difference between `SourceVersion.latest()` and `SourceVersion.latestSupported()`. The first one uses a hardcoded constant from annotation processor compilation JDK. Can't it end up in inlining it, and loosing the dynamic aspect? With `SourceVersion.latestSupported()` I guess it uses version of JDK used for compilation of target code, processed by the AP. – Ondřej Fischer Apr 04 '22 at 21:22
  • @OndřejFischer Good question. I think it can't happen because it's a method call which returns the enum constant. As far as I know method inlining is only done at runtime by the JIT and never at compile time. I'm not even sure if enums are inlined at all. – kapex Apr 05 '22 at 08:30
  • Good point. Then I'm not sure, which is better to use. Anyway, the aswer is very valuable, pointing to these methods. Thanks. – Ondřej Fischer Apr 06 '22 at 13:15
  • `@SupportedSourceVersion(SourceVersion.latest())` fails bc `.latest()` is not a "enum constant expression" – is the only way to specify forward-compatibility to use the `getSupportedSourceVersion` method itself? – theonlygusti Jun 17 '23 at 11:41
  • @theonlygusti The annotation can only be used if the value known at compile time. If you want to use `latest()` I think there is no other way than overriding `getSupportedSourceVersion` – kapex Jun 17 '23 at 13:11