scala hibernate/jpa - ignore autogenerated bitmap$init$0 mapping

后端 未结 2 1850
礼貌的吻别
礼貌的吻别 2021-01-05 16:08

Trying to use hibernate/jpa with scala. Running into interesting issue.

This is my entity definition.

@Entity
class Product(n: String, d: Double) ext         


        
相关标签:
2条回答
  • 2021-01-05 16:55

    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!

    0 讨论(0)
  • 2021-01-05 16:57

    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
    }
    
    0 讨论(0)
提交回复
热议问题