This is an automated email from the ASF dual-hosted git repository.
solomax pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openjpa.git
The following commit(s) were added to refs/heads/master by this push:
new cb20dd6 [OPENJPA-2777] Javax index (#39)
cb20dd6 is described below
commit cb20dd6b95a07fe87bf46a2c33580322d0b11cd0
Author: Maxim Solodovnik <[email protected]>
AuthorDate: Tue Mar 5 20:44:49 2019 +0700
[OPENJPA-2777] Javax index (#39)
[OPENJPA-2777] javax.persistense.Index can be used on Table annotation
---
.../org/apache/openjpa/jdbc/meta/ClassMapping.java | 1 +
.../apache/openjpa/jdbc/meta/ClassMappingInfo.java | 126 ++++++++++++++++-----
.../apache/openjpa/jdbc/meta/localizer.properties | 5 +
.../jdbc/AnnotationPersistenceMappingParser.java | 41 ++++++-
.../openjpa/persistence/jdbc/localizer.properties | 4 +
.../jdbc/annotations/EntityWithIndices.java | 76 +++++++++++++
.../persistence/jdbc/annotations/TestIndices.java | 64 +++++++++++
7 files changed, 286 insertions(+), 31 deletions(-)
diff --git
a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java
index a1a387f..1e35054 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java
@@ -903,6 +903,7 @@ public class ClassMapping
// once columns are resolved, resolve unique constraints as they need
// the columns be resolved
_info.getUniques(this, true);
+ _info.getIndices(this, true);
}
/**
diff --git
a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMappingInfo.java
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMappingInfo.java
index 0cad85d..60cc2a0 100644
---
a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMappingInfo.java
+++
b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMappingInfo.java
@@ -34,6 +34,7 @@ import
org.apache.openjpa.jdbc.identifier.QualifiedDBIdentifier;
import org.apache.openjpa.jdbc.meta.strats.FullClassStrategy;
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.schema.ForeignKey;
+import org.apache.openjpa.jdbc.schema.Index;
import org.apache.openjpa.jdbc.schema.Schema;
import org.apache.openjpa.jdbc.schema.SchemaGroup;
import org.apache.openjpa.jdbc.schema.Table;
@@ -77,6 +78,7 @@ public class ClassMappingInfo
// Unique constraints indexed by primary or secondary table name
private Map<DBIdentifier,List<Unique>> _uniques;
+ private Map<DBIdentifier,List<Index>> _indices = new HashMap<>();
/**
* The described class name.
*/
@@ -452,13 +454,21 @@ public class ClassMappingInfo
}
}
if (cinfo._uniques != null) {
- if (_uniques == null)
- _uniques = new HashMap<>();
- for (Entry<DBIdentifier, List<Unique>> entry :
cinfo._uniques.entrySet())
- if (!_uniques.containsKey(entry.getKey()))
- _uniques.put(entry.getKey(), entry.getValue());
+ if (_uniques == null) {
+ _uniques = new HashMap<>();
+ }
+ for (Entry<DBIdentifier, List<Unique>> entry :
cinfo._uniques.entrySet()) {
+ if (!_uniques.containsKey(entry.getKey())) {
+ _uniques.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+ _indices.clear();
+ for (Entry<DBIdentifier, List<Index>> entry :
cinfo._indices.entrySet()) {
+ if (!_indices.containsKey(entry.getKey())) {
+ _indices.put(entry.getKey(), entry.getValue());
+ }
}
-
}
/**
@@ -480,24 +490,50 @@ public class ClassMappingInfo
* @param unique the unique constraint. null means no-op.
*/
public void addUnique(DBIdentifier table, Unique unique) {
- if (!DBIdentifier.equal(_tableName, table) &&
- (_seconds == null || !_seconds.containsKey(table))) {
+ if (!DBIdentifier.equal(_tableName, table) &&
+ (_seconds == null || !_seconds.containsKey(table))) {
throw new UserException(_loc.get("unique-no-table",
new Object[]{table, _className, _tableName,
((_seconds == null) ? "" : _seconds.keySet())}));
- }
- if (unique == null)
- return;
+ }
+ if (unique == null)
+ return;
if (_uniques == null)
_uniques = new HashMap<>();
unique.setTableIdentifier(table);
List<Unique> uniques = _uniques.get(table);
if (uniques == null) {
- uniques = new ArrayList<>();
- uniques.add(unique);
- _uniques.put(table, uniques);
+ uniques = new ArrayList<>();
+ uniques.add(unique);
+ _uniques.put(table, uniques);
} else {
- uniques.add(unique);
+ uniques.add(unique);
+ }
+ }
+
+ /**
+ * Add index for the given table.
+ * @param table must be primary table or secondary table name added a
+ * priori to this receiver.
+ * @param idx the index. null means no-op.
+ */
+ public void addIndex(DBIdentifier table, Index idx) {
+ if (!DBIdentifier.equal(_tableName, table) &&
+ (_seconds == null || !_seconds.containsKey(table))) {
+ throw new UserException(_loc.get("index-no-table",
+ new Object[]{table, _className, _tableName,
+ ((_seconds == null) ? "" : _seconds.keySet())}));
+ }
+ if (idx == null)
+ return;
+ idx.setTableIdentifier(table);
+ List<Index> indices = _indices.get(table);
+ if (indices == null) {
+ indices = new ArrayList<>();
+ indices.add(idx);
+ _indices.put(table, indices);
+ } else {
+ indices.add(idx);
}
}
@@ -531,31 +567,65 @@ public class ClassMappingInfo
return new Unique[0];
List<Unique> result = new ArrayList<>();
for (DBIdentifier tableName : _uniques.keySet()) {
- List<Unique> uniqueConstraints = _uniques.get(tableName);
- for (Unique template : uniqueConstraints) {
- Column[] templateColumns = template.getColumns();
+ List<Unique> uniqueConstraints = _uniques.get(tableName);
+ for (Unique template : uniqueConstraints) {
+ Column[] templateColumns = template.getColumns();
Column[] uniqueColumns = new Column[templateColumns.length];
Table table = getTable((ClassMapping)cm, tableName, adapt);
- for (int i=0; i<uniqueColumns.length; i++) {
+ for (int i=0; i<uniqueColumns.length; i++) {
DBIdentifier columnName =
templateColumns[i].getIdentifier();
- if (!table.containsColumn(columnName)) {
+ if (!table.containsColumn(columnName)) {
throw new UserException(_loc.get(
"unique-missing-column",
new Object[]{cm, columnName, tableName,
Arrays.toString(table.getColumnNames())}));
- }
+ }
Column uniqueColumn = table.getColumn(columnName);
- uniqueColumns[i] = uniqueColumn;
- }
- Unique unique = createUnique(cm, "unique", template,
- uniqueColumns, adapt);
- if (unique != null)
- result.add(unique);
- }
+ uniqueColumns[i] = uniqueColumn;
+ }
+ Unique unique = createUnique(cm, "unique", template,
+ uniqueColumns, adapt);
+ if (unique != null)
+ result.add(unique);
+ }
}
return result.toArray(new Unique[result.size()]);
}
+ /**
+ * Get all indices associated with both the primary and/or
+ * secondary tables.
+ *
+ */
+ public Index[] getIndices(MetaDataContext cm, boolean adapt) {
+ if (_indices.isEmpty())
+ return new Index[0];
+ List<Index> result = new ArrayList<>();
+ for (DBIdentifier tableName : _indices.keySet()) {
+ List<Index> indices = _indices.get(tableName);
+ for (Index template : indices) {
+ Column[] templateColumns = template.getColumns();
+ Column[] columns = new Column[templateColumns.length];
+ Table table = getTable((ClassMapping)cm, tableName, adapt);
+ for (int i = 0; i < columns.length; i++) {
+ DBIdentifier columnName =
templateColumns[i].getIdentifier();
+ if (!table.containsColumn(columnName)) {
+ throw new UserException(_loc.get(
+ "index-missing-column",
+ new Object[]{cm, columnName, tableName,
+ Arrays.toString(table.getColumnNames())}));
+ }
+ Column column = table.getColumn(columnName);
+ columns[i] = column;
+ }
+ Index idx = createIndex(cm, "index", template, columns, adapt);
+ if (idx != null)
+ result.add(idx);
+ }
+ }
+ return result.toArray(new Index[result.size()]);
+ }
+
@Override
public File getSourceFile() {
return _file;
diff --git
a/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties
b/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties
index 36079b2..f267615 100644
---
a/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties
+++
b/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties
@@ -416,6 +416,11 @@ unique-missing-column: The column "{1}" in a unique
constraint in "{0}" on \
unique-no-table: A unique constraint on table "{0}" can not be added to \
mapping of class "{1}" because the table does neither match its primary
\
table "{2}" nor any of its secondary table(s) "{3}".
+index-no-table: Index on table "{0}" can not be added to \
+ mapping of class "{1}" because the table does neither match its primary
\
+ table "{2}" nor any of its secondary table(s) "{3}".
+index-missing-column: The column "{1}" in a index in "{0}" on \
+ table "{2}" can not be found in the list of available columns "{3}".
bad-version-column-table: One of the version column "{0}" has been associated \
with table "{1}", but no primary or secondary table of such name exists.
version-type-unsupported: Version field "{0}" of {1} is not supported.
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 592328a..d22431b 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
@@ -615,6 +615,7 @@ public class AnnotationPersistenceMappingParser
}
addUniqueConstraints(tName.getName(), cm, cm.getMappingInfo(),
table.uniqueConstraints());
+ addIndices(tName.getName(), cm, cm.getMappingInfo(), table.indexes());
}
Unique createUniqueConstraint(MetaDataContext ctx, UniqueConstraint anno) {
@@ -643,7 +644,7 @@ public class AnnotationPersistenceMappingParser
Unique unique = createUniqueConstraint(ctx, anno);
unique.setTableIdentifier(DBIdentifier.newTable(table, delimit()));
if (info instanceof ClassMappingInfo)
- ((ClassMappingInfo) info).addUnique(table, unique);
+ ((ClassMappingInfo)
info).addUnique(DBIdentifier.newTable(table), unique);
else if (info instanceof FieldMappingInfo)
((FieldMappingInfo) info).addJoinTableUnique(unique);
else
@@ -651,6 +652,40 @@ public class AnnotationPersistenceMappingParser
}
}
+
+ org.apache.openjpa.jdbc.schema.Index createIndex(MetaDataContext ctx,
javax.persistence.Index anno) {
+ String columnNames = anno.columnList();
+ if (StringUtil.isEmpty(columnNames))
+ throw new UserException(_loc.get("index-no-column", ctx));
+ DBIdentifier[] sColNames =
DBIdentifier.toArray(columnNames.split(","), DBIdentifierType.COLUMN,
delimit());
+ org.apache.openjpa.jdbc.schema.Index indx = new
org.apache.openjpa.jdbc.schema.Index();
+ for (int i = 0; i < sColNames.length; i++) {
+ if (DBIdentifier.isEmpty(sColNames[i]))
+ throw new UserException(_loc.get("index-empty-column",
+ Arrays.toString(sColNames), ctx));
+ Column column = new Column();
+ column.setIdentifier(sColNames[i]);
+ indx.addColumn(column);
+ }
+ indx.setUnique(anno.unique());
+ if (!StringUtil.isEmpty(anno.name())) {
+ indx.setIdentifier(DBIdentifier.newConstraint(anno.name(),
delimit()));
+ }
+ return indx;
+ }
+
+ void addIndices(String table, MetaDataContext ctx,
+ MappingInfo info, javax.persistence.Index... indices) {
+ for (javax.persistence.Index anno : indices) {
+ org.apache.openjpa.jdbc.schema.Index idx = createIndex(ctx, anno);
+ idx.setTableIdentifier(DBIdentifier.newTable(table, delimit()));
+ if (info instanceof ClassMappingInfo)
+ ((ClassMappingInfo)
info).addIndex(DBIdentifier.newTable(table), idx);
+ else
+ throw new InternalException();
+ }
+ }
+
/**
* Form a qualified table name from a schema and table name.
*/
@@ -1644,7 +1679,7 @@ public class AnnotationPersistenceMappingParser
// cache the JAXB XmlRootElement class if it is present so we do not
// have a hard-wired dependency on JAXB here
- Class xmlRootElementClass = null;
+ Class<?> xmlRootElementClass = null;
try {
xmlRootElementClass =
Class.forName("javax.xml.bind.annotation.XmlRootElement");
} catch (Exception e) {
@@ -1669,7 +1704,7 @@ public class AnnotationPersistenceMappingParser
.getDBDictionary();
if (dict.supportsXMLColumn)
// column maps to xml type
- ((Column)
cols.get(i)).setTypeIdentifier(DBIdentifier.newColumnDefinition(dict.xmlTypeName));
+
cols.get(i).setTypeIdentifier(DBIdentifier.newColumnDefinition(dict.xmlTypeName));
}
unique |= (pcols[i].unique()) ? TRUE : FALSE;
diff --git
a/openjpa-persistence-jdbc/src/main/resources/org/apache/openjpa/persistence/jdbc/localizer.properties
b/openjpa-persistence-jdbc/src/main/resources/org/apache/openjpa/persistence/jdbc/localizer.properties
index f31c6de..b4ab97c 100644
---
a/openjpa-persistence-jdbc/src/main/resources/org/apache/openjpa/persistence/jdbc/localizer.properties
+++
b/openjpa-persistence-jdbc/src/main/resources/org/apache/openjpa/persistence/jdbc/localizer.properties
@@ -53,6 +53,10 @@ unique-empty-column: A unique constraint "{0}" specified in
mapping of class \
unique-many-on-seq-unsupported: More than one unique constraints is specified \
on sequence generator "{1}" in "{0}". But multiple unique constraint on
\
sequence generator is currently not supported.
+index-no-column: An index specified in mapping of "{0}" specified \
+ no column.
+index-empty-column: An index "{0}" specified in mapping of class \
+ "{1}" includes an empty column.
discriminator-on-abstract-class: A discriminator value has been specified for \
the abstract class "{0}". The discriminator will never be used and may
be \
safely removed.
diff --git
a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/EntityWithIndices.java
b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/EntityWithIndices.java
new file mode 100644
index 0000000..cc073d1
--- /dev/null
+++
b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/EntityWithIndices.java
@@ -0,0 +1,76 @@
+/*
+ * 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 javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Index;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "INDICES1"
+ , indexes = {@Index(name = "idx_index1", columnList = "index1")
+ , @Index(name = "idx_long", columnList = "LONG_NAME", unique =
true)})
+public class EntityWithIndices {
+ @Id
+ @Column(name = "PK")
+ private Long pk;
+
+ @Column(name = "INDEX1")
+ private String index1;
+
+ @Column(name = "LONG_NAME")
+ private String longName;
+
+ @Column(name = "NAME")
+ private String name;
+
+ public Long getPk() {
+ return pk;
+ }
+
+ public void setPk(Long pk) {
+ this.pk = pk;
+ }
+
+ public String getIndex1() {
+ return index1;
+ }
+
+ public void setIndex1(String index1) {
+ this.index1 = index1;
+ }
+
+ public String getLongName() {
+ return longName;
+ }
+
+ public void setLongName(String longName) {
+ this.longName = longName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git
a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestIndices.java
b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestIndices.java
new file mode 100644
index 0000000..f105d64
--- /dev/null
+++
b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestIndices.java
@@ -0,0 +1,64 @@
+/*
+ * 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.HashSet;
+import java.util.Set;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.identifier.DBIdentifier;
+import org.apache.openjpa.jdbc.meta.ClassMapping;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.Index;
+import org.apache.openjpa.jdbc.schema.Table;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+import org.junit.Test;
+
+public class TestIndices extends SingleEMFTestCase {
+ @Override
+ public void setUp() {
+ setUp(EntityWithIndices.class, CLEAR_TABLES
+// ,"openjpa.Log","SQL=trace"
+ );
+ }
+
+ @Test
+ public void testIndicesCreated() {
+ JDBCConfiguration conf = (JDBCConfiguration)
emf.getConfiguration();
+ ClassMapping cls =
conf.getMappingRepositoryInstance().getMapping(EntityWithIndices.class, null,
true);
+ Table table = cls.getTable();
+ Index idx1 =
table.getIndex(DBIdentifier.newIndex("idx_index1"));
+ assertNotNull("Defined index should exist", idx1);
+ assertFalse(idx1.isUnique());
+
+ Index idx2 = table.getIndex(DBIdentifier.newIndex("idx_long"));
+ assertNotNull("Defined index should exist", idx2);
+ assertTrue(idx2.isUnique());
+
+ Set<String> indexedCols = new HashSet<>();
+ for (Index idx : table.getIndexes()) {
+ for (Column col : idx.getColumns()) {
+ indexedCols.add(col.getIdentifier().getName());
+ }
+ }
+ assertTrue(indexedCols.contains("INDEX1"));
+ assertTrue(indexedCols.contains("LONG_NAME"));
+ assertFalse(indexedCols.contains("NAME"));
+ }
+}