Trying to use hibernate/jpa with scala. Running into interesting issue.
This is my entity definition.
@Entity
class Product(n: String, d: Double) ext
Found a couple of interesting things about this issue.
I have this Model
class in my application:
@Entity
@Table(name="users")
class User extends Model{
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="users_id_seq")
@Column(name="id", updatable=false, nullable=false)
val id:Long = 0L
@BeanProperty var name:String = _
@BeanProperty var email:String = _
}
This class is compiled to a java class named User
, which in turn is defined like this:
@Entity
@Table(name="users")
@ScalaSignature(bytes=long array of bytes)
public class User extends Model
implements ScalaObject, EntityBean
{
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="users_id_seq")
@Column(name="id", updatable=false, nullable=false)
private final long id;
private String name;
private String email;
private volatile int bitmap$init$0;
private static String _EBEAN_MARKER = "models.User";
...
public long id()
{
if ((_ebean_get_bitmap$init$0() & 0x1) != 0)
{
_ebean_get_id(); return _ebean_get_id();
}
throw new
UninitializedFieldError("Uninitialized field: User.scala: 17".toString());
}
public String name()
{
if ((_ebean_get_bitmap$init$0() & 0x2) != 0)
{
_ebean_get_name(); return _ebean_get_name();
} throw new
UninitializedFieldError("Uninitialized field: User.scala: 19".toString());
}
public void name_$eq(String paramString) {
_ebean_set_name(paramString);
_ebean_set_bitmap$init$0(_ebean_get_bitmap$init$0() | 0x2);
}
....
The bitmap$init$0
actually comes from a class enhancement, and I thought that the responsible was the Ebean
library, which I'm currently using. But after reading your post I went to investigate if JPA itself was doing some sort of bytecode enhancement on this object.
In order to check this out, I created a copy project, but in Java. The generated code for the User
class happens to have no bitmap$init$0
field, as follow:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="users")
public class User
{
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="users_id_seq")
@Column(name="id", updatable=false, nullable=false)
private Long id;
private String name;
private String email;
public void setId(Long id)
{
this.id = id;
}
public Long getId() {
return this.id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
}
All this kind of trouble led me to this post and I most certainly agree. It seems that integrating JPA to Scala Ebean/Hibernate is kind of a real pain. I still didn't understand if this bitmap$ini$0
field in injected to the class bytecode by Ebean or something else.
It seems that you can try to bypass this kind of behavior by associating an annotation (@Transitent
) to the generated Java bytecode, by compiling the code first for java then to Scala, something similar to what is described here. But I really don't think that's really worthy!
I don't know where that autogenerated field is coming from, but you could try to streamline your class to have less fields:
@Entity
class Product(var name: String = "", var price: Double = 0) extends EntityBase {
@ManyToOne
@JoinColumn(name="orderId")
var order: Order = _
override def toString = "Product: " + id + " " + name
}