From 171167b3c0873a39e98abcded530e997a0919510 Mon Sep 17 00:00:00 2001 From: Christian Wegener Date: Fri, 22 May 2026 22:05:20 +0200 Subject: [PATCH] Fix: @Index(columnNames) at field level is now correctly applied The columnNames attribute of the OpenJPA-specific @Index annotation was not passed to the internal parseIndex overload and therefore silently ignored. A new overload parseIndex(..., String[] columnNames) adds the specified columns to the schema Index object. The existing 4-parameter method delegates to it in a backwards-compatible way. Regression test: TestIndexColumnNames with EntityWithIndexColumnNames --- .../AnnotationPersistenceMappingParser.java | 364 +++++++++--------- .../EntityWithIndexColumnNames.java | 71 ++++ .../annotations/TestIndexColumnNames.java | 73 ++++ 3 files changed, 334 insertions(+), 174 deletions(-) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/EntityWithIndexColumnNames.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestIndexColumnNames.java diff --git a/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java b/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java index 5c99264a77..b561f0f5a6 100644 --- a/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java +++ b/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java @@ -189,16 +189,16 @@ * @author Abe White */ public class AnnotationPersistenceMappingParser - extends AnnotationPersistenceMetaDataParser { + extends AnnotationPersistenceMetaDataParser { protected static final int TRUE = 1; protected static final int FALSE = 2; private static final Localizer _loc = Localizer.forPackage - (AnnotationPersistenceMappingParser.class); + (AnnotationPersistenceMappingParser.class); private static final Map, MappingTag> _tags = - new HashMap<>(); + new HashMap<>(); private DBDictionary _dict; @@ -304,7 +304,7 @@ protected void parsePackageMappingAnnotations(Package pkg) { break; default: throw new UnsupportedException(_loc.get("unsupported", pkg, - anno.toString())); + anno.toString())); } } } @@ -313,7 +313,7 @@ protected void parsePackageMappingAnnotations(Package pkg) { * Allow subclasses to handle unknown annotations. */ protected boolean handleUnknownPackageMappingAnnotation(Package pkg, - Annotation anno) { + Annotation anno) { return false; } @@ -330,7 +330,7 @@ private void parseTableGenerator(AnnotatedElement el, TableGenerator gen) { log.trace(_loc.get("parse-gen", name)); SequenceMapping meta = (SequenceMapping) getRepository(). - getCachedSequenceMetaData(name); + getCachedSequenceMetaData(name); if (meta != null) { if (log.isWarnEnabled()) log.warn(_loc.get("dup-gen", name, el)); @@ -346,19 +346,19 @@ private void parseTableGenerator(AnnotatedElement el, TableGenerator gen) { meta.setInitialValue(gen.initialValue()); meta.setAllocate(gen.allocationSize()); meta.setSource(getSourceFile(), (el instanceof Class) ? el : null, - SourceTracker.SRC_ANNOTATIONS); + SourceTracker.SRC_ANNOTATIONS); switch (gen.uniqueConstraints().length) { - case 0: - break; // nothing to do - case 1: - meta.setUniqueColumnsIdentifier(DBIdentifier.toArray(gen.uniqueConstraints()[0].columnNames(), - DBIdentifierType.COLUMN, delimit())); - meta.setUniqueConstraintIdentifier(DBIdentifier.newConstraint(gen.uniqueConstraints()[0].name(), - delimit())); - break; - default: - log.warn(_loc.get("unique-many-on-seq-unsupported", el, name)); + case 0: + break; // nothing to do + case 1: + meta.setUniqueColumnsIdentifier(DBIdentifier.toArray(gen.uniqueConstraints()[0].columnNames(), + DBIdentifierType.COLUMN, delimit())); + meta.setUniqueConstraintIdentifier(DBIdentifier.newConstraint(gen.uniqueConstraints()[0].name(), + delimit())); + break; + default: + log.warn(_loc.get("unique-many-on-seq-unsupported", el, name)); } } @@ -381,26 +381,26 @@ protected void parseClassMappingAnnotations(ClassMetaData meta) { break; case ASSOC_OVERRIDES: parseAssociationOverrides(cm, ((AssociationOverrides) anno). - value()); + value()); break; case ATTR_OVERRIDE: parseAttributeOverrides(cm, (AttributeOverride) anno); break; case ATTR_OVERRIDES: parseAttributeOverrides(cm, ((AttributeOverrides) anno). - value()); + value()); break; case DISCRIM_COL: parseDiscriminatorColumn(cm, (DiscriminatorColumn) anno); break; case DISCRIM_VAL: cm.getDiscriminator().getMappingInfo().setValue - (((DiscriminatorValue) anno).value()); + (((DiscriminatorValue) anno).value()); if (Modifier.isAbstract(cm.getDescribedType(). getModifiers()) && getLog().isInfoEnabled()) { getLog().info( - _loc.get("discriminator-on-abstract-class", cm - .getDescribedType().getName())); + _loc.get("discriminator-on-abstract-class", cm + .getDescribedType().getName())); } break; case INHERITANCE: @@ -411,8 +411,8 @@ protected void parseClassMappingAnnotations(ClassMetaData meta) { break; case PK_JOIN_COLS: parsePrimaryKeyJoinColumns(cm, - ((PrimaryKeyJoinColumns) anno). - value()); + ((PrimaryKeyJoinColumns) anno). + value()); break; case SECONDARY_TABLE: parseSecondaryTables(cm, (SecondaryTable) anno); @@ -425,7 +425,7 @@ protected void parseClassMappingAnnotations(ClassMetaData meta) { break; case SQL_RESULT_SET_MAPPINGS: parseSQLResultSetMappings(cm, ((SqlResultSetMappings) anno). - value()); + value()); break; case TABLE: parseTable(cm, (Table) anno); @@ -438,7 +438,7 @@ protected void parseClassMappingAnnotations(ClassMetaData meta) { break; case DISCRIM_STRAT: cm.getDiscriminator().getMappingInfo().setStrategy - (((DiscriminatorStrategy) anno).value()); + (((DiscriminatorStrategy) anno).value()); break; case FK: parseForeignKey(cm.getMappingInfo(), (ForeignKey) anno); @@ -448,14 +448,14 @@ protected void parseClassMappingAnnotations(ClassMetaData meta) { break; case MAPPING_OVERRIDES: parseMappingOverrides(cm, - ((MappingOverrides) anno).value()); + ((MappingOverrides) anno).value()); break; case STRAT: cm.getMappingInfo().setStrategy(((Strategy) anno).value()); break; case SUBCLASS_FETCH_MODE: cm.setSubclassFetchMode(toEagerFetchModeConstant - (((SubclassFetchMode) anno).value())); + (((SubclassFetchMode) anno).value())); break; case VERSION_COL: parseVersionColumns(cm, (VersionColumn) anno); @@ -465,14 +465,14 @@ protected void parseClassMappingAnnotations(ClassMetaData meta) { break; case VERSION_STRAT: cm.getVersion().getMappingInfo().setStrategy - (((VersionStrategy) anno).value()); + (((VersionStrategy) anno).value()); break; case X_MAPPING_OVERRIDE: parseMappingOverrides(cm, (XMappingOverride) anno); break; case X_MAPPING_OVERRIDES: parseMappingOverrides(cm, - ((XMappingOverrides) anno).value()); + ((XMappingOverrides) anno).value()); break; case X_TABLE: case X_SECONDARY_TABLE: @@ -480,7 +480,7 @@ protected void parseClassMappingAnnotations(ClassMetaData meta) { // no break; not supported yet default: throw new UnsupportedException(_loc.get("unsupported", cm, - anno)); + anno)); } } } @@ -489,7 +489,7 @@ protected void parseClassMappingAnnotations(ClassMetaData meta) { * Allow subclasses to handle unknown annotations. */ protected boolean handleUnknownClassMappingAnnotation(ClassMapping cls, - Annotation anno) { + Annotation anno) { return false; } @@ -497,7 +497,7 @@ protected boolean handleUnknownClassMappingAnnotation(ClassMapping cls, * Parse @AssociationOverride(s). */ private void parseAssociationOverrides(ClassMapping cm, - AssociationOverride... assocs) { + AssociationOverride... assocs) { FieldMapping sup; JoinColumn[] scols; int unique; @@ -509,7 +509,7 @@ private void parseAssociationOverrides(ClassMapping cm, sup = (FieldMapping) cm.getDefinedSuperclassField(assoc.name()); if (sup == null) sup = (FieldMapping) cm.addDefinedSuperclassField - (assoc.name(), Object.class, Object.class); + (assoc.name(), Object.class, Object.class); scols = assoc.joinColumns(); joinTbl = assoc.joinTable(); if ((scols == null || scols.length == 0) && joinTbl == null) @@ -535,7 +535,7 @@ private void parseAssociationOverrides(ClassMapping cm, * Parse @AttributeOverride(s). */ private void parseAttributeOverrides(ClassMapping cm, - AttributeOverride... attrs) { + AttributeOverride... attrs) { FieldMapping sup; for (AttributeOverride attr : attrs) { if (StringUtil.isEmpty(attr.name())) @@ -543,7 +543,7 @@ private void parseAttributeOverrides(ClassMapping cm, sup = (FieldMapping) cm.getDefinedSuperclassField(attr.name()); if (sup == null) sup = (FieldMapping) cm.addDefinedSuperclassField(attr.name(), - Object.class, Object.class); + Object.class, Object.class); if (attr.column() != null) parseColumns(sup, attr.column()); } @@ -553,7 +553,7 @@ private void parseAttributeOverrides(ClassMapping cm, * Parse inheritance @PrimaryKeyJoinColumn(s). */ private void parsePrimaryKeyJoinColumns(ClassMapping cm, - PrimaryKeyJoinColumn... joins) { + PrimaryKeyJoinColumn... joins) { List cols = new ArrayList<>(joins.length); for (PrimaryKeyJoinColumn join : joins) cols.add(newColumn(join)); @@ -579,7 +579,7 @@ private Column newColumn(PrimaryKeyJoinColumn join) { * Parse @SecondaryTable(s). */ private void parseSecondaryTables(ClassMapping cm, - SecondaryTable... tables) { + SecondaryTable... tables) { ClassMappingInfo info = cm.getMappingInfo(); List joins = null; @@ -597,7 +597,7 @@ private void parseSecondaryTables(ClassMapping cm, joins.add(newColumn(join)); info.setSecondaryTableJoinColumns(sName, joins); } else { - info.addSecondaryTable(sName); + info.addSecondaryTable(sName); } addUniqueConstraints(sName.getName(), cm, info, table.uniqueConstraints()); } @@ -614,7 +614,7 @@ private void parseTable(ClassMapping cm, Table table) { cm.getMappingInfo().setTableIdentifier(tName); } addUniqueConstraints(tName.getName(), cm, cm.getMappingInfo(), - table.uniqueConstraints()); + table.uniqueConstraints()); addIndices(tName.getName(), cm, cm.getMappingInfo(), table.indexes()); } @@ -639,7 +639,7 @@ Unique createUniqueConstraint(MetaDataContext ctx, UniqueConstraint anno) { } void addUniqueConstraints(String table, MetaDataContext ctx, - MappingInfo info, UniqueConstraint... uniqueConstraints) { + MappingInfo info, UniqueConstraint... uniqueConstraints) { for (UniqueConstraint anno : uniqueConstraints) { Unique unique = createUniqueConstraint(ctx, anno); unique.setTableIdentifier(DBIdentifier.newTable(table, delimit())); @@ -677,7 +677,7 @@ org.apache.openjpa.jdbc.schema.Index createIndex(MetaDataContext ctx, jakarta.pe } void addIndices(String table, MetaDataContext ctx, - MappingInfo info, jakarta.persistence.Index... indices) { + MappingInfo info, jakarta.persistence.Index... indices) { for (jakarta.persistence.Index anno : indices) { org.apache.openjpa.jdbc.schema.Index idx = createIndex(ctx, anno); idx.setTableIdentifier(DBIdentifier.newTable(table, delimit())); @@ -708,7 +708,7 @@ private DBIdentifier toTableIdentifier(String schema, String table) { * {@link SQLResultSetMappingMetaData}. */ private void parseSQLResultSetMappings(ClassMapping cm, - SqlResultSetMapping... annos) { + SqlResultSetMapping... annos) { MappingRepository repos = (MappingRepository) getRepository(); Log log = getLog(); for (SqlResultSetMapping anno : annos) { @@ -716,7 +716,7 @@ private void parseSQLResultSetMappings(ClassMapping cm, log.trace(_loc.get("parse-sqlrsmapping", anno.name())); QueryResultMapping result = repos.getCachedQueryResultMapping - (null, anno.name()); + (null, anno.name()); if (result != null) { if (log.isWarnEnabled()) log.warn(_loc.get("dup-sqlrsmapping", anno.name(), cm)); @@ -725,14 +725,14 @@ private void parseSQLResultSetMappings(ClassMapping cm, result = repos.addQueryResultMapping(null, anno.name()); result.setSource(getSourceFile(), cm.getDescribedType(), - SourceTracker.SRC_ANNOTATIONS); + SourceTracker.SRC_ANNOTATIONS); for (EntityResult entity : anno.entities()) { QueryResultMapping.PCResult entityResult = result.addPCResult - (entity.entityClass()); + (entity.entityClass()); if (!StringUtil.isEmpty(entity.discriminatorColumn())) entityResult.addMapping(PCResult.DISCRIMINATOR, - entity.discriminatorColumn()); + entity.discriminatorColumn()); for (FieldResult field : entity.fields()) { DBIdentifier sColName = DBIdentifier.newColumn(field.column(), delimit()); @@ -753,7 +753,7 @@ private void parseSQLResultSetMappings(ClassMapping cm, * Parse @DiscriminatorColumn. */ private void parseDiscriminatorColumn(ClassMapping cm, - DiscriminatorColumn dcol) { + DiscriminatorColumn dcol) { Column col = new Column(); if (!StringUtil.isEmpty(dcol.name())) { col.setIdentifier(DBIdentifier.newColumn(dcol.name(),delimit())); @@ -779,7 +779,7 @@ private void parseDiscriminatorColumn(ClassMapping cm, discrim.setJavaType(JavaTypes.STRING); } cm.getDiscriminator().getMappingInfo().setColumns - (Arrays.asList(new Column[]{ col })); + (Arrays.asList(new Column[]{ col })); } /** @@ -806,7 +806,7 @@ private void parseInheritance(ClassMapping cm, Inheritance inherit) { * Parse class-level @MappingOverride(s). */ private void parseMappingOverrides(ClassMapping cm, - MappingOverride... overs) { + MappingOverride... overs) { FieldMapping sup; for (MappingOverride over : overs) { if (StringUtil.isEmpty(over.name())) @@ -814,7 +814,7 @@ private void parseMappingOverrides(ClassMapping cm, sup = (FieldMapping) cm.getDefinedSuperclassField(over.name()); if (sup == null) sup = (FieldMapping) cm.addDefinedSuperclassField(over.name(), - Object.class, Object.class); + Object.class, Object.class); populate(sup, over); } } @@ -851,28 +851,28 @@ private void parseDataStoreIdColumn(ClassMapping cm, DataStoreIdColumn id) { * Parse the given foreign key. */ private void parseForeignKey(MappingInfo info, ForeignKey fk) { - if (!fk.implicit()) { - parseForeignKey(info, fk.name(), fk.enabled(), fk.deferred(), - fk.deleteAction(), fk.updateAction()); - } else { + if (!fk.implicit()) { + parseForeignKey(info, fk.name(), fk.enabled(), fk.deferred(), + fk.deleteAction(), fk.updateAction()); + } else { info.setImplicitRelation(true); assertDefault(fk); - } + } } /** * Set foreign key data on the given mapping info. */ protected void parseForeignKey(MappingInfo info, String name, - boolean enabled, boolean deferred, ForeignKeyAction deleteAction, - ForeignKeyAction updateAction) { + boolean enabled, boolean deferred, ForeignKeyAction deleteAction, + ForeignKeyAction updateAction) { if (!enabled) { info.setCanForeignKey(false); return; } org.apache.openjpa.jdbc.schema.ForeignKey fk = - new org.apache.openjpa.jdbc.schema.ForeignKey(); + new org.apache.openjpa.jdbc.schema.ForeignKey(); if (!StringUtil.isEmpty(name)) fk.setIdentifier(DBIdentifier.newForeignKey(name, delimit())); fk.setDeferred(deferred); @@ -883,15 +883,15 @@ protected void parseForeignKey(MappingInfo info, String name, void assertDefault(ForeignKey fk) { boolean isDefault = StringUtil.isEmpty(fk.name()) - && fk.enabled() - && !fk.deferred() + && fk.enabled() + && !fk.deferred() && fk.deleteAction() == ForeignKeyAction.RESTRICT && fk.updateAction() == ForeignKeyAction.RESTRICT - && fk.columnNames().length == 0 - && fk.specified(); + && fk.columnNames().length == 0 + && fk.specified(); if (!isDefault) throw new UserException(_loc.get("implicit-non-default-fk", _cls, - getSourceFile()).getMessage()); + getSourceFile()).getMessage()); } @@ -918,24 +918,40 @@ private int toForeignKeyAction(ForeignKeyAction action) { * Parse the given index. */ private void parseIndex(MappingInfo info, Index idx) { - parseIndex(info, idx.name(), idx.enabled(), idx.unique()); + parseIndex(info, idx.name(), idx.enabled(), idx.unique(), idx.columnNames()); } /** * Set index data on the given mapping info. */ protected void parseIndex(MappingInfo info, String name, - boolean enabled, boolean unique) { + boolean enabled, boolean unique) { + parseIndex(info, name, enabled, unique, null); + } + + /** + * Set index data on the given mapping info, including optional explicit column names. + */ + protected void parseIndex(MappingInfo info, String name, + boolean enabled, boolean unique, String[] columnNames) { if (!enabled) { info.setCanIndex(false); return; } org.apache.openjpa.jdbc.schema.Index idx = - new org.apache.openjpa.jdbc.schema.Index(); + new org.apache.openjpa.jdbc.schema.Index(); if (!StringUtil.isEmpty(name)) idx.setIdentifier(DBIdentifier.newConstraint(name, delimit())); idx.setUnique(unique); + + if (columnNames != null) for (String columnName : columnNames) { + org.apache.openjpa.jdbc.schema.Column column = + new org.apache.openjpa.jdbc.schema.Column(); + column.setIdentifier(DBIdentifier.newColumn(columnName, delimit())); + idx.addColumn(column); + } + info.setIndex(idx); } @@ -943,7 +959,7 @@ protected void parseIndex(MappingInfo info, String name, * Set unique data on the given mapping info. */ private void parseUnique(FieldMapping fm, - org.apache.openjpa.persistence.jdbc.Unique anno) { + org.apache.openjpa.persistence.jdbc.Unique anno) { ValueMappingInfo info = fm.getValueInfo(); if (!anno.enabled()) { info.setCanUnique(false); @@ -951,7 +967,7 @@ private void parseUnique(FieldMapping fm, } org.apache.openjpa.jdbc.schema.Unique unq = - new org.apache.openjpa.jdbc.schema.Unique(); + new org.apache.openjpa.jdbc.schema.Unique(); if (!StringUtil.isEmpty(anno.name())) unq.setIdentifier(DBIdentifier.newIndex(anno.name(), delimit())); unq.setDeferred(anno.deferred()); @@ -976,15 +992,15 @@ private void parseVersionColumns(ClassMapping cm, VersionColumn... vcols) { */ private static Column newColumn(VersionColumn anno, boolean delimit) { return newColumn(anno.name(), - anno.nullable(), - anno.insertable(), - anno.updatable(), - anno.columnDefinition(), - anno.length(), - anno.precision(), - anno.scale(), - anno.table(), - delimit); + anno.nullable(), + anno.insertable(), + anno.updatable(), + anno.columnDefinition(), + anno.length(), + anno.precision(), + anno.scale(), + anno.table(), + delimit); } static Column newColumn(String name, @@ -1011,7 +1027,7 @@ else if (length != 255) col.setTypeIdentifier(DBIdentifier.newColumnDefinition(columnDefinition)); col.setType(Schemas.getJDBCType(col.getTypeIdentifier().getName())); col.setJavaType(JavaTypes.getTypeCode(Schemas.getJavaType - (col.getType(), col.getSize(), col.getDecimalDigits()))); + (col.getType(), col.getSize(), col.getDecimalDigits()))); } col.setFlag(Column.FLAG_UNINSERTABLE, !insertable); col.setFlag(Column.FLAG_UNUPDATABLE, !updatable); @@ -1023,7 +1039,7 @@ else if (length != 255) * Parse class-level @XMappingOverride(s). */ private void parseMappingOverrides(ClassMapping cm, - XMappingOverride... overs) { + XMappingOverride... overs) { FieldMapping sup; for (XMappingOverride over : overs) { if (StringUtil.isEmpty(over.name())) @@ -1031,7 +1047,7 @@ private void parseMappingOverrides(ClassMapping cm, sup = (FieldMapping) cm.getDefinedSuperclassField(over.name()); if (sup == null) sup = (FieldMapping) cm.addDefinedSuperclassField(over.name(), - Object.class, Object.class); + Object.class, Object.class); populate(sup, over); } } @@ -1141,9 +1157,9 @@ private static int toEagerFetchModeConstant(FetchMode mode) { protected void parseLobMapping(FieldMetaData fmd) { Column col = new Column(); int typeCode = fmd.isElementCollection() ? fmd.getElement().getDeclaredTypeCode() : - fmd.getDeclaredTypeCode(); + fmd.getDeclaredTypeCode(); Class type = fmd.isElementCollection() ? fmd.getElement().getDeclaredType() : - fmd.getDeclaredType(); + fmd.getDeclaredType(); if (typeCode == JavaTypes.STRING || type == char[].class @@ -1162,7 +1178,7 @@ protected void parseLobMapping(FieldMetaData fmd) { protected void parseMemberMappingAnnotations(FieldMetaData fmd) { FieldMapping fm = (FieldMapping) fmd; AnnotatedElement el = (AnnotatedElement) getRepository(). - getMetaDataFactory().getDefaults().getBackingMember(fmd); + getMetaDataFactory().getDefaults().getBackingMember(fmd); MappingTag tag; for (Annotation anno : el.getDeclaredAnnotations()) { @@ -1178,14 +1194,14 @@ protected void parseMemberMappingAnnotations(FieldMetaData fmd) { break; case ASSOC_OVERRIDES: parseAssociationOverrides(fm, ((AssociationOverrides) anno). - value()); + value()); break; case ATTR_OVERRIDE: parseAttributeOverrides(fm, (AttributeOverride) anno); break; case ATTR_OVERRIDES: parseAttributeOverrides(fm, ((AttributeOverrides) anno). - value()); + value()); break; case COL: parseColumns(fm, (jakarta.persistence.Column) anno); @@ -1207,7 +1223,7 @@ protected void parseMemberMappingAnnotations(FieldMetaData fmd) { break; case KEY_CLASS_CRIT: fm.getKeyMapping().getValueInfo().setUseClassCriteria - (((KeyClassCriteria) anno).value()); + (((KeyClassCriteria) anno).value()); break; case KEY_COL: parseKeyColumns(fm, (KeyColumn) anno); @@ -1218,20 +1234,20 @@ protected void parseMemberMappingAnnotations(FieldMetaData fmd) { case KEY_EMBEDDED_MAPPING: KeyEmbeddedMapping kembed = (KeyEmbeddedMapping) anno; parseEmbeddedMapping(fm.getKeyMapping(), - DBIdentifier.newColumn(kembed.nullIndicatorColumnName(), delimit()), - DBIdentifier.newConstant(kembed.nullIndicatorAttributeName()), - kembed.overrides()); + DBIdentifier.newColumn(kembed.nullIndicatorColumnName(), delimit()), + DBIdentifier.newConstant(kembed.nullIndicatorAttributeName()), + kembed.overrides()); break; case KEY_FK: KeyForeignKey kfk = (KeyForeignKey) anno; parseForeignKey(fm.getKeyMapping().getValueInfo(), - kfk.name(), kfk.enabled(), kfk.deferred(), - kfk.deleteAction(), kfk.updateAction()); + kfk.name(), kfk.enabled(), kfk.deferred(), + kfk.deleteAction(), kfk.updateAction()); break; case KEY_INDEX: KeyIndex kidx = (KeyIndex) anno; parseIndex(fm.getKeyMapping().getValueInfo(), kidx.name(), - kidx.enabled(), kidx.unique()); + kidx.enabled(), kidx.unique()); break; case KEY_JOIN_COL: parseKeyJoinColumns(fm, (KeyJoinColumn) anno); @@ -1241,11 +1257,11 @@ protected void parseMemberMappingAnnotations(FieldMetaData fmd) { break; case KEY_NONPOLY: fm.getKeyMapping().setPolymorphic(toPolymorphicConstant - (((KeyNonpolymorphic) anno).value())); + (((KeyNonpolymorphic) anno).value())); break; case KEY_STRAT: fm.getKeyMapping().getValueInfo() - .setStrategy(((KeyStrategy) anno).value()); + .setStrategy(((KeyStrategy) anno).value()); break; case MAP_KEY_COL: parseMapKeyColumn(fm, (MapKeyColumn) anno); @@ -1258,15 +1274,15 @@ protected void parseMemberMappingAnnotations(FieldMetaData fmd) { break; case MAP_KEY_JOIN_COLS: parseMapKeyJoinColumns(fm, - ((MapKeyJoinColumns) anno).value()); + ((MapKeyJoinColumns) anno).value()); break; case PK_JOIN_COL: parsePrimaryKeyJoinColumns(fm, (PrimaryKeyJoinColumn) anno); break; case PK_JOIN_COLS: parsePrimaryKeyJoinColumns(fm, - ((PrimaryKeyJoinColumns) anno). - value()); + ((PrimaryKeyJoinColumns) anno). + value()); break; case TABLE_GEN: parseTableGenerator(el, (TableGenerator) anno); @@ -1279,7 +1295,7 @@ protected void parseMemberMappingAnnotations(FieldMetaData fmd) { break; case CLASS_CRIT: fm.getValueInfo().setUseClassCriteria - (((ClassCriteria) anno).value()); + (((ClassCriteria) anno).value()); break; case CONTAINER_TABLE: parseContainerTable(fm, (ContainerTable) anno); @@ -1289,11 +1305,11 @@ protected void parseMemberMappingAnnotations(FieldMetaData fmd) { break; case EAGER_FETCH_MODE: fm.setEagerFetchMode(toEagerFetchModeConstant - (((EagerFetchMode) anno).value())); + (((EagerFetchMode) anno).value())); break; case ELEM_CLASS_CRIT: fm.getElementMapping().getValueInfo().setUseClassCriteria - (((ElementClassCriteria) anno).value()); + (((ElementClassCriteria) anno).value()); break; case ELEM_COL: parseElementColumns(fm, (ElementColumn) anno); @@ -1304,35 +1320,35 @@ protected void parseMemberMappingAnnotations(FieldMetaData fmd) { case ELEM_EMBEDDED_MAPPING: ElementEmbeddedMapping ee = (ElementEmbeddedMapping) anno; parseEmbeddedMapping(fm.getElementMapping(), - DBIdentifier.newConstant(ee.nullIndicatorAttributeName()), - DBIdentifier.newColumn(ee.nullIndicatorColumnName(), delimit()), - ee.overrides()); + DBIdentifier.newConstant(ee.nullIndicatorAttributeName()), + DBIdentifier.newColumn(ee.nullIndicatorColumnName(), delimit()), + ee.overrides()); break; case ELEM_FK: ElementForeignKey efk = (ElementForeignKey) anno; parseForeignKey(fm.getElementMapping().getValueInfo(), - efk.name(), efk.enabled(), efk.deferred(), - efk.deleteAction(), efk.updateAction()); + efk.name(), efk.enabled(), efk.deferred(), + efk.deleteAction(), efk.updateAction()); break; case ELEM_INDEX: ElementIndex eidx = (ElementIndex) anno; parseIndex(fm.getElementMapping().getValueInfo(), - eidx.name(), eidx.enabled(), eidx.unique()); + eidx.name(), eidx.enabled(), eidx.unique()); break; case ELEM_JOIN_COL: parseElementJoinColumns(fm, (ElementJoinColumn) anno); break; case ELEM_JOIN_COLS: parseElementJoinColumns(fm, ((ElementJoinColumns) anno). - value()); + value()); break; case ELEM_NONPOLY: fm.getElementMapping().setPolymorphic(toPolymorphicConstant - (((ElementNonpolymorphic) anno).value())); + (((ElementNonpolymorphic) anno).value())); break; case ELEM_STRAT: fm.getElementMapping().getValueInfo() - .setStrategy(((ElementStrategy) anno).value()); + .setStrategy(((ElementStrategy) anno).value()); break; case EMBEDDED_MAPPING: parseEmbeddedMapping(fm, (EmbeddedMapping) anno); @@ -1345,11 +1361,11 @@ protected void parseMemberMappingAnnotations(FieldMetaData fmd) { break; case NONPOLY: fm.setPolymorphic(toPolymorphicConstant - (((Nonpolymorphic) anno).value())); + (((Nonpolymorphic) anno).value())); break; case ORDER_COLUMN: parseJavaxOrderColumn(fm, - (jakarta.persistence.OrderColumn)anno); + (jakarta.persistence.OrderColumn)anno); break; case ORDER_COL: parseOrderColumn(fm, (OrderColumn) anno); @@ -1359,24 +1375,24 @@ protected void parseMemberMappingAnnotations(FieldMetaData fmd) { break; case UNIQUE: parseUnique(fm, - (org.apache.openjpa.persistence.jdbc.Unique) anno); + (org.apache.openjpa.persistence.jdbc.Unique) anno); break; case X_EMBEDDED_MAPPING: XEmbeddedMapping embed = (XEmbeddedMapping) anno; parseEmbeddedMapping(fm, DBIdentifier.newColumn(embed.nullIndicatorColumnName(), delimit()), - DBIdentifier.newConstant(embed.nullIndicatorAttributeName()), embed.overrides()); + DBIdentifier.newConstant(embed.nullIndicatorAttributeName()), embed.overrides()); break; case X_JOIN_COL: parseXJoinColumns(fm, fm.getValueInfo(), true, - (XJoinColumn) anno); + (XJoinColumn) anno); break; case X_JOIN_COLS: parseXJoinColumns(fm, fm.getValueInfo(), true, - ((XJoinColumns) anno).value()); + ((XJoinColumns) anno).value()); break; default: throw new UnsupportedException(_loc.get("unsupported", fm, - anno.toString())); + anno.toString())); } } } @@ -1385,7 +1401,7 @@ protected void parseMemberMappingAnnotations(FieldMetaData fmd) { * Allow subclasses to handle unknown annotations. */ protected boolean handleUnknownMemberMappingAnnotation(FieldMapping fm, - Annotation anno) { + Annotation anno) { return false; } @@ -1410,7 +1426,7 @@ protected static int toPolymorphicConstant(NonpolymorphicType val) { * Parse given @AssociationOverride annotations on an embedded mapping. */ private void parseAssociationOverrides(FieldMapping fm, - AssociationOverride... assocs) { + AssociationOverride... assocs) { FieldMapping efm; JoinColumn[] ecols; @@ -1421,12 +1437,12 @@ private void parseAssociationOverrides(FieldMapping fm, efm = getEmbeddedFieldMapping(fm, assoc.name()); if (efm == null) throw new MetaDataException(_loc.get("embed-override-name", - fm, assoc.name())); + fm, assoc.name())); ecols = assoc.joinColumns(); joinTbl = assoc.joinTable(); if ((ecols == null || ecols.length == 0) && joinTbl == null) throw new MetaDataException(_loc.get("embed-override-name", - fm, assoc.name())); + fm, assoc.name())); if (ecols != null && ecols.length > 0) { unique = 0; jcols = new ArrayList<>(ecols.length); @@ -1445,7 +1461,7 @@ private void parseAssociationOverrides(FieldMapping fm, * Parse given @AttributeOverride annotations on an embedded mapping. */ private void parseAttributeOverrides(FieldMapping fm, - AttributeOverride... attrs) { + AttributeOverride... attrs) { for (AttributeOverride attr : attrs) { String attrName = attr.name(); FieldMapping efm = getEmbeddedFieldMapping(fm, attrName); @@ -1455,7 +1471,7 @@ private void parseAttributeOverrides(FieldMapping fm, } public static FieldMapping getEmbeddedFieldMapping(FieldMapping fm, - String attrName) { + String attrName) { return getEmbeddedFieldMapping(fm, attrName, true); } @@ -1476,23 +1492,23 @@ else if (attrName != null && attrName.startsWith("value.")) case JavaTypes.COLLECTION : // a collection of embeddables if (isKey || isValue) throw new MetaDataException(_loc.get("embed-override-name", - fm, attrName)); + fm, attrName)); embed = fm.getElementMapping().getEmbeddedMapping(); break; case JavaTypes.MAP: // a map if (!isKey && !isValue) throw new MetaDataException(_loc.get("embed-override-name", - fm, attrName)); + fm, attrName)); if (isKey) embed = getEmbeddedMapping(fm.getKeyMapping(), mustExist); else if (isValue) embed = getEmbeddedMapping(fm.getElementMapping(), - mustExist); + mustExist); break; default: // an embeddable if (isKey || isValue) throw new MetaDataException(_loc.get("embed-override-name", - fm, attrName)); + fm, attrName)); embed = getEmbeddedMapping(fm.getValueMapping(), mustExist); break; } @@ -1506,7 +1522,7 @@ else if (isValue) } public static Class getEmbeddedClassType(FieldMapping fm, - String attrName) { + String attrName) { ValueMapping embed = null; boolean isKey = false; boolean isValue = false; @@ -1522,13 +1538,13 @@ else if (attrName != null && attrName.startsWith("value.")) case JavaTypes.COLLECTION : // a collection of embeddables if (isKey || isValue) throw new MetaDataException(_loc.get("embed-override-name", - fm, attrName)); + fm, attrName)); embed = fm.getElementMapping(); break; case JavaTypes.MAP: // a map if (!isKey && !isValue) throw new MetaDataException(_loc.get("embed-override-name", - fm, attrName)); + fm, attrName)); if (isKey) embed = fm.getKeyMapping(); else if (isValue) @@ -1537,7 +1553,7 @@ else if (isValue) default: // an embeddable if (isKey || isValue) throw new MetaDataException(_loc.get("embed-override-name", - fm, attrName)); + fm, attrName)); embed = fm.getValueMapping(); break; } @@ -1549,7 +1565,7 @@ else if (isValue) } public static ClassMapping getEmbeddedMapping(ValueMapping val, boolean - createNew) { + createNew) { ClassMapping embed = val.getEmbeddedMapping(); if (embed != null || !createNew) return embed; @@ -1571,7 +1587,7 @@ public static FieldMapping getAttributeOverrideField(String attrName, efm = embed.getFieldMapping(attrName); if (efm == null) throw new MetaDataException(_loc.get("embed-override-name", - fm, attrName)); + fm, attrName)); return efm; } String attrName1 = attrName.substring(0, idxOfDot); @@ -1579,7 +1595,7 @@ public static FieldMapping getAttributeOverrideField(String attrName, efm = embed.getFieldMapping(attrName1); if (efm == null) throw new MetaDataException(_loc.get("embed-override-name", - fm, attrName1)); + fm, attrName1)); ClassMapping embed1 = getEmbeddedMapping(efm.getValueMapping()); return getAttributeOverrideField(attrName2, efm, embed1); } @@ -1589,7 +1605,7 @@ public static FieldMapping getAttributeOverrideField(String attrName, */ private void parseEnumerated(FieldMapping fm, Enumerated anno) { String strat = EnumValueHandler.class.getName() + "(StoreOrdinal=" - + (anno.value() == EnumType.ORDINAL) + ")"; + + (anno.value() == EnumType.ORDINAL) + ")"; if (fm.isElementCollection()) fm.getElementMapping().getValueInfo().setStrategy(strat); else @@ -1601,7 +1617,7 @@ private void parseEnumerated(FieldMapping fm, Enumerated anno) { */ private void parseMapKeyEnumerated(FieldMapping fm, MapKeyEnumerated anno) { String strat = EnumValueHandler.class.getName() + "(StoreOrdinal=" - + (anno.value() == EnumType.ORDINAL) + ")"; + + (anno.value() == EnumType.ORDINAL) + ")"; fm.getKeyMapping().getValueInfo().setStrategy(strat); } @@ -1612,7 +1628,7 @@ private void parseTemporal(FieldMapping fm, Temporal anno) { List cols = fm.getValueInfo().getColumns(); if (!cols.isEmpty() && cols.size() != 1) throw new MetaDataException(_loc.get("num-cols-mismatch", fm, - String.valueOf(cols.size()), "1")); + String.valueOf(cols.size()), "1")); if (cols.isEmpty()) { cols = Arrays.asList(new Column[]{ new Column() }); if (fm.isElementCollection()) { @@ -1645,7 +1661,7 @@ private void parseMapKeyTemporal(FieldMapping fm, MapKeyTemporal anno) { List cols = fm.getKeyMapping().getValueInfo().getColumns(); if (!cols.isEmpty() && cols.size() != 1) throw new MetaDataException(_loc.get("num-cols-mismatch", fm, - String.valueOf(cols.size()), "1")); + String.valueOf(cols.size()), "1")); if (cols.isEmpty()) { cols = Arrays.asList(new Column[]{ new Column() }); fm.getKeyMapping().getValueInfo().setColumns(cols); @@ -1669,7 +1685,7 @@ private void parseMapKeyTemporal(FieldMapping fm, MapKeyTemporal anno) { * Parse @Column(s). */ protected void parseColumns(FieldMapping fm, - jakarta.persistence.Column... pcols) { + jakarta.persistence.Column... pcols) { if (pcols.length == 0) return; @@ -1677,7 +1693,7 @@ protected void parseColumns(FieldMapping fm, List cols = fm.getValueInfo().getColumns(); if (!cols.isEmpty() && cols.size() != pcols.length) throw new MetaDataException(_loc.get("num-cols-mismatch", fm, - String.valueOf(cols.size()), String.valueOf(pcols.length))); + String.valueOf(cols.size()), String.valueOf(pcols.length))); // cache the JAXB XmlRootElement class if it is present so we do not // have a hard-wired dependency on JAXB here @@ -1698,12 +1714,12 @@ protected void parseColumns(FieldMapping fm, cols.add(newColumn(pcols[i], delimit())); } if (xmlRootElementClass != null - && StringUtil.isEmpty(pcols[i].columnDefinition()) - && AccessController.doPrivileged(J2DoPrivHelper + && StringUtil.isEmpty(pcols[i].columnDefinition()) + && AccessController.doPrivileged(J2DoPrivHelper .isAnnotationPresentAction(fm.getDeclaredType(), (Class) xmlRootElementClass))) { DBDictionary dict = ((MappingRepository) getRepository()) - .getDBDictionary(); + .getDBDictionary(); if (dict.supportsXMLColumn) // column maps to xml type cols.get(i).setTypeIdentifier(DBIdentifier.newColumnDefinition(dict.xmlTypeName)); @@ -1711,7 +1727,7 @@ protected void parseColumns(FieldMapping fm, unique |= (pcols[i].unique()) ? TRUE : FALSE; DBIdentifier sSecTable = DBIdentifier.newTable(pcols[i].table(), delimit()); - sSecondary = trackSecondaryTable(fm, sSecondary, sSecTable, i); + sSecondary = trackSecondaryTable(fm, sSecondary, sSecTable, i); } if (fm.isElementCollection()) @@ -1726,7 +1742,7 @@ protected void parseColumns(FieldMapping fm, * Create a new schema column with information from the given annotation. */ private static Column newColumn(jakarta.persistence.Column anno, - boolean delimit) { + boolean delimit) { Column col = new Column(); setupColumn(col, anno, delimit); return col; @@ -1736,7 +1752,7 @@ private static Column newColumn(jakarta.persistence.Column anno, * Setup the given column with information from the given annotation. */ private static void setupColumn(Column col, jakarta.persistence.Column anno, - boolean delimit) { + boolean delimit) { if (!StringUtil.isEmpty(anno.name())) col.setIdentifier(DBIdentifier.newColumn(anno.name(),delimit)); if (!StringUtil.isEmpty(anno.columnDefinition())) @@ -1758,7 +1774,7 @@ else if (anno.length() != 255) * unique attribute of each column */ protected void setColumns(FieldMapping fm, MappingInfo info, - List cols, int unique) { + List cols, int unique) { info.setColumns(cols); if (unique == TRUE) info.setUnique(new org.apache.openjpa.jdbc.schema.Unique()); @@ -1777,7 +1793,7 @@ protected void setColumns(FieldMapping fm, MappingInfo info, * @return secondary table for field */ private DBIdentifier trackSecondaryTable(FieldMapping fm, DBIdentifier secondary, - DBIdentifier colSecondary, int col) { + DBIdentifier colSecondary, int col) { if (DBIdentifier.isEmpty(colSecondary)) colSecondary = DBIdentifier.NULL; if (col == 0) @@ -1791,21 +1807,21 @@ private DBIdentifier trackSecondaryTable(FieldMapping fm, DBIdentifier secondary * Parse @JoinTable. */ private void parseJoinTable(FieldMapping fm, JoinTable join) { - FieldMappingInfo info = fm.getMappingInfo(); - DBIdentifier joinTbl = toTableIdentifier(join.schema(), join.name()); + FieldMappingInfo info = fm.getMappingInfo(); + DBIdentifier joinTbl = toTableIdentifier(join.schema(), join.name()); info.setTableIdentifier(joinTbl); parseJoinColumns(fm, info, false, join.joinColumns()); parseJoinColumns(fm, fm.getElementMapping().getValueInfo(), false, - join.inverseJoinColumns()); + join.inverseJoinColumns()); addUniqueConstraints(info.getTableIdentifier().getName(), fm, info, - join.uniqueConstraints()); + join.uniqueConstraints()); } /** * Parse given @JoinColumn annotations. */ private void parseJoinColumns(FieldMapping fm, MappingInfo info, - boolean secondaryAllowed, JoinColumn... joins) { + boolean secondaryAllowed, JoinColumn... joins) { if (joins.length == 0) return; @@ -1860,7 +1876,7 @@ private Column newColumn(JoinColumn join) { col.setTypeIdentifier(DBIdentifier.newColumnDefinition(join.columnDefinition())); String refColumnName = join.referencedColumnName(); if (!StringUtil.isEmpty(refColumnName)) { - setTargetIdentifier(col, refColumnName); + setTargetIdentifier(col, refColumnName); } col.setNotNull(!join.nullable()); col.setFlag(Column.FLAG_UNINSERTABLE, !join.insertable()); @@ -1878,11 +1894,11 @@ private Column newColumn(JoinColumn join) { */ private static final char SINGLE_QUOTE = '\''; protected void setTargetIdentifier(Column col, String refColumnName) { - if (refColumnName.charAt(0) == SINGLE_QUOTE) { - col.setTargetIdentifier(DBIdentifier.newConstant(refColumnName)); - } else { - col.setTargetIdentifier(DBIdentifier.newColumn(refColumnName, delimit())); - } + if (refColumnName.charAt(0) == SINGLE_QUOTE) { + col.setTargetIdentifier(DBIdentifier.newConstant(refColumnName)); + } else { + col.setTargetIdentifier(DBIdentifier.newColumn(refColumnName, delimit())); + } } /** @@ -1925,7 +1941,7 @@ else if (anno.length() != 255) * Parse given @PrimaryKeyJoinColumn annotations. */ private void parsePrimaryKeyJoinColumns(FieldMapping fm, - PrimaryKeyJoinColumn... joins) { + PrimaryKeyJoinColumn... joins) { List cols = new ArrayList<>(joins.length); for (PrimaryKeyJoinColumn join : joins) cols.add(newColumn(join)); @@ -1936,7 +1952,7 @@ private void parsePrimaryKeyJoinColumns(FieldMapping fm, * Parse given @XJoinColumn annotations. */ protected void parseXJoinColumns(FieldMapping fm, MappingInfo info, - boolean secondaryAllowed, XJoinColumn... joins) { + boolean secondaryAllowed, XJoinColumn... joins) { if (joins.length == 0) return; @@ -1947,7 +1963,7 @@ protected void parseXJoinColumns(FieldMapping fm, MappingInfo info, cols.add(newColumn(joins[i], delimit())); unique |= (joins[i].unique()) ? TRUE : FALSE; sSecondary = trackSecondaryTable(fm, sSecondary, - DBIdentifier.newTable(joins[i].table(), delimit()), i); + DBIdentifier.newTable(joins[i].table(), delimit()), i); if (!secondaryAllowed && !DBIdentifier.isNull(sSecondary)) throw new MetaDataException(_loc.get("bad-second", fm)); } @@ -1989,7 +2005,7 @@ private void parseEmbeddedMapping(FieldMapping fm, EmbeddedMapping anno) { efm = embed.getFieldMapping(over.name()); if (efm == null) throw new MetaDataException(_loc.get("embed-override-name", - fm, over.name())); + fm, over.name())); populate(efm, over); } @@ -2009,8 +2025,8 @@ else if (!StringUtil.isEmpty(anno.nullIndicatorColumnName())) * Parse embedded info for the given mapping. */ private void parseEmbeddedMapping(ValueMapping vm, - DBIdentifier nullIndicatorAttribute, DBIdentifier nullIndicatorColumn, - XMappingOverride[] overrides) { + DBIdentifier nullIndicatorAttribute, DBIdentifier nullIndicatorColumn, + XMappingOverride[] overrides) { ClassMapping embed = vm.getEmbeddedMapping(); if (embed == null) throw new MetaDataException(_loc.get("not-embedded", vm)); @@ -2020,7 +2036,7 @@ private void parseEmbeddedMapping(ValueMapping vm, efm = embed.getFieldMapping(over.name()); if (efm == null) throw new MetaDataException(_loc.get("embed-override-name", - vm, over.name())); + vm, over.name())); populate(efm, over); } @@ -2070,7 +2086,7 @@ protected void parseCollectionTable(FieldMapping fm, CollectionTable ctbl) { //ctbl.catalog() parseJoinColumns(fm, fm.getMappingInfo(), false, ctbl.joinColumns()); addUniqueConstraints(info.getTableIdentifier().getName(), fm.getDefiningMetaData(), - info, ctbl.uniqueConstraints()); + info, ctbl.uniqueConstraints()); } /** @@ -2098,7 +2114,7 @@ private void parseOrderColumn(FieldMapping fm, OrderColumn order) { * Parse @jakarta.persistence.OrderColumn */ private void parseJavaxOrderColumn(FieldMapping fm, - jakarta.persistence.OrderColumn order) { + jakarta.persistence.OrderColumn order) { Column col = new Column(); if (!StringUtil.isEmpty(order.name())) @@ -2116,7 +2132,7 @@ private void parseJavaxOrderColumn(FieldMapping fm, * Parse @ElementJoinColumn(s). */ protected void parseElementJoinColumns(FieldMapping fm, - ElementJoinColumn... joins) { + ElementJoinColumn... joins) { if (joins.length == 0) return; @@ -2144,9 +2160,9 @@ private Column newColumn(ElementJoinColumn join, boolean delimit) { col.setTargetField(join.referencedAttributeName()); col.setNotNull(!join.nullable()); col.setFlag (Column.FLAG_UNINSERTABLE, !join.insertable ()); - col.setFlag (Column.FLAG_UNUPDATABLE, !join.updatable ()); - return col; - } + col.setFlag (Column.FLAG_UNUPDATABLE, !join.updatable ()); + return col; + } /** * Parse @MapKeyColumn. @@ -2167,7 +2183,7 @@ protected void parseMapKeyColumn(FieldMapping fm, MapKeyColumn anno) { * Setup the given column with information from the given annotation. */ private void setupMapKeyColumn(FieldMapping fm, Column col, - MapKeyColumn anno) { + MapKeyColumn anno) { if (!StringUtil.isEmpty(anno.name())) { col.setIdentifier(DBIdentifier.newColumn(anno.name(), delimit())); } @@ -2192,7 +2208,7 @@ else if (anno.length() != 255) * unique attribute of the column */ protected void setMapKeyColumn(FieldMapping fm, MappingInfo info, - Column col, int unique) { + Column col, int unique) { List cols = new ArrayList<>(); cols.add(col); info.setColumns(cols); diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/EntityWithIndexColumnNames.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/EntityWithIndexColumnNames.java new file mode 100644 index 0000000000..cd9b1f4ff0 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/EntityWithIndexColumnNames.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.jdbc.annotations; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import org.apache.openjpa.persistence.jdbc.Index; + +/** + * Test entity for verifying that the {@code columnNames} attribute of the + * OpenJPA-specific {@link Index} annotation is correctly applied when placed + * at the field level. + */ +@Entity +@Table(name = "IDX_COL_NAMES_ENTITY") +public class EntityWithIndexColumnNames { + + @Id + @Column(name = "PK") + private Long pk; + + @Column(name = "COL_A") + @Index(name = "idx_col_a_b", columnNames = {"COL_A", "COL_B"}) + private String colA; + + @Column(name = "COL_B") + private String colB; + + public Long getPk() { + return pk; + } + + public void setPk(Long pk) { + this.pk = pk; + } + + public String getColA() { + return colA; + } + + public void setColA(String colA) { + this.colA = colA; + } + + public String getColB() { + return colB; + } + + public void setColB(String colB) { + this.colB = colB; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestIndexColumnNames.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestIndexColumnNames.java new file mode 100644 index 0000000000..ad8b3c8226 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestIndexColumnNames.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.jdbc.annotations; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.openjpa.jdbc.meta.ClassMapping; +import org.apache.openjpa.jdbc.meta.FieldMapping; +import org.apache.openjpa.jdbc.schema.Column; +import org.apache.openjpa.jdbc.schema.Index; +import org.apache.openjpa.persistence.JPAFacadeHelper; +import org.apache.openjpa.persistence.test.SingleEMFTestCase; +import org.junit.Test; + +/** + * Regression test for the bug where the {@code columnNames} attribute of the + * OpenJPA-specific field-level {@link org.apache.openjpa.persistence.jdbc.Index} + * annotation was silently ignored during annotation parsing. + * + *

Root cause: {@code AnnotationPersistenceMappingParser.parseIndex(MappingInfo, Index)} + * called the internal overload without passing {@code idx.columnNames()}, so the + * specified column names were never added to the schema {@code Index} object.

+ */ +public class TestIndexColumnNames extends SingleEMFTestCase { + + private ClassMapping _mapping; + + @Override + public void setUp() { + setUp(EntityWithIndexColumnNames.class, CLEAR_TABLES); + emf.createEntityManager().close(); + _mapping = (ClassMapping) JPAFacadeHelper.getMetaData(emf, EntityWithIndexColumnNames.class); + } + + @Test + public void testFieldIndexColumnNamesAreApplied() { + FieldMapping fm = _mapping.getFieldMapping("colA"); + assertNotNull("Field mapping for 'colA' must exist", fm); + + Index idx = fm.getValueIndex(); + assertNotNull("@Index on field 'colA' must create a schema index", idx); + + Column[] columns = idx.getColumns(); + assertTrue( + "Index defined with columnNames must contain at least one explicit column; " + + "before the fix, columnNames was ignored and the column list was empty", + columns.length > 0); + + Set colNames = Arrays.stream(columns) + .map(c -> c.getIdentifier().getName()) + .collect(Collectors.toSet()); + assertTrue("Index must contain COL_A (listed in columnNames)", colNames.contains("COL_A")); + assertTrue("Index must contain COL_B (listed in columnNames)", colNames.contains("COL_B")); + } +}