Cannot use java value as parameter to java annotation on scala function

2,780 views
Skip to first unread message

Randy

unread,
Aug 1, 2011, 4:19:17 PM8/1/11
to scala-user
I have 3 java files: HW.java, myAnn.java, and Constants.java in
package myApp.

Constants.java:

public final class Constants {
public static final String WORLD ="World";
}

myAnn.java:

public @interface myAnn {
java.lang.String name() default "";
}

HW.java:

class HW {
@myAnn(name = Constants.WORLD)
public static void main(String[] args){
System.out.println("Hi "+ Constants.WORLD);
}
}

My app compiles and runs fine as shown above (I'm using 2.9.0.1), but
I want to migrate HW.java to scala as HelloWorld.scala:

object HelloWorld {
@myAnn(name = Constants.WORLD)
def main(args: Array[String]) {
println("Hello " + Constants.WORLD)
}
}

When I try to compile this, I get

error: annotation argument needs to be a constant; found:
Constants.WORLD @myAnn(name = Constants.WORLD)

If I remove the annotation then HelloWorld compiles and executes as
expected.

Why can I use Constants.WORLD as a parameter to an annotation from a
java program, but not from a scala program? Is there something I can
modify in Constants.java to allow it to be used from either java or
scala? I can't modify myAnn.java, and I can't migrate Constants.java
yet.

Lukas Rytz

unread,
Aug 2, 2011, 2:54:25 AM8/2/11
to Randy, scala-user
Hi,

this is a known issue, reported here

Though it should work if you compile the java files first, and
then set scalac's classpath to the folder containing the classfiles.

Lukas

Randy Unger

unread,
Aug 10, 2011, 12:58:29 PM8/10/11
to Lukas Rytz, scala-user
Thanks for that info. Now I'm looking for a workaround for this bug. My first thought was to migrate the constants file to scala, but when I do that I can't figure out how to use those constants in my java files. 

From the example I posted earlier, I'm moving Constants.java to Const.scala. No matter what syntax I've tried to reference the constant, I get an error. For example, @myAnn(name = Const$.MODULE$.WORLD) produces "WORLD has private access in myApp.Const$. Most other ways I've tried, such as @myAnn(name = Const.WORLD()) produce "Attribute value must be constant." 

Can anyone she some light on how to reference a scala constant from a java file? Thanks a bunch. Below is the updated code producing the new errors.

Const.scala:

object Const {
  final val WORLD = "World"
}

myAnn.java:

public @interface myAnn {
   java.lang.String name() default "";
}

HW.java:

class HW {
//    @myAnn(name = Const.WORLD)
//    @myAnn(name = Const.WORLD())
    @myAnn(name = Const$.MODULE$.WORLD)   //How do I make this compile?!
   public static void main(String[] args){
       System.out.println("Hi "+ Const.WORLD());
   }
}

Lukas Rytz

unread,
Aug 11, 2011, 3:05:17 AM8/11/11
to Randy Unger, scala-user
I don't think you can. Look at the bytecode of "Const.class" and "Const$.class" using javap.

Doesn't the solution that I suggested earlier work? You define the constants in Const.java, but
instead of passing the source file into scalac, you point the classpath of scalac to the compiled
"Const.class", that should work.

Lukas

Paulo "JCranky" Siqueira

unread,
Aug 11, 2011, 11:20:15 AM8/11/11
to Lukas Rytz, scala-user, Randy Unger

Does adding 'class Const' makes any difference in the generated bytecode? (I don't have access to a computer to try this right now, sorry)

[],

Paulo "JCranky" Siqueira
http://jcranky.com

Randy

unread,
Aug 11, 2011, 1:48:41 PM8/11/11
to scala-user
Lukas,

Thanks a lot for the suggestion but that doesn't work in our build
environment. We're using the IntelliJ scala plugin, and it would take
an extra step to first compile the Java constants from the command
line outside the IDE, followed by the normal build process in
IntelliJ. We have non-programmers sharing the IDE setup as well, and
management doesn't want to introduce this extra step.

The solution I'm going with for the time being is to have two separate
Constants files - one for Java and one for Scala during the migration.
Once the migration to scala is complete we will remove the java
constants file.

Thanks again,
Randy

Randy

unread,
Aug 11, 2011, 1:51:51 PM8/11/11
to scala-user
Paulo,

Thanks for the suggestion. Are you proposing that I change "object
Const" to "class Const"? I don't think this will work because "object"
is necessary to make the constants static.

Thanks,
Randy

On Aug 11, 8:20 am, "Paulo \"JCranky\" Siqueira"
<paulo.sique...@gmail.com> wrote:
> Does adding 'class Const' makes any difference in the generated bytecode? (I
> don't have access to a computer to try this right now, sorry)
>
> [],
>
> Paulo "JCranky" Siqueirahttp://jcranky.com
> Em 11/08/2011 04:05, "Lukas Rytz" <lukas.r...@epfl.ch> escreveu:
>
>
>
>
>
>
>
> > I don't think you can. Look at the bytecode of "Const.class" and
> > "Const$.class" using javap.
>
> > Doesn't the solution that I suggested earlier work? You define the
> constants
> > in Const.java, but
> > instead of passing the source file into scalac, you point the classpath of
> > scalac to the compiled
> > "Const.class", that should work.
>
> > Lukas
>

Paulo "JCranky" Siqueira

unread,
Aug 11, 2011, 3:05:23 PM8/11/11
to Randy, scala-user

Actually I meant having both, but ignore this suggestion, a quick test here demonstrated no significant difference... :-(

[],

Paulo "JCranky" Siqueira
http://jcranky.com

Reply all
Reply to author
Forward
0 new messages