Você estava bem perto de encontrar a solução.
A seguinte configuração funciona:
Pacote Npm
@Entity
@Table(name = "npm_package")
public class NpmPackage {
public NpmPackage(String name, String description) {
this.name = name;
this.description = description;
}
public NpmPackage() {
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
@OneToMany(mappedBy = "npmPackage", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
private List<NpmPackageVersion> versions = new ArrayList<>();
...//getters and setters
public void addVersion(NpmPackageVersion version) {
this.versions.add(version);
version.setNpmPackage(this);
}
public void removeVersion(NpmPackageVersion version) {
this.versions.remove(version);
}
}
NpmPackageVersion
@Entity
@Table(name = "npm_package_version")
public class NpmPackageVersion {
public NpmPackageVersion(String version, License license) {
setVersion(version);
this.license = license;
}
public NpmPackageVersion() {
}
@EmbeddedId
private NpmPackageIdVersion npmPackageIdVersion = new NpmPackageIdVersion();
@MapsId("npmPackageId")
@ManyToOne
private NpmPackage npmPackage;
@ManyToOne
private License license;
public String getVersion() {
return npmPackageIdVersion.version;
}
public void setVersion(String version) {
npmPackageIdVersion.version = version;
}
...//getters and setters
@Embeddable
public static class NpmPackageIdVersion implements Serializable {
private static final long serialVersionUID = 3357194191099820556L;
private Long npmPackageId;
private String version;
... //getters and setters etc.
}
}
Licença
@Entity
@Table(name = "license")
public class License {
public License() {}
public License(String name, String licenseId) {
this.name = name;
this.licenseId = licenseId;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String reference;
@Column(name = "is_deprecated_license_id")
private boolean deprecatedLicenseId;
private Integer referenceNumber;
private String name;
private String licenseId;
@Column(name = "is_osi_approved")
private boolean osiApproved;
... //getters and setters
}
Usei o seguinte código para testar:
@Transactional
public NpmPackage createPackage() {
License license = new License("General Public License", "GPL 2.0");
em.persist(license);
NpmPackage npmPackage = new NpmPackage("react", "React Framework");
npmPackage.addVersion(new NpmPackageVersion("8.11.0", license));
em.persist(npmPackage);
}