web-dev-qa-db-fra.com

lombok a-t-il des effets secondaires sur jpa

Je travaille sur la conversion d'une entité jpa pour utiliser lombok. Le code résultant est le suivant:

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

Le message d'erreur résultant contient les éléments suivants

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

Je ne sais vraiment pas quoi google ici. (J'ai essayé de tout coller avant formatType dans google - je n'ai rien vu)

REMARQUE:

  1. les champs ont été renommés et les aspects qui ne semblent pas pertinents ont été omis, par souci de concision et de confidentialité. si quelque chose ressemble à une faute de frappe, c'est probablement le cas. s'il vous plaît laissez-moi savoir si vous remarquez quelque chose afin que je puisse y remédier.

  2. les 3 lignes décrivant le champ sont inchangées par rapport au code avec lequel je travaille

ÉDITER:

Je viens de le remarquer juste avant le message d'erreur

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

Devrait être fonctionnel

  @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
  }

J'ai annulé les modifications de lombok, j'aimerais toujours savoir quel est le problème, mais il n'y a pas de précipitation. De plus, grâce à ce joli petit bug, j'ai environ 4 heures de retard, donc je peux être un peu lent sur les réponses.

Le pk de la table enfant est un fk de la table parent, et sans lombok, tout semble fonctionner, malgré le fait que la classe Child n'a pas d'ID.

SOLUTION:

J'ai complètement oublié de demander ça. Il n'y a pas longtemps, j'ai revisité ce problème. Pour expliquer la solution, regardons une version légèrement simplifiée du premier exemple que j'ai inclus.

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

Il semblerait que Lombok vous donnera ceci:

@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;
   }
   ...
}

Notez que les annotations sont toujours attachées au champ. Maintenant, je ne sais pas si c'est seulement la version ou l'implémentation de JPA que nous utilisons, mais je suppose que si un accesseur est défini, jpa ignore simplement les annotations en plus de @Column (Ainsi que tous les paramètres spécifiés pour @Column - c'est pourquoi jpa cherchait le mauvais nom de colonne). Nous avons donc réellement besoin de:

@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;
   }
   ...
}

Après beaucoup de confusion en essayant de trouver des exemples et de remplir certains détails sur la façon dont lombok fait son truc (pour être honnête, je suis très facilement confus), j'ai découvert ce petit bijou: onMethod=@__({@AnnotationsHere}) =. En utilisant cette fonctionnalité, j'ai trouvé ce qui suit:

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

   ...
}

Et hop ça marche. Maintenant que nous avons ce qui est apparemment la seule solution disponible, je voudrais répondre à la question que nous réfléchissons tous en ce moment: est-ce vraiment plus propre que de simplement écrire la méthode manuellement et d'y attacher les annotations? Réponse: ... je n'en ai aucune idée. Je suis juste content d'avoir trouvé une solution.

11
chrisgotter

C'est étrange. Pouvez-vous montrer plus de code? J'essaie d'écrire un projet simple avec une partie du code comme dans votre question et cela a fonctionné. J'ai utilisé Spring Boot et MySQL. Essayez de vérifier votre configuration. Il y a mon code:

Enum:

public enum FormatType {

    FIRST_TYPE, SECOND_TYPE
}

Table dans MySQL:

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

Entité:

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;
}

Référentiel:

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();
    }
}
2
Alexander Yakunin

J'ai rencontré le même problème avec Lombok et JPA mais j'ai configuré le Lombok et cela a fonctionné comme prévu. Voici le code:

Contrôleur

package com.sms.controller;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.sms.model.StudentModel;
import com.sms.persistance.StudentRepository;

@RestController
public class StudentController {

    @Autowired
    private StudentRepository sr;

    @PostMapping("/addstudent")
    public String addStudent(@Valid @RequestBody StudentModel studentModel) {
        StudentModel result = sr.save(studentModel);
        return result.equals(null)?"Failed":"Successfully Saved student data";
    }

}

Modèle

package com.sms.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;
import lombok.RequiredArgsConstructor;

@Data
@RequiredArgsConstructor
@Entity
@Table(name="student", schema="development")
public class StudentModel {

    @Id
    @Column(name="student_id")
    private int id;
    @Column(name="student_name")
    private String studentname;
    @Column(name="student_address")
    private String studentaddress;



}

Référentiel

package com.sms.persistance;

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

import com.sms.model.StudentModel;

@Repository
public interface StudentRepository extends JpaRepository<StudentModel, Integer>{

}
1
shaktirath

Il est peu probable que lombok cause des problèmes d'exécution, car il fonctionne sur le temps de précompilation, vous pourriez trouver utile de décompiler le code généré, je trouve parfois que l'ordre dans lequel les annotations lombok sont placées dans le code source affecte le résultat final, donc, vous utilisez @Data et @NoArgsConstructor, je suppose que vous pouvez supprimer @NoArgsConstructor et essayer de voir si cela résout votre problème.

1
leoconco