45

I can't figure out why the following won't compile. The error the IDE gives me is "The value for annotation attribute RequestParam.defaultValue must be a constant expression".

My project involves Spring and Maven, and it goes the following:

private static final String MAX_LONG_AS_STRING = Long.toString(Long.MAX_VALUE);

@RequestMapping(method=RequestMethod.GET)
public List<Spittle> spittles(
        @RequestParam(value="max",
                    defaultValue=MAX_LONG_AS_STRING) long max,
        @RequestParam(value="count", defaultValue="20") int count) {
    return spittleRepository.findSpittles(max, count);
}

I'm thinking the error comes from the conversion of Long to String, but I do not know how to fix it. I will appreciate any help, I am new to annotations and Spring.

Robert Columbia
  • 6,313
  • 15
  • 32
  • 40
  • 13
    @EJP Maybe she doesn't understand why something that looks like a constant really isn't a constant? This isn't trivial. – ajb Aug 26 '16 at 03:05
  • 3
    That is fantastic, your example same as mine, I read "Spring in action" also. There is many such kind of mistakes – Tigran Babajanyan Oct 29 '17 at 10:54

1 Answers1

80

The Java rules say that when you have an annotation, and it has a parameter that expects a primitive type (such as an int) or a String, the value must be a constant expression. [This has nothing to do with Spring.] Roughly speaking, a constant expression is one whose value the compiler can figure out at compile time. However, there are rules for what constitutes a constant expression. These rules are in JLS 15.28. Only certain types of operations can be used in a constant expression. A method call, such as Long.toString(), isn't one of those. So using that makes your expression not a constant expression, even though it looks like it should be. (It looks like it to you, because you know what Long.toString does. However, the compiler doesn't keep a catalog of all methods to know which ones are "constant" methods whose values can be figured out at compile time.)

However, the example at the link shows that the + operator can be used, even when one of the arguments is not a string and therefore a toString() method is implicitly called. This suggests that you might be able to make things work like this:

private static final String MAX_LONG_AS_STRING = "" + Long.MAX_VALUE;

I haven't tried it, though.

ajb
  • 31,309
  • 3
  • 58
  • 84
  • 1
    Ohh! Thank you very much for your help, the option you gave me does work! And the link and explanation you gave really helped understand more about constant expressions. I wasn't aware about the compile time difference until I investigated more, but didn't know it had something to do with the method usage as well. Thank you very much for brief but great explanation! – Kassandra Hinojosa Rodriguez Aug 26 '16 at 03:49
  • 2
    `toString()` is a method call at runtime. `"" + 5` creates a constant string (as they are immutable) at compile time - i may be wrong – junvar Nov 18 '17 at 20:33
  • 3
    @junvar Nothing prevents a compiler from creating a constant string for `Long.toString(Long.MAX_VALUE)`. There are multiple Java compilers, and each one could decide whether to optimize this to a constant string or not. However, Java's rules about what is legal or not are the same regardless of compiler. The legality rules don't depend on optional optimizations that a compiler may or may not make. – ajb Nov 19 '17 at 01:00
  • why static final Integer WINDOW_SIZE = 300; is also giving me not a constant expression, there is no method call here ? – vipin Oct 04 '19 at 05:28
  • @vipin I think we'd need a Minimal Reproducible example, and it should be a new question – ajb Oct 04 '19 at 17:38
  • can I make this private static final String INSTANCE_ID = "" + UUID.randomUUID().toString(); as a constant expression? – Sumit Kandoi Jan 17 '20 at 11:35
  • 1
    @SumitKandoi No. (You can declare the INSTANCE_ID, but you can't use it in an annotation.) Your expression contains two method calls, and constant expressions can't have any. Furthermore, randomUUID() isn't something that can be computed at compile time--it should return a different value every time it's called, which means computing it at compile time is out of the question. – ajb Jan 18 '20 at 23:43
  • @vipin Integer is not a primitive type. Use int. – Nicholas Oct 30 '20 at 03:41