diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/ExceptionLocalizationResource.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/ExceptionLocalizationResource.java index 54e22ec3ab0..ee190a9c3da 100644 --- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/ExceptionLocalizationResource.java +++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/ExceptionLocalizationResource.java @@ -148,7 +148,7 @@ public class ExceptionLocalizationResource extends ListResourceBundle { { "metamodel_managed_type_attribute_not_present", "The attribute [{0}] is not present in the managed type [{1}]." }, { "metamodel_managed_type_attribute_type_incorrect", "Expected attribute type [{2}] on the existing attribute [{0}] on the managed type [{1}] but found attribute type [{3}]." }, { "metamodel_identifiable_version_attribute_type_incorrect", "Expected version attribute type [{2}] on the existing version attribute [{0}] on the identifiable type [{1}] but found attribute type [{3}]." }, - { "metamodel_identifiable_id_attribute_type_incorrect", "Expected id attribute type [{2}] on the existing id attribute [{0}] on the identifiable type [{1}] but found attribute type [{3}]." }, + { "metamodel_identifiable_id_attribute_type_incorrect", "Expected id attribute type [{2}] in the existing id attributes [{0}] on the identifiable type [{1}] but found attribute types [{3}]." }, { "metamodel_managed_type_declared_attribute_not_present_but_is_on_superclass", "The declared attribute [{0}] from the managed type [{1}] is not present - however, it is declared on a superclass." }, { "metamodel_managed_type_attribute_return_type_incorrect", "Expected attribute return type [{2}] on the existing attribute [{0}] on the managed type [{1}] but found attribute return type [{3}]." }, { "metamodel_incompatible_persistence_config_for_getIdType", "Incompatible persistence configuration getting Metamodel Id Type for the ManagedType [{0}]." }, diff --git a/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/metamodel/Bar.java b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/metamodel/Bar.java new file mode 100644 index 00000000000..be7fc6fe455 --- /dev/null +++ b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/metamodel/Bar.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +// Contributors: +// Oracle - initial API and implementation from Oracle +package org.eclipse.persistence.testing.models.jpa.metamodel; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name="CMP3_MM_BAR") +public class Bar { + + @Id + private Long id; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + +} diff --git a/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/metamodel/Foo.java b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/metamodel/Foo.java new file mode 100644 index 00000000000..926d5fa250d --- /dev/null +++ b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/metamodel/Foo.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +// Contributors: +// Oracle - initial API and implementation from Oracle +package org.eclipse.persistence.testing.models.jpa.metamodel; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import java.util.List; + +@Entity +@Table(name="CMP3_MM_FOO") +public class Foo { + + @Id + private Long id; + + @OneToMany(mappedBy = "foo") + private List fooBars; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public List getFooBars() { + return fooBars; + } + + public void setFooBars(List fooBars) { + this.fooBars = fooBars; + } + +} diff --git a/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/metamodel/FooBar.java b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/metamodel/FooBar.java new file mode 100644 index 00000000000..e64f2202eda --- /dev/null +++ b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/metamodel/FooBar.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +// Contributors: +// Oracle - initial API and implementation from Oracle +package org.eclipse.persistence.testing.models.jpa.metamodel; + +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapsId; +import jakarta.persistence.Table; + +@Entity +@Table(name="CMP3_MM_FOOBAR") +public class FooBar { + + @EmbeddedId + private FooBarId id; + + @ManyToOne + @JoinColumn(name = "bar_id") + @MapsId("barId") + private Bar bar; + + @ManyToOne + @JoinColumn(name = "foo_id") + @MapsId("fooId") + private Foo foo; + + public FooBarId getId() { + return id; + } + + public void setId(FooBarId id) { + this.id = id; + } + + public Bar getBar() { + return bar; + } + + public void setBar(Bar bar) { + this.bar = bar; + } + + public Foo getFoo() { + return foo; + } + + public void setFoo(Foo foo) { + this.foo = foo; + } + +} diff --git a/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/metamodel/FooBarId.java b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/metamodel/FooBarId.java new file mode 100644 index 00000000000..1d55506f2b9 --- /dev/null +++ b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/models/jpa/metamodel/FooBarId.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +// Contributors: +// Oracle - initial API and implementation from Oracle +package org.eclipse.persistence.testing.models.jpa.metamodel; + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import java.io.Serializable; +import java.util.Objects; + +@Embeddable +public class FooBarId implements Serializable { + + @Column(name = "foo_id") + private Long fooId; + + @Column(name = "bar_id") + private Long barId; + + public Long getFooId() { + return fooId; + } + + public void setFooId(Long fooId) { + this.fooId = fooId; + } + + public Long getBarId() { + return barId; + } + + public void setBarId(Long barId) { + this.barId = barId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FooBarId fooBarId = (FooBarId) o; + return fooId.equals(fooBarId.fooId) && barId.equals(fooBarId.barId); + } + + @Override + public int hashCode() { + return Objects.hash(fooId, barId); + } +} diff --git a/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/tests/jpa/metamodel/MetamodelMetamodelTest.java b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/tests/jpa/metamodel/MetamodelMetamodelTest.java index a8ae56d6615..9ad364550d4 100644 --- a/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/tests/jpa/metamodel/MetamodelMetamodelTest.java +++ b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/tests/jpa/metamodel/MetamodelMetamodelTest.java @@ -82,6 +82,8 @@ import org.eclipse.persistence.testing.models.jpa.metamodel.EmbeddedPK; import org.eclipse.persistence.testing.models.jpa.metamodel.Enclosure; import org.eclipse.persistence.testing.models.jpa.metamodel.EnclosureIdClassPK; +import org.eclipse.persistence.testing.models.jpa.metamodel.FooBar; +import org.eclipse.persistence.testing.models.jpa.metamodel.FooBarId; import org.eclipse.persistence.testing.models.jpa.metamodel.GalacticPosition; import org.eclipse.persistence.testing.models.jpa.metamodel.HardwareDesigner; import org.eclipse.persistence.testing.models.jpa.metamodel.MSRootPropertyAccess; @@ -125,9 +127,9 @@ */ public class MetamodelMetamodelTest extends MetamodelTest { - public static final int METAMODEL_ALL_ATTRIBUTES_SIZE = 150;//6; + public static final int METAMODEL_ALL_ATTRIBUTES_SIZE = 158;//6; // Note: Since BasicTypes are lazy - loaded into the metamodel-types Map - this test must preceed any test that verifies all BasicType objects like "testIdentifiableType_getIdType_Method" - public static final int METAMODEL_ALL_TYPES = 52; + public static final int METAMODEL_ALL_TYPES = 56; public static final int METAMODEL_MANUFACTURER_DECLARED_TYPES = 28; // Get # of processor cores (hard cores + hyperthreaded cores) public static final int numberProcessingUnits = Runtime.getRuntime().availableProcessors(); @@ -202,6 +204,7 @@ public static Test suite() { suite.addTest(new MetamodelMetamodelTest("testIdentifiableType_getVersion_Method")); suite.addTest(new MetamodelMetamodelTest("testIdentifiableType_getDeclaredId_Method")); suite.addTest(new MetamodelMetamodelTest("testIdentifiableType_getId_Method")); + suite.addTest(new MetamodelMetamodelTest("testIdentifiableType_getId_with_EmbeddedId_Method")); suite.addTest(new MetamodelMetamodelTest("testIdentifiableType_getDeclaredId_normal_execution_attribute_is_declared")); suite.addTest(new MetamodelMetamodelTest("testIdentifiableType_getDeclaredId_variant_execution_attribute_is_declared_above")); suite.addTest(new MetamodelMetamodelTest("testIdentifiableType_getDeclaredId_variant_execution_attribute_is_not_declared_at_all")); @@ -1702,6 +1705,42 @@ public void testIdentifiableType_getId_Method() { } } + public void testIdentifiableType_getId_with_EmbeddedId_Method() { + EntityManager em = null; + boolean expectedIAExceptionThrown = false; + try { + em = privateTestSetup(); + assertNotNull(em); + Metamodel metamodel = em.getMetamodel(); + assertNotNull(metamodel); + EntityType fooBarEntityType = metamodel.entity(FooBar.class); + assertNotNull(fooBarEntityType); + assertTrue(fooBarEntityType.hasSingleIdAttribute()); + + // Actual Test Case + /** + * Return the attribute that corresponds to the id attribute of + * the entity or mapped superclass. + * @param type the type of the represented id attribute + * @return id attribute + * @throws IllegalArgumentException if id attribute of the given + * type is not present in the identifiable type or if + * the identifiable type has an id class + */ + // SingularAttribute getId(Class type); + + SingularAttribute fooBarId = fooBarEntityType.getId(FooBarId.class); + //FooBarId declared by @EmbeddedId + assertNotNull(fooBarId); + } catch (IllegalArgumentException iae) { + iae.printStackTrace(); + expectedIAExceptionThrown = true; + } finally { + cleanup(em); + assertFalse("An IAE exception should not occur here.", expectedIAExceptionThrown); + } + } + public void testIdentifiableType_getVersion_Method() { EntityManager em = null; boolean expectedIAExceptionThrown = false; diff --git a/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/tests/jpa/metamodel/MetamodelTableCreator.java b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/tests/jpa/metamodel/MetamodelTableCreator.java index 2bf46b584a1..64a6da348d4 100644 --- a/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/tests/jpa/metamodel/MetamodelTableCreator.java +++ b/jpa/eclipselink.jpa.test/src/it/java/org/eclipse/persistence/testing/tests/jpa/metamodel/MetamodelTableCreator.java @@ -98,6 +98,9 @@ public MetamodelTableCreator() { addTableDefinition(buildCMP3_MM_BOARD_SEQTable()); addTableDefinition(buildCMP3_MM_PERSON_SEQTable()); addTableDefinition(buildCMP3_MM_MANUF_CMP3_MM_MANUFTable()); + addTableDefinition(buildCMP3_MM_BARTable()); + addTableDefinition(buildCMP3_MM_FOOTable()); + addTableDefinition(buildCMP3_MM_FOOBARTable()); } @@ -2355,5 +2358,65 @@ public static TableDefinition buildCMP3_MM_MANUF_CMP3_MM_MANUFTable() { return table; } + public static TableDefinition buildCMP3_MM_BARTable() { + TableDefinition table = new TableDefinition(); + table.setName("CMP3_MM_BAR"); + + FieldDefinition field = new FieldDefinition(); + field.setName("ID"); + field.setTypeName("NUMERIC"); + field.setSize(15); + field.setShouldAllowNull(false); + field.setIsPrimaryKey(true); + field.setUnique(false); + field.setIsIdentity(true); + table.addField(field); + + return table; + } + + public static TableDefinition buildCMP3_MM_FOOTable() { + TableDefinition table = new TableDefinition(); + table.setName("CMP3_MM_FOO"); + + FieldDefinition field = new FieldDefinition(); + field.setName("ID"); + field.setTypeName("NUMERIC"); + field.setSize(15); + field.setShouldAllowNull(false); + field.setIsPrimaryKey(true); + field.setUnique(false); + field.setIsIdentity(true); + table.addField(field); + + return table; + } + + public static TableDefinition buildCMP3_MM_FOOBARTable() { + TableDefinition table = new TableDefinition(); + table.setName("CMP3_MM_FOOBAR"); + + FieldDefinition field = new FieldDefinition(); + field.setName("bar_id"); + field.setTypeName("NUMERIC"); + field.setSize(15); + field.setShouldAllowNull(false); + field.setIsPrimaryKey(true); + field.setUnique(false); + field.setIsIdentity(true); + table.addField(field); + + FieldDefinition field2 = new FieldDefinition(); + field2.setName("foo_id"); + field2.setTypeName("NUMERIC"); + field2.setSize(15); + field2.setShouldAllowNull(false); + field2.setIsPrimaryKey(true); + field2.setUnique(false); + field2.setIsIdentity(true); + table.addField(field2); + + return table; + } } diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/metamodel/IdentifiableTypeImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/metamodel/IdentifiableTypeImpl.java index 153ca6b9630..3df1b97c5fd 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/metamodel/IdentifiableTypeImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/metamodel/IdentifiableTypeImpl.java @@ -26,6 +26,7 @@ // 08/06/2010-2.2 mobrien 322018 - reduce protected instance variables to private to enforce encapsulation package org.eclipse.persistence.internal.jpa.metamodel; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -196,6 +197,8 @@ public SingularAttribute getId(Class type) { "metamodel_identifiable_id_attribute_is_incorrect_idclass", new Object[] { this })); } else { + List anAttributesMsg = new ArrayList<>(); + List anAttributesJavaTypeMsg = new ArrayList<>(); // verify single id attribute type for(SingularAttribute anAttribute : idAttributes) { // Verify type is correct - relax restriction on null and Object.class (from same classLoader) @@ -203,11 +206,15 @@ public SingularAttribute getId(Class type) { type.getCanonicalName().equals(anAttribute.getJavaType().getCanonicalName())) { idAttribute = (SingularAttribute) anAttribute; } else { - throw new IllegalArgumentException(ExceptionLocalization.buildMessage( - "metamodel_identifiable_id_attribute_type_incorrect", - new Object[] { anAttribute, this, type, anAttribute.getJavaType() })); + anAttributesMsg.add(anAttribute.toString()); + anAttributesJavaTypeMsg.add(anAttribute.getJavaType().toString()); } } + if (idAttribute == null) { + throw new IllegalArgumentException(ExceptionLocalization.buildMessage( + "metamodel_identifiable_id_attribute_type_incorrect", + new Object[] { anAttributesMsg, this, type, anAttributesJavaTypeMsg })); + } } return idAttribute; }