Warning: Trying to access array offset on value of type bool in /home/www/blog/wp-content/themes/catch-box/functions.php on line 1079

Constructor Arguments with JPA-Annotations

Scala provides the possibility to define constructor argument that are class properties as well. I recoded the entity OrganisationAssociation to use j__organisations as argument.

The example entity from my post Relations with Scala Collections and JPA looks like this:

@Entity
@Table(name = "org_assoc")
@SequenceGenerator(name = "org_assoc_id_seq", sequenceName = "org_assoc_id_sequence")
class OrganisationAssociation extends MIPEntity {
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "org_assoc_id_seq")
  @Column(name = "org_assoc_id", nullable = false, length = 20)
  @BeanProperty
  var id: BigInteger = _

  @OneToMany
  @BeanProperty
  var j__organisations = :+[Organisation]

  def organisations_=(c: SC[Organisation]) = j__organisations = c
  def organisations: SC[Organisation] = j__organisations
}

What do we have to do to use annotated constructor arguments?

Simply Annotating a constructor argument means, that the annotation only ends up on the actual argument of the constructor. To provide the annotation to the generated fields or getters and setters we have to use the meta annotation @field. This behaviour changed since RC2 and will require a additional meta annotation to every (!) annotation (something like @(OneToMany @field)() )

To simplify this and to improve readability, we can use a type alias like otm in this case (@BeanProperty is already meta annotated with @field):

object MyShorterAnnotations {
  type otm = OneToMany @field
}

This leads to the following code:

import MyShorterAnnotations._
. . .
class OrganisationAssociation(@BeanProperty @otm var j__organisations:JC[Organisation] = :+[Organisation]) extends MIPEntity {
  . . .
  def organisations_=(c: SC[Organisation]) = j__organisations = c
  def organisations: SC[Organisation] = j__organisations
}

Unfortunately default values for constructor arguments do not create a public default constructor.
The Scala Compiler creates something like this, btw:

public static final List init$default$1()
{
  return .MODULE$.init$default$1();
}

And I really do not know where the assignment finally happens and since I am using the OpenJPA Enhancer by openjpa-maven-plugin, the plugin will create a default constructor automatically. But this enhanced constructor is not aware of Scalas internals, so it does not do what he has to do: create a empty Collection.

So we have to provide a proper public default constructor manually:

	class OrganisationAssociation(@BeanProperty @otm var j__organisations:JC[Organisation]) extends MIPEntity {
	  def this() = this(:+[Organisation])
	  . . .
	  def organisations_=(c: SC[Organisation]) = j__organisations = c
	  def organisations: SC[Organisation] = j__organisations
	}

This code works like the initial example (test code is here).

More information about Scala 2.8 Annotations is available here