Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

does lombok have side effects on jpa

Tags:

java

jpa

lombok

I am working on converting a jpa entity to use lombok. The resulting code is the following:

@Entity
@Table(name = "TEST")
@Data
@NoArgsConstructor
@AllArgsConstructor
class Test {
   ...
   @Column(name = "FORMATTING")
   @Enumerated(EnumType.ORDINAL)
   private FormatType formatType;
   ...
}

The resulting error message contains the following

Caused by: org.hibernate.HibernateException: Missing column: formatType in TEST

I am really not sure what to google here. (I tried pasting everything before formatType into google - didn't see anything)

NOTE:

  1. fields have been renamed and aspects which do not appear relevant have been omitted, for the sake of brevity and privacy. if something looks like a typo, it probably is. please let me know if you notice something so that i can address it.

  2. the 3 lines describing the field are unchanged from the code i'm working with

EDIT:

I just noticed this right before the error message

13:22:19,967 INFO  [org.hibernate.tool.hbm2ddl.TableMetadata] (ServerService Thread Pool -- 57) HHH000261: Table found: TABLE
13:22:19,967 INFO  [org.hibernate.tool.hbm2ddl.TableMetadata] (ServerService Thread Pool -- 57) HHH000037: Columns: [..., formatType, ...]
13:22:19,968 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 57) MSC000001: Failed to start service jboss.persistenceunit."...": org.jboss.msc.service.StartException in service jboss.persistenceunit."...": javax.persistence.PersistenceException: [PersistenceUnit: ...] Unable to build EntityManagerFactory

Should be functional

  @Entity
  @Inheritance(strategy = InheritanceType.JOINED)
  @Table(name = "PARENT")

  public abstract class Parent implements Serializable {

     private static final long serialVersionUID = 1;
     @Id
     @Column(name = "ID")
     @GeneratedValue
     private long id;
     @Column(name = "ENABLED")
     private boolean enabled;
  }

  @Entity
  @Table(name = "CHILD")
  @Data
  @NoArgsConstructor
  @AllArgsConstructor
  public class Child extends Parent {
     /** XXX: HERE BE DRAGONS */
     @Column(name = "ENUM_1")
     @Enumerated(EnumType.STRING)
     private Enum1 enum1;
     @Column(name = "ENUM_2")
     @Enumerated(EnumType.ORDINAL)
     private Enum2 enum2;
     /** XXX: NO MORE DRAGONS */
     @Column(name = "FREQUENCY")
     private String frequency;
     @Column(name = "EMPTY")
     private boolean empty;
     @Column(name = "MAX_SIZE")
     private int maxSize;
  }
  public enum Enum1 {
     A,
     B,
     C
  }
  public enum Enum2 {
     X,
     Y,
     Z
  }

I have rolled back the lombok changes, I would still like to know what the issue is, but there is no rush. Also, thanks to this lovely little bug i am about 4 hours behind so i may be a little slow on the responses.

The pk of the child table is an fk to the parent table, and without lombok everything appears to work, despite the fact that the Child class has no id.

SOLUTION:

I completely forgot about asking this. Not long ago I revizited this problem. To explain the solution lets look at a slightly simplified version of the first example i included.

@Entity
@Table(name = "TEST")
@Setter
@Getter
class Test {
   ...
   @Column(name = "FORMATTING")
   @Enumerated(EnumType.ORDINAL)
   private FormatType formatType;
   ...
}

It would appear that Lombok will give you this:

@Entity
@Table(name = "TEST")
class Test {
   ...
   @Column(name = "FORMATTING")
   @Enumerated(EnumType.ORDINAL)
   private FormatType formatType;

   public FormatType getFormatType() {
      return formatType;
   }
   public void setFormatType(FormatType formatType) {
      this.formatType = formatType;
   }
   ...
}

Note that the annotations are still attached to the field. Now, I am not certain if it is just the version or implementation of JPA that we are using but I gather that if an accessor is defined jpa just ignores any annotations besides @Column (as well as any parameters specified for @Column - which is why jpa was looking for the wrong column name). So we actually need:

@Entity
@Table(name = "TEST")
class Test {
   ...
   private FormatType formatType;

   @Column(name = "FORMATTING")
   @Enumerated(EnumType.ORDINAL)
   public FormatType getFormatType() {
      return formatType;
   }
   public void setFormatType(FormatType formatType) {
      this.formatType = formatType;
   }
   ...
}

After a great deal of confusion trying to find examples and fill in some specifics regarding how lombok does its thing (to be fair I am very easily confused) i discovered this little gem: onMethod=@__({@AnnotationsHere}). Utilizing this feature I came up with the following:

@Entity
@Table(name = "TEST")
@Setter
class Test {
   ...
   @Getter(onMethod=@__({
         @Column(name = "FORMATTING"),
         @Enumerated(EnumType.ORDINAL)
      }))
   private FormatType formatType;

   ...
}

And presto it works. Now that we have what is apparently the only available solution I would like to address the question we are all pondering at the moment: is that really any cleaner than just writing the method manually and attaching the annotations there? Answer: ... I have no idea. I am just happy I found a solution.

like image 295
chrisgotter Avatar asked Sep 05 '17 20:09

chrisgotter


People also ask

Is it OK to use Lombok?

Since all the dependency to Lombok is unidirectional i.e. classes depends on Lombok but Lombok doesn't directly depend on the classes, it doesn't create the real tight coupling. Also the compiled code is finally Lombok free hence making it safe to use.

Is Lombok good Java?

Conclusion. The Lombok library was created to make Java an easier language in which to code. It takes some of the most common boilerplate headaches out of the developer's task list. It can be useful for making your code more concise, reducing the chance for bugs, and speeding up development time.

Is JPA the same as Spring data JPA?

Spring data jpa- it is same like jpa means we can describe in below way. Spring Data Jpa is jpa data abstraction access which means it likes a jpa but it add some extra functionality, Without jpa we can not implement the spring data jpa.


1 Answers

Its strange. Can you show more code? I'm trying to write a simple project with part of code like in your question and it worked. I used Spring Boot and MySQL. Try to check your configuration. There is my code:

Enum:

public enum FormatType {

    FIRST_TYPE, SECOND_TYPE
}

Table in MySQL:

create table TEST
(
    ID int auto_increment primary key,
    FORMATTING int not null
);

Entity:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Table(name = "TEST")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Test {

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @Column(name = "FORMATTING")
    @Enumerated(EnumType.ORDINAL)
    private FormatType formatType;
}

Repository:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface TestRepository extends JpaRepository<Test, Integer> {
}

Service:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TestService {

    private TestRepository repository;

    @Autowired
    public TestService(TestRepository repository) {
        this.repository = repository;
    }

    public List<Test> getAllTestEntities() {
        return repository.findAll();
    }
}
like image 59
Alexander Yakunin Avatar answered Sep 30 '22 13:09

Alexander Yakunin