-3

It looks like my misconceptions have led me to this question. Please help me sort them out. JLS 9.6.1 states that "Class or an invocation of Class (§4.5)" is covered as an annotation type, chrylis -cautiouslyoptimistic pointed out.

We all agree that a static import is a constant (well, pretend I did not make that statement: It is of course not true https://stackoverflow.com/a/9083023/1236128)

import static path.to.someFunction

I create an annotation like this

@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface Testing {
    Class<? extends Function> symbol();
}

Given a static function (even declaring this final does not make someFunction constant by definition in Java, which is throwing me off):

public static Function<Long, Long> someFunction = a -> b;

Excuse me (I realize there is a difference between the function itself and its application),

public static Function<Long, Long> someFunction = a -> 2L;

I create a unit test like this (assuming the aforementioned static import):

@Test
@Testing(symbol = someFunction)
void someFunctionTest() {
    ....
}

Aside from my mistakes, does anybody recognize how useful this would be at compile time? I could use reflection on all functions marked with say @Tested to see whether there is indeed a test for it somewhere (on the basis of the @Testing annotation).

The funny thing is, I am supplying the annotation with a constant, but that is the complaint given by IntelliJ:

Attribute value must be [a] constant.

What's up with that? Is the annotation mechanism trying to execute the function, or will it accept it as a higher order function?

Jonathan Komar
  • 2,678
  • 4
  • 32
  • 43
  • 1
    and [How to supply value to an annotation from a Constant java](https://stackoverflow.com/questions/2065937/how-to-supply-value-to-an-annotation-from-a-constant-java) – luk2302 Sep 02 '20 at 08:38
  • And [Which types can be used for Java annotation members?](https://stackoverflow.com/questions/1458535/which-types-can-be-used-for-java-annotation-members) – luk2302 Sep 02 '20 at 08:42
  • 1
    I don't agree that a static import is a constant. – BeUndead Sep 02 '20 at 08:43
  • Note: If you _really_ wanted, you could define it as a `String` where you define the lambda's contents, and then compile that `String` to a function instance at runtime when processing the annotation... Spring's SpEL (amongst other things) work like this. – BeUndead Sep 21 '20 at 16:10

3 Answers3

1

We all agree that a static import is a constant.

No, we don't.

A static import does nothing other than making a field/method/... accessible via a simple name as opposed to having to use the fully qualified name.

That simple name might be a reference to a constant field or it might be a reference to something else.

You've defined someFunction as

public static Function<Long, Long> someFunction = a -> b;

According to the rules of the Java language that is not a "constant expression" (emphasis mine):

A constant expression is an expression denoting a value of primitive type or a String [...]

Obviously a Function is neither a primitive value nor a String.

Additionally you've defined the symbol to take a Class<? extends Function>, which means you need to assign it a class that implements Function. someFunction is not a Class, it's an actual object that happens to implement Function.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
  • Would applying `final` to my definition of `someFunction` do any good? I have a hard time accepting that `someFunction` is not a constant. Like if I define it as `a->2`. – Jonathan Komar Sep 02 '20 at 08:50
  • @JonathanKomar: would applying `final` change the type to be a primitive or `String`? Would it change the field from `Function` to `Class extends Function>`. The short of it is that lambdas won't give you a `Class extends Function>`, they can only give you a `Function` so you won't be able to use lambdas in your annotations. – Joachim Sauer Sep 02 '20 at 08:53
  • Ok a couple of things to add to that: I though `Function` was a class. I suppose the application of `someFunction` would be a constant. Would this be covered under Java's def: `Function someFunction = a -> 2L`? The output could be deboxed into a primitive... – Jonathan Komar Sep 02 '20 at 09:04
  • 1
    @JonathanKomar `Function` _is_ a class. You aren't passing `Function.class`, you're trying to pass _an instance of `Function`_. – chrylis -cautiouslyoptimistic- Sep 02 '20 at 14:27
1

The overall answer is no, you cannot do this. And your code does not work for a multitude of reasons:

  • someFunction is not a compile time constant
  • someFunction is not a Class<? extends Function> as symbol expects
  • the actual type Function<?,?> is not supported as an attribute type in annotations.
luk2302
  • 55,258
  • 23
  • 97
  • 137
  • I was of the understanding that a static function *is* a compile-time constant. Isn't the type `Function,?>`just a way of telling the compiler to typecheck `Function` against `?, ?`? – Jonathan Komar Sep 02 '20 at 08:46
  • "constant expression" in Java has a very clear definition and can only ever apply to primitive values or `String` values. – Joachim Sauer Sep 02 '20 at 08:54
  • @JonathanKomar https://stackoverflow.com/questions/9082971/compile-time-constants-and-variables – luk2302 Sep 02 '20 at 08:54
  • @luk2302 Wow, that post was helpful. msi's answer really hits the nail on the head, and I am prone to think that my question was the result of my misconception of what a *constant* is in Java. – Jonathan Komar Sep 02 '20 at 09:20
0

You can't do it as-is. JLS 9.6.1:

The return type of a method declared in an annotation type must be one of the following, or a compile-time error occurs:

  • A primitive type
  • String
  • Class or an invocation of Class (§4.5)
  • An enum type
  • An annotation type
  • An array type whose component type is one of the preceding types (§10.1).
chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152