Bonjour à tous,
J'ai parcouru de nombreux forums et tutos Hibernate français et anglais, mais je peine à trouver un cas aussi complexe que le mien...
Je dois développer une appli Java où trois classes DossierREG.java, Beneficiaire.java, DepenseBeneficiaire.java sont liées de la manière suivante :
- Un DossierREG contient un Set<Beneficiaire>.
- Un Beneficiaire contient un Set<DepenseBeneficiaire>.
De plus :
- Chacune des trois classes contient un identifiant du type NomDeLaClasseId.java : le précédent développeur de mon appli a, pour une raison que mon statut de débutante Hibernate m'empêche de comprendre, créé une classe NomDeLaClasseId pour chaque classe ou presque, et y toucher casse l'appli.
- La PK du DossierREG est composée d'un ID unique généré en faisant un 
select max(id)+1 sur la classe (ne vous fiez pas aux @Parameter nomtable_seq), et de l'ID de l'action.
- La PK du Beneficiaire est aussi composée d'un ID généré, combiné à l'ID du dossier et à l'ID de l'action.
- La PK de la DepenseBeneficiaire est composée de l'ID du dossier, de l'ID de l'action, de l'ID du Beneficiaire, et de l'ID du type de la DepenseBeneficiaire.
Je ne peux malheureusement pas toucher à la structure SQL car je ne suis pas la seule à m'appuyer sur cette base de données, et mon appli doit donc s'adapter à ces contraintes !
Si mon appli ne contient que des DossierREG et des Beneficiaire, tout va bien, j'enregistre en BDD sans souci, mais lorsque je rajoute un Set<DepenseBeneficiaire> à ma classe Beneficiaire, Hibernate me sort l'erreur suivante :
org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: fr.site.hibernate.classes.DepenseBeneficiaire.beneficiaire in fr.site.hibernate.classes.Beneficiaire.depensesJ'en déduis que mon mapping par 
beneficiaire n'aboutit pas là où je veux, et que les DepenseBeneficiaire n'arrivent pas à faire le lien avec les Beneficiaire...
Est-ce que quelqu'un de plus calé que moi pourrait me donner une piste, me dire quelles annotations corriger, ou quel mapping ajouter, s'il-vous-plaît ?
Je code sur Eclipse Galileo 3.5.1, avec le jdk.1.6.0_12, et Hibernate 3.
DossierREG.java
Code:
@Entity
@Table(name="dossier")
public class DossierREG implements Serializable
{
   private static final long serialVersionUID = -4550370284540235670L;
   
   public static final String FIELD_ID = "idDossierREG";
   public static final String FIELD_IDWEB = "idDossierWeb";
   public static final String FIELD_BENEFICIAIRES = "beneficiaires";
   
   private DossierREGId idDossierREG;
   private Long idDossierWeb;
   private Set<Beneficiaire> beneficiaires;
   
   
   @EmbeddedId
   @AttributeOverrides
   ({
      @AttributeOverride(name="numero", column=@Column(name="id", length=45))
   })
   @AssociationOverrides
   ({
      @AssociationOverride(name="action", joinColumns=@JoinColumn(name="action_id", referencedColumnName="id"))
   })
   @GeneratedValue(generator="idDossierWebGenerator",strategy=GenerationType.TABLE)
   @GenericGenerator
   (
      name="idDossierWebGenerator",
      strategy="fr.site.hibernate.utils.TableHiLoCompositeIdGenerator",
      parameters=
      {
         @Parameter(name="table", value="dossier_seq"),
         @Parameter(name="column", value="id"),
         @Parameter(name="max_lo", value="0"),
         @Parameter(name="primaryKeyGetter", value="getIdDossierREG"),
         @Parameter(name="fieldSetter", value="setNumero"),
         @Parameter(name="returnIncrementedValue", value="true")
      }
   )
   public DossierREGId getIdDossierREG() {
      return idDossierREG;
   }
   public void setIdDossierREG(DossierREGId idDossierREG) {
      this.idDossierREG = idDossierREG;
      if(idDossierWeb == null)
      {
         try
         {
            idDossierWeb = Long.parseLong(idDossierREG.getNumero());
         }
         catch(NumberFormatException e) {}
      }
   }
   @Transient
   @NotNull
   @Valid
   public String getNumero()
   {
      return idDossierREG.getNumero();
   }
   public void setNumero(String numero)
   {
      idDossierREG.setNumero(numero);
   }
   @ManyToOne
   @JoinColumn(name="action_id", insertable=false, updatable=false)
   @NotNull
   @Valid
   public Action getAction()
   {
      return idDossierREG.getAction();
   }
   public void setAction(Action action)
   {
      idDossierREG.setAction(action);
   }
   @Column(name="idweb", precision=10)
   public Long getIdDossierWeb() {
      return idDossierWeb;
   }
   public void setIdDossierWeb(Long idDossierWeb) {
      this.idDossierWeb = idDossierWeb;
   }
   @OneToMany(mappedBy="dossierREG")
   @Cascade({CascadeType.ALL})
   @JoinColumns
   ({
      @JoinColumn(name="dossier_id", referencedColumnName="id"),
      @JoinColumn(name="action_id", referencedColumnName="action_id")
   })
   public Set<Beneficiaire> getBeneficiaires() throws Exception {
      return beneficiaires;
   }
   public void setBeneficiaires(Set<Beneficiaire> beneficiaires) {
      this.beneficiaires = beneficiaires;
   }
   public DossierREG()
   {
      idDossierREG = new DossierREGId();
   }
   
   @Override
   public boolean equals(Object obj)
   {
      if(!(obj instanceof DossierREG))
         return false;
      DossierREG dossier = (DossierREG)obj;
      return
         new EqualsBuilder()
         .append(dossier.getIdDossierREG(), getIdDossierREG())
         .isEquals();
   }
   
   @Override
   public int hashCode()
   {
      return
         new HashCodeBuilder()
         .append(getIdDossierREG())
         .toHashCode();
   }
}
DossierREGId.java
Code:
@Embeddable
public class DossierREGId implements Serializable
{
   public static final String FIELD_NUMERO         = "numero";
   public static final String FIELD_ACTION         = "action";
   
   private static final long serialVersionUID = 594721741357431918L;
   private String numero;
   private Action action;
   
   public String getNumero() {
      return numero;
   }
   public void setNumero(String numero) {
      this.numero = numero;
   }
   public void setNumero(Long numero) {
      setNumero(numero.toString());
   }
   @ManyToOne
   public Action getAction() {
      return action;
   }
   public void setAction(Action action) {
      this.action = action;
   }
   
   @Override
   public boolean equals(Object obj)
   {
      if(!(obj instanceof DossierREGId))
         return false;
      DossierREGId id = (DossierREGId)obj;
      return
         new EqualsBuilder()
         .append(id.getNumero(), getNumero())
         .append(id.getAction(), getAction())
         .isEquals();
   }
   
   @Override
   public int hashCode()
   {
      return
         new HashCodeBuilder()
         .append(getNumero())
         .append(getAction())
         .toHashCode();
   }
}
Beneficiaire.java
Code:
@Entity
@Table(name="beneficiaire")
public class Beneficiaire implements Serializable
{
   public enum TypeBeneficiaire
   {
      ADHERENT      ("A", "A"),
      FOURNISSEUR      ("F", "F"),
      ORGANISME      ("O", "O"),
      STAGIAIRE      ("S", "S");
      
      private String identifier;
      private String libelle;
      
      public String getIdentifier() {
         return identifier;
      }
      public String getLibelle() {
         return libelle;
      }
      
      private TypeBeneficiaire(String identifier, String libelle)
      {
         this.identifier = identifier;
         this.libelle = libelle;
      }
      
      public static TypeBeneficiaire value(String identifier)
      {
         TypeBeneficiaire result = null;
         for(TypeBeneficiaire typeBeneficiaire: values())
         {
            if(typeBeneficiaire.getIdentifier().equals(identifier))
            {
               result = typeBeneficiaire;
               break;
            }
         }
         return result;
      }
   }
   
   private static final long serialVersionUID = 3872180192633198521L;
   public static final String FIELD_IDBENEFICIAIRE = "identifier";
   public static final String FIELD_DOSSIERREG = "dossierREG";
   public static final String FIELD_ID = "id";
   public static final String FIELD_DEPENSES = "depenses";
   
   private BeneficiaireId identifier;
   private String numeroFacture;
   private Date dateFacture;
   private TypeBeneficiaire typeBeneficiaire;
   private Long stagiaire_Id;
   private Long adherent_Id;
   private Long fournisseur_Id;
   private Long organisme_Id;
   private int id;
   private Set<DepenseBeneficiaire> depenses;
   
   @EmbeddedId
   @AttributeOverrides
   ({
      @AttributeOverride(name="id", column=@Column(name="id", length=10))
   })
   @AssociationOverrides
   ({
      @AssociationOverride
      (
         name="dossierREG",
         joinColumns=
         {
            @JoinColumn(name="dossier_id", referencedColumnName="id"),
            @JoinColumn(name="action_id", referencedColumnName="action_id")
         }
      )
   })
   public BeneficiaireId getIdentifier() {
      return identifier;
   }
   public void setIdentifier(BeneficiaireId identifier) {
      this.identifier = identifier;
   }
   @ManyToOne
   @JoinColumns
   ({
      @JoinColumn(name="dossier_id", referencedColumnName="id", insertable=false, updatable=false),
      @JoinColumn(name="action_id", referencedColumnName="action_id", insertable=false, updatable=false)
   })
   public DossierREG getDossierREG()
   {
      return identifier.getDossierREG();
   }
   public void setDossierREG(DossierREG dossierREG)
   {
      identifier.setDossierREG(dossierREG);
   }
   @Column(name="id")
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   @Column(name="nofact")
   public String getNumeroFacture() {
      return numeroFacture;
   }
   public void setNumeroFacture(String numeroFacture) {
      this.numeroFacture = numeroFacture;
   }
   @Column(name="dtfact")
   @Valid
   public Date getDateFacture() {
      return dateFacture;
   }
   public void setDateFacture(Date dateFacture) {
      this.dateFacture = dateFacture;
   }
   @Column(name="stagiaire_id")
   public void setStagiaire_Id(Long bId) {
      this.stagiaire_Id = bId;
   }
   public Long getStagiaire_Id() {
      return stagiaire_Id;
   }
   @Column(name="fournisseur_id")
   public void setFournisseur_Id(Long bId) {
      this.fournisseur_Id = bId;
   }
   public Long getFournisseur_Id() {
      return fournisseur_Id;
   }
   @Column(name="adherent_id")
   public void setAdherent_Id(Long bId) {
      this.adherent_Id = bId;
   }
   public Long getAdherent_Id() {
      return adherent_Id;
   }
   @Column(name="organisme_id")
   public void setOrganisme_Id(Long bId) {
      this.organisme_Id = bId;
   }
   public Long getOrganisme_Id() {
      return organisme_Id;
   }
   @OneToMany(mappedBy="beneficiaire")
   @Cascade({CascadeType.ALL})
   @JoinColumns
   ({
      @JoinColumn(name="dossier_id", referencedColumnName="dossier_id"),
      @JoinColumn(name="action_id", referencedColumnName="action_id")
   })
   public Set<DepenseBeneficiaire> getDepenses() throws Exception {
      return depenses;
   }
   public void setDepenses(Set<DepenseBeneficiaire> depenses) {
      this.depenses = depenses;
   }
   
   public Beneficiaire()
   {
      identifier = new BeneficiaireId();
   }
   
   public Beneficiaire(int idBeneficiaire, TypeBeneficiaire typeBeneficiaire, Long b_id) {
      this();
      this.typeBeneficiaire = typeBeneficiaire;
      switch(this.typeBeneficiaire) {
         case ADHERENT:       setAdherent_Id(b_id);
                        break;
         case ORGANISME:    setOrganisme_Id(b_id);
                        break;
         case FOURNISSEUR:    setFournisseur_Id(b_id);
                        break;
         case STAGIAIRE:    setStagiaire_Id(b_id);   
                        break;
         default:          break;
      }
      setId(idBeneficiaire);
   }
   public Beneficiaire(DossierREG dossierREG)
   {
      this();
      setDossierREG(dossierREG);
   }
   
   @Override
   public boolean equals(Object obj)
   {
      if(!(obj instanceof Beneficiaire))
         return false;
      Beneficiaire beneficiaire = (Beneficiaire)obj;
      return
         new EqualsBuilder()
         .append(beneficiaire.getIdentifier(), getIdentifier())
         .isEquals();
   }
   
   @Override
   public int hashCode()
   {
      return
         new HashCodeBuilder()
         .append(getIdentifier())
         .toHashCode();
   }
}
BeneficiaireId.java
Code:
@Embeddable
public class BeneficiaireId implements Serializable
{
   private static final long serialVersionUID = -4762088849677965696L;
   public static final String FIELD_DOSSIERREG = "dossierREG";
   
   private DossierREG dossierREG;
   @ManyToOne
   public DossierREG getDossierREG() {
      return dossierREG;
   }
   public void setDossierREG(DossierREG dossierREG) {
      this.dossierREG = dossierREG;
   }
   @Override
   public boolean equals(Object obj)
   {
      if(!(obj instanceof BeneficiaireId))
         return false;
      BeneficiaireId id = (BeneficiaireId)obj;
      return
         new EqualsBuilder()
         .append(id.getDossierREG(), getDossierREG())
         .isEquals();
   }
   
   @Override
   public int hashCode()
   {
      return
         new HashCodeBuilder()
         .append(getDossierREG())
         .toHashCode();
   }
}
DepenseBeneficiaire.java
Code:
@Entity
@Table(name="dep_beneficiaire")
public class DepenseBeneficiaire implements Serializable
{
   public enum NatureDepense
   {
      RTT      ("01",    "Remuneration temps travail"),
      RHTT      ("16",    "Remuneration hors temps travail"),
      AF      ("17",    "Allocation formation"),
      F      ("03",    "Formation"),
      R      ("07",    "Repas"),
      HR      ("08",    "Hebergement repas"),
      T      ("09",    "Transport"),
      D      ("10",    "Divers"),
      LS      ("18",    "Location salle"),
      LM      ("19",    "Location materiel");
      
      private String identifier;
      private String libelle;
      
      public String getIdentifier() {
         return identifier;
      }
      public String getLibelle() {
         return libelle;
      }
      
      private NatureDepense(String identifier, String libelle)
      {
         this.identifier = identifier;
         this.libelle = libelle;
      }
      
      public static NatureDepense value(String identifier)
      {
         NatureDepense result = null;
         for(NatureDepense natureDepense: values())
         {
            if(natureDepense.getIdentifier().equals(identifier))
            {
               result = natureDepense;
               break;
            }
         }
         return result;
      }
   }
   
   
   private static final long serialVersionUID = -508614089121636369L;
   public static final String FIELD_ID = "identifier";
   public static final String FIELD_DOSSIERREG = "dossierREG";
   public static final String FIELD_DEPENSEID = "depense_id";
   public static final String FIELD_BENEFICIAIREID = "beneficiaire_id";
   public static final String FIELD_BENEFICIAIRETYPE = "beneficiaire_type";
   public static final String FIELD_BENEFICIAIRE = "beneficiaire";
   
   private DepenseBeneficiaireId identifier;
   private NatureDepense depense_id;
   private Long beneficiaire_id;
   private String beneficiaire_type;
   
   @EmbeddedId
   @AttributeOverrides
   ({
      @AttributeOverride(name="id", column=@Column(name="id", length=10))
   })
   @AssociationOverrides
   ({
      @AssociationOverride
      (
         name="beneficiaire",
         joinColumns=
         {
            @JoinColumn(name="dossier_id", referencedColumnName="dossier_id"),
            @JoinColumn(name="action_id", referencedColumnName="action_id")
         }
      )
   })
   public DepenseBeneficiaireId getIdentifier() {
      return identifier;
   }
   public void setIdentifier(DepenseBeneficiaireId identifier) {
      this.identifier = identifier;
   }
   @ManyToOne
   @JoinColumns
   ({
      @JoinColumn(name="dossier_id", referencedColumnName="id", insertable=false, updatable=false),
      @JoinColumn(name="action_id", referencedColumnName="action_id", insertable=false, updatable=false)
   })
   public DossierREG getDossierREG()
   {
      return identifier.getDossierREG();
   }
   public void setDossierREG(DossierREG dossierREG)
   {
      identifier.setDossierREG(dossierREG);
   }
   @Column(name="depense_id")
   @Type
   (
      type="fr.site.hibernate.utils.GenericEnumUserType",
      parameters=
      {
         @Parameter(name="enumClassName", value="fr.site.hibernate.classes.DepenseBeneficiaire$NatureDepense"),
         @Parameter(name="valueOfMethod", value="value")
      }
   )
   public void setDepense_id(NatureDepense depense_id) {
      this.depense_id = depense_id;
   }
   public NatureDepense getDepense_id() {
      return depense_id;
   }
   @Column(name="beneficiaire_id")
   public void setBeneficiaire_id(Long beneficiaire_id) {
      this.beneficiaire_id = beneficiaire_id;
   }
   public Long getBeneficiaire_id() {
      return beneficiaire_id;
   }
   @Column(name="beneficaire_type")
   public void setBeneficiaire_type(String beneficiaire_type) {
      this.beneficiaire_type = beneficiaire_type;
   }
   public String getBeneficiaire_type() {
      return beneficiaire_type;
   }
   
   public DepenseBeneficiaire()
   {
      identifier = new DepenseBeneficiaireId();
   }
   public DepenseBeneficiaire(DossierREG dossierREG)
   {
      this();
      setDossierREG(dossierREG);
   }
   @Override
   public boolean equals(Object obj)
   {
      if(!(obj instanceof DepenseBeneficiaire))
         return false;
      DepenseBeneficiaire DepenseBeneficiaire = (DepenseBeneficiaire)obj;
      return
         new EqualsBuilder()
         .append(DepenseBeneficiaire.getIdentifier(), getIdentifier())
         .isEquals();
   }
   
   @Override
   public int hashCode()
   {
      return
         new HashCodeBuilder()
         .append(getIdentifier())
         .toHashCode();
   }
}
DepenseBeneficiaireId.java
Code:
@Embeddable
public class DepenseBeneficiaireId implements Serializable
{
   private static final long serialVersionUID = 4891427738954480255L;
   public static final String FIELD_DOSSIERREG = "dossierREG";
   public static final String FIELD_BENEFICIAIRE = "beneficiaire";
   
   private DossierREG dossierREG;
   private Beneficiaire beneficiaire;
   
   @ManyToOne
   public DossierREG getDossierREG() {
      return dossierREG;
   }
   public void setDossierREG(DossierREG dossierREG) {
      this.dossierREG = dossierREG;
   }
   @ManyToOne
   public Beneficiaire getBeneficiaire() {
      return beneficiaire;
   }
   public void setBeneficiaire(Beneficiaire beneficiaire) {
      this.beneficiaire = beneficiaire;
   }
   
   @Override
   public boolean equals(Object obj)
   {
      if(!(obj instanceof DepenseBeneficiaireId))
         return false;
      DepenseBeneficiaireId id = (DepenseBeneficiaireId)obj;
      return
         new EqualsBuilder()
         .append(id.getDossierREG(), getDossierREG())
         .isEquals();
   }
   
   @Override
   public int hashCode()
   {
      return
         new HashCodeBuilder()
         .append(getDossierREG())
         .toHashCode();
   }
}
J'ai aussi posté sur developpez.com : 
http://www.developpez.net/forums/d10061 ... d-generes/ et dans la partie anglophone de ce forum.