title: How to map to attributes from embedded class to a single database column with JPA?
body: <p>As the title could be a bit unclear I will explain much here.</p>
  
  <p>I have an entity mapped with JPA. In this entity I use an embeddable class which contains to attributes. The problem is that I want to map the two attributes on the same database column (example comes after). To achieve that, I override the two attributes and map them to the column and for one of the two I use insertable = false and updatable = false.</p>
  
  <p>The thing is that doesn't work (getting "repeated column mapping..." and I can't find a solution to this problem. I also didn't find someone with a similar problem. I hope I searched well but as I searched a lot I think it's ok.</p>
  
  <p>For your information, I'm using JPA 2.1 with Hibernate implementation (but I don't want to use Hibernate specific features).</p>
  
  <p>Here is my source code for this class. The problem is with the "Periode" object which represent a period (of many kind : month, year). The thing is I want to use this class to represent a year (stored in database as an integer in a single column) and so be able to access Periode start and end date properties.</p>
  
  <p>Periode comes from legacy code and I have relatively limited "power" over it (as it's used in many other projects). Database is also legacy so I can't change it in order to put two dates instead of just the year.</p>
  
  <pre><code>@SuppressWarnings("serial")
  @Embeddable
  public class CandidateId implements Serializable {
      // Fields
      private Periode period;
      private IdentifiantContrat contractId;
  
      // Constructors
      @SuppressWarnings("unused")
      private CandidateId() {}
  
      public CandidateId(Periode period, IdentifiantContrat contractId) {
          this.period = period;
          this.contractId = contractId;
      }
  
      public CandidateId(Periode period, IdentifiantAffilie employerId) {
          this(period, new IdentifiantContrat(employerId, 0));
      }
  
      // Getters
      @Embedded
      @AttributeOverrides({
          @AttributeOverride(name = "debut", column = @Column(name = "PERIODE", nullable = false) ),
          @AttributeOverride(name = "fin", column = @Column(name = "PERIODE", nullable = false, insertable = false, updatable = false))
      })
  //  @Converts({
  //      @Convert(attributeName = "debut", converter = FiscalStartDateConverter.class),
  //      @Convert(attributeName = "fin", converter = FiscalEndDateConverter.class)
  //  })
      public Periode getPeriod() {
          return period;
      }
  
      @Embedded
      public IdentifiantContrat getContractId() {
          return contractId;
      }
  
      // Setters
      public void setPeriod(Periode period) {
          this.period = period;
      }
  
      public void setContractId(IdentifiantContrat contractId) {
          this.contractId = contractId;
      }
  
      // Methods
      @Override
      public int hashCode() {
          final int prime = 31;
          int result = 1;
          result = prime * result + ((contractId == null) ? 0 : contractId.hashCode());
          result = prime * result + ((period == null) ? 0 : period.hashCode());
          return result;
      }
  
      @Override
      public boolean equals(Object obj) {
          if (this == obj)
              return true;
          if (obj == null)
              return false;
          if (getClass() != obj.getClass())
              return false;
          CandidateId other = (CandidateId) obj;
          if (contractId == null) {
              if (other.contractId != null)
                  return false;
          } else if (!contractId.equals(other.contractId))
              return false;
          if (period == null) {
              if (other.period != null)
                  return false;
          } else if (!period.equals(other.period))
              return false;
          return true;
      }
  
      @Override
      public String toString() {
          return "CandidatDeclarationId [period=" + period + ", contractId=" + contractId + "]";
      }
  }
  </code></pre>
  
  <p>As you can see, I plan to use converters to convert int value from db to the two matching dates, but one problem at a time.</p>
  
  <p>When testing my code, I get this information:</p>
  
  <pre><code>javax.persistence.PersistenceException: [PersistenceUnit: belgium-fiscal-model] Unable to build Hibernate SessionFactory
      at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1249)
      at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.access$600(EntityManagerFactoryBuilderImpl.java:120)
      at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:860)
      at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
      at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:425)
      at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:849)
      at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:75)
      at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:54)
      at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
      at be.groups.kernel.utils.persistence.JpaUtil.initEntityManagerFactory(JpaUtil.java:168)
      at be.groups.kernel.utils.persistence.JpaUtil.createEntityManagerFactory(JpaUtil.java:65)
      at be.groups.belgium.fiscal.model.services.CandidateServiceTest.setUp(CandidateServiceTest.java:54)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:483)
      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
      at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
      at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
      at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
      at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
  Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: be.groups.belgium.fiscal.model.domain.Candidate column: PERIODE (should be mapped with insert="false" update="false")
      at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:709)
      at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:750)
      at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:506)
      at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
      at org.hibernate.cfg.Configuration.validate(Configuration.java:1360)
      at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1851)
      at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:857)
      ... 25 more
  
  java.lang.NullPointerException
      at be.groups.belgium.fiscal.model.services.CandidateServiceTest.tearDown(CandidateServiceTest.java:74)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:483)
      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
      at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
      at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
      at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
  </code></pre>
  
  <p>If something is unclear, just tell me I'll try to precise it.</p>
  
  <p>EDIT :
  Here is the Candidate class as asked by OndrejM. But I don't think the problem come from it (I already checked that, though I miss to mention it sorry^^). But maybe I'm missing something so if it can help, here is the class!</p>
  
  <pre><code>@Entity
  @Table(name = "ECHEANCIER_FISCAL_PERSONNE")
  public class Candidate {
      // Fields
      private CandidateId id;
  
      private Date datePassage;
      private String justification;
  
      private Integer actionProgramme;
      private Integer actionGestionnaire;
  
      private BaseSignaturePersistance persistenceSignature;
  
      // Constructors
      private Candidate() {}
  
      // Getters
      @EmbeddedId
      public CandidateId getId() {
          return id;
      }
  
      @Column(name = "ACTION_PROGRAMME", nullable = true)
      public Integer getActionProgramme() {
          return actionProgramme;
      }
  
      @Column(name = "ACTION_GESTIONNAIRE", nullable = true)
      public Integer getActionGestionnaire() {
          return actionGestionnaire;
      }
  
      @Column(name = "DT_PASSAGE", nullable = true)
      public Date getDatePassage() {
          return datePassage;
      }
  
      @Column(name = "JUSTIFICATION", nullable = true)
      public String getJustification() {
          return justification;
      }
  
      @Embedded
      public BaseSignaturePersistance getPersistenceSignature() {
          return persistenceSignature;
      }
  
      // Setters
      public void setId(CandidateId id) {
          this.id = id;
      }
  
      public void setActionProgramme(Integer actionProgramme) {
          this.actionProgramme = actionProgramme;
      }
  
      public void setActionGestionnaire(Integer actionGestionnaire) {
          this.actionGestionnaire = actionGestionnaire;
      }
  
      public void setDatePassage(Date datePassage) {
          this.datePassage = datePassage;
      }
  
      public void setJustification(String justification) {
          this.justification = justification;
      }
  
      public void setPersistenceSignature(BaseSignaturePersistance persistenceSignature) {
          this.persistenceSignature = persistenceSignature;
      }
  
      // Methods
      /**
       * Tells if this concerns a single contract or not
       * 
       * @return true if this concerns a single contract, else false
       *      
       * @since 1.0.0
       */
      @Transient
      public boolean isSingleContract() {
          return id.getContractId().getNumero() != 0;
      }
  
      /**
       * Tells if this concerns an employer (multiple contracts) or not
       * 
       * @return true if this concerns an employer, else false
       *      
       * @since 1.0.0
       */
      @Transient
      public boolean isWholeEmployer() {
          return !isSingleContract();
      }
  
      /**
       * Tells if the candidate is blocked
       * 
       * @return true if this is blocked, else false
       *      
       * @since 2.0.0
       */
      @Transient
      public boolean isBlocked() {
          return actionGestionnaire == null
                  ? (actionProgramme == null || actionProgramme == StatutCloture.PAS_PRET_POUR_PREPARATION.getValeur())
                  : (actionGestionnaire == StatutCloture.PAS_PRET_POUR_PREPARATION.getValeur());
      }
  }
  </code></pre>
  
  <p>Here is also the BaseSignaturePersistence class which is embedded in Candidate class. Sorry for mixing english and french code but as I said I work with legacy code and so some classes are in french (decision to use english has only be made recently).</p>
  
  <pre><code>@Embeddable            
  public class BaseSignaturePersistance {
  
      /**
       * Auteur creation des données.
       */
      private String auteurCreation;
      /**
       * Auteur modification des données.
       */
      private String auteurModification;
      /**
       * Date creation des données
       */
      private Date dateCreation;
      /**
       * Date modification des données.
       */
      private Date dateModification;
  
      /**
       * Nouvel Objet Signature.
       *
       * @param lAuteurCreation
       * @param lDateCreation
       * @param lAuteurModification
       * @param lDateModification
       */
      @Requires("auteurCreation!=null &amp;&amp; dateCreation!=null")
      @Ensures({"this.auteurCreation == auteurCreation &amp;&amp; this.dateCreation == dateCreation",
          "this.dateModification!=null ? this.auteurModification!=null : true",
          "this.auteurModification!=null ? this.dateModification!=null : true"})
      public BaseSignaturePersistance(String auteurCreation, Date dateCreation, String auteurModification, Date dateModification) {
          this.auteurCreation = auteurCreation;
          this.dateCreation = dateCreation;
          this.auteurModification = auteurModification;
          this.dateModification = dateModification;
      }
  
      /**
       * Nouvel objet signature contenant seulement la partie creation
       * @param unAuteurCreation
       * @param uneDateCreation 
       */
      @Requires({
          "unAuteurCreation!=null",
          "uneDateCreation!=null"
      })
      public BaseSignaturePersistance(String unAuteurCreation, Date uneDateCreation){
          this(unAuteurCreation, uneDateCreation, null, null);
      }
  
      /**
       * Nouvel objet signature contenant seulement la partie creation
       * @param unAuteurCreation 
       */
      @Requires({
          "auteurCreation!=null"
      })
      public BaseSignaturePersistance(String unAuteurCreation){
          this(unAuteurCreation, DateUtility.getNow(), null, null);
      }
  
      /**
       * Nouvel objet signature.
       * Utiliser setModification ou SetSuppression pour compléter ce qui est nécessaire.
       */
      public BaseSignaturePersistance(){
          this.auteurCreation = null;
          this.dateCreation = null;
          this.auteurModification = null;
          this.dateModification = null;
      }
  
      /**
       * Affecte {@code auteur} et {@code date} à {@code auteurModification} et {@code dateModification}.
       *
       * @param auteur
       * @param date
       */
      @Requires("auteur!=null &amp;&amp; date!=null")
      @Ensures("auteurModification == auteur &amp;&amp; dateModification == date")
      public void setModification(String auteur, Date date) {
          auteurModification = auteur;
          dateModification = date;
      }
  
      public void copy(BaseSignaturePersistance other) {
          auteurCreation = other.auteurCreation;
          dateCreation = other.dateCreation;
          auteurModification = other.auteurModification;
          dateModification = other.dateModification;
      }
  
      @Column(name = "AUTEUR_CREATION", nullable = false)  
      public String getAuteurCreation() {
          return auteurCreation;
      }
  
      @Column(name = "AUTEUR_MODIFICATION")
      public String getAuteurModification() {
          return auteurModification;
      }
  
      @Temporal(TemporalType.TIMESTAMP)
      @Column(name = "DT_CREATION", nullable = false)
      public Date getDateCreation() {
          return dateCreation;
      }
  
      @Temporal(TemporalType.TIMESTAMP)
      @Column(name = "DT_MODIFICATION")
      public Date getDateModification() {
          return dateModification;
      }
  
      public void setAuteurCreation(String auteurCreation) {
          this.auteurCreation = auteurCreation;
      }
  
      public void setAuteurModification(String auteurModification) {
          this.auteurModification = auteurModification;
      }
  
      public void setDateCreation(Date dateCreation) {
          this.dateCreation = dateCreation;
      }
  
      public void setDateModification(Date dateModification) {
          this.dateModification = dateModification;
      }
  
      /**
       * Gives most recent date the object has been modified
       * 
       * @return modification date if any, else creation date
       */
      @Transient
      public Date getDateDerniereModification() {
          return dateModification != null ? dateModification : dateCreation;
      }
  
      /**
       * Gives most recent author that has modified the object
       * 
       * @return modification author if any, else creation author
       */
      @Transient
      public String getAuteurDerniereModification() {
          return auteurModification != null ? auteurModification : auteurCreation;
      }
  
      @Override
      public int hashCode() {
          final int prime = 31;
          int result = 1;
          result = prime * result
                  + ((auteurCreation == null) ? 0 : auteurCreation.hashCode());
          result = prime
                  * result
                  + ((auteurModification == null) ? 0 : auteurModification
                          .hashCode());
          result = prime * result
                  + ((dateCreation == null) ? 0 : dateCreation.hashCode());
          result = prime
                  * result
                  + ((dateModification == null) ? 0 : dateModification.hashCode());
          return result;
      }
  
      @Override
      public boolean equals(Object obj) {
          if (this == obj)
              return true;
          if (obj == null)
              return false;
          if (getClass() != obj.getClass())
              return false;
          BaseSignaturePersistance other = (BaseSignaturePersistance) obj;
          if (auteurCreation == null) {
              if (other.auteurCreation != null)
                  return false;
          } else if (!auteurCreation.equals(other.auteurCreation))
              return false;
          if (auteurModification == null) {
              if (other.auteurModification != null)
                  return false;
          } else if (!auteurModification.equals(other.auteurModification))
              return false;
          if (dateCreation == null) {
              if (other.dateCreation != null)
                  return false;
          } else if (!dateCreation.equals(other.dateCreation))
              return false;
          if (dateModification == null) {
              if (other.dateModification != null)
                  return false;
          } else if (!dateModification.equals(other.dateModification))
              return false;
          return true;
      }
  
      @Override
      public String toString() {
          return "BaseSignaturePersistance [auteurCreation=" + auteurCreation
                  + ", auteurModification=" + auteurModification
                  + ", dateCreation=" + dateCreation + ", dateModification="
                  + dateModification + "]";
      }
  }
  </code></pre>