views:

597

answers:

2

I've been building out some annotated domain classes in Scala 2.8.0 using Hibernate Annotations 3.4.0. It's been working fine, except that there are certain annotations which take an array as a parameter. For example, here's a Java annotation that I want to express in Scala:

@OneToMany(mappedBy="passport_id", cascade=CascadeType.PERSIST)

However, the annotation requires an array/set as input:

[ERROR] .../Passport.scala:50: error: type mismatch; 
[INFO]  found   : javax.persistence.CascadeType(value PERSIST)
[INFO]  required: Array[javax.persistence.CascadeType]
[INFO]     @OneToMany(mappedBy="passport_id", cascade=CascadeType.PERSIST)

I've tried various parentheses, square/angle/curly brackets, and so on:

@OneToMany(mappedBy="passport_id", cascade=(CascadeType.PERSIST))
@OneToMany(mappedBy="passport_id", cascade=[CascadeType.PERSIST])
@OneToMany(mappedBy="passport_id", cascade=<CascadeType.PERSIST>)
@OneToMany(mappedBy="passport_id", cascade={CascadeType.PERSIST})

... but unfortunately I've reached the end of my understanding of Scala/Java annotations. Help is appreciated.

+4  A: 

From Rex Kerr:

@OneToMany(mappedBy="passport_id", cascade=Array(CascadeType.PERSIST))

This worked. Thanks.

Isaac Oates
+10  A: 

I'll add a few snippets from the spec to explain why Rex's solution works.

For Scala on the JVM, arguments to annotations that will be retained within the generated class must be constant expressions:

Instances of an annotation class inheriting from trait scala.ClassfileAnnotation will be stored in the generated class files. ... Additionally, on both Java and .NET, all constructor arguments must be constant expressions.

What are constant expressions?

6.24 Constant Expressions Constant expressions are expressions that the Scala compiler can evaluate to a constant. The definition of “constant expression” depends on the platform, but they include at least the expressions of the following forms:

  • A literal of a value class, such as an integer
  • A string literal
  • A class constructed with Predef.classOf (§12.4)
  • An element of an enumeration from the underlying platform
  • A literal array, of the form Array(c1, . . . , cn), where all of the ci ’s are themselves constant expressions
  • An identifier defined by a constant value definition (§4.1).

You should also be able to refactor the argument to a final val. This doesn't seem to work for Arrays, however. I'll raise a bug.

class T(value: Any) extends ClassfileAnnotation

object Holder {
   final val as = Array(1, 2, 3)
   final val a = 1
} 

@T(Holder.a)
@T(Holder.as)  // annot.scala:9: error: annotation argument needs to be a constant; found: Holder.as
class Target
retronym