JPA-43 Impl Index and ForeignKey for JPA 2.1

This commit is contained in:
Strong Liu 2013-03-22 16:06:21 +08:00
parent eeca84460e
commit 4b698302a5
10 changed files with 445 additions and 118 deletions

View File

@ -65,10 +65,12 @@ import javax.persistence.ExcludeDefaultListeners;
import javax.persistence.ExcludeSuperclassListeners;
import javax.persistence.FetchType;
import javax.persistence.FieldResult;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Index;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
@ -227,6 +229,8 @@ public class JPAOverriddenAnnotationReader implements AnnotationReader {
annotationToXml.put( MapKeyJoinColumns.class, "map-key-join-column" );
annotationToXml.put( OrderColumn.class, "order-column" );
annotationToXml.put( Cacheable.class, "cacheable" );
annotationToXml.put( Index.class, "index" );
annotationToXml.put( ForeignKey.class, "foreign-key" );
}
private XMLContext xmlContext;
@ -659,6 +663,7 @@ public class JPAOverriddenAnnotationReader implements AnnotationReader {
annotation.setValue( "schema", defaults.getSchema() );
}
buildUniqueConstraints( annotation, subelement );
buildIndex( annotation, subelement );
annotation.setValue( "joinColumns", getJoinColumns( subelement, false ) );
annotation.setValue( "inverseJoinColumns", getJoinColumns( subelement, true ) );
return AnnotationFactory.create( annotation );
@ -1069,6 +1074,7 @@ public class JPAOverriddenAnnotationReader implements AnnotationReader {
annotation.setValue( "joinColumns", joinColumns );
}
buildUniqueConstraints( annotation, subelement );
buildIndex( annotation, subelement );
annotationList.add( AnnotationFactory.create( annotation ) );
}
}
@ -2298,6 +2304,7 @@ public class JPAOverriddenAnnotationReader implements AnnotationReader {
annotation.setValue( "schema", defaults.getSchema() );
}
buildUniqueConstraints( annotation, subelement );
buildIndex( annotation, subelement );
return AnnotationFactory.create( annotation );
}
}
@ -2321,6 +2328,7 @@ public class JPAOverriddenAnnotationReader implements AnnotationReader {
annotation.setValue( "schema", defaults.getSchema() );
}
buildUniqueConstraints( annotation, element );
buildIndex( annotation, element );
annotation.setValue( "pkJoinColumns", buildPrimaryKeyJoinColumns( element ) );
secondaryTables.add( (SecondaryTable) AnnotationFactory.create( annotation ) );
}
@ -2376,7 +2384,19 @@ public class JPAOverriddenAnnotationReader implements AnnotationReader {
}
}
}
private static void buildIndex(AnnotationDescriptor annotation, Element element){
List indexElementList = element.elements( "index" );
Index[] indexes = new Index[indexElementList.size()];
for(int i=0;i<indexElementList.size();i++){
Element subelement = (Element)indexElementList.get( i );
AnnotationDescriptor indexAnn = new AnnotationDescriptor( Index.class );
copyStringAttribute( indexAnn, subelement, "name", false );
copyStringAttribute( indexAnn, subelement, "column-list", true );
copyBooleanAttribute( indexAnn, subelement, "unique" );
indexes[i] = AnnotationFactory.create( indexAnn );
}
annotation.setValue( "indexes", indexes );
}
private static void buildUniqueConstraints(AnnotationDescriptor annotation, Element element) {
List uniqueConstraintElementList = element.elements( "unique-constraint" );
UniqueConstraint[] uniqueConstraints = new UniqueConstraint[uniqueConstraintElementList.size()];

View File

@ -133,10 +133,18 @@ public class MappingReader {
try {
saxReader.setFeature( "http://apache.org/xml/features/validation/schema", true );
// saxReader.setFeature( "http://apache.org/xml/features/validation/dynamic", true );
saxReader.setProperty(
"http://apache.org/xml/properties/schema/external-schemaLocation",
"http://java.sun.com/xml/ns/persistence/orm " + xsd
);
if ( "orm_2_1.xsd".equals( xsd ) ) {
saxReader.setProperty(
"http://apache.org/xml/properties/schema/external-schemaLocation",
"http://xmlns.jcp.org/xml/ns/persistence/orm " + xsd
);
}
else {
saxReader.setProperty(
"http://apache.org/xml/properties/schema/external-schemaLocation",
"http://java.sun.com/xml/ns/persistence/orm " + xsd
);
}
}
catch ( SAXException e ) {
saxReader.setValidation( false );

View File

@ -212,7 +212,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
}
public void setRole(String role) {
this.role = role==null ? null : role.intern();
this.role = role;
}
public void setSorted(boolean sorted) {
@ -549,7 +549,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
}
public void setLoaderName(String name) {
this.loaderName = name==null ? null : name.intern();
this.loaderName = name;
}
public String getReferencedPropertyName() {
@ -557,7 +557,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
}
public void setReferencedPropertyName(String propertyRef) {
this.referencedPropertyName = propertyRef==null ? null : propertyRef.intern();
this.referencedPropertyName = propertyRef;
}
public boolean isOptimisticLocked() {

View File

@ -0,0 +1,144 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013 by Red Hat Inc and/or its affiliates or by
* third-party contributors as indicated by either @author tags or express
* copyright attribution statements applied by the authors. All
* third-party contributions are distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.annotations.index.jpa;
import java.util.Iterator;
import org.junit.Test;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.Bag;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Index;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Set;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UniqueKey;
import org.hibernate.test.annotations.embedded.Book;
import org.hibernate.test.annotations.embedded.WealthyPerson;
import org.hibernate.test.event.collection.detached.Alias;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* @author Strong Liu <stliu@hibernate.org>
*/
public class AbstractJPAIndexTest extends BaseCoreFunctionalTestCase {
@Test
public void testTableIndex() {
PersistentClass entity = configuration().getClassMapping( Car.class.getName() );
Iterator itr = entity.getTable().getUniqueKeyIterator();
assertTrue( itr.hasNext() );
UniqueKey uk = (UniqueKey) itr.next();
assertFalse( itr.hasNext() );
assertTrue( StringHelper.isNotEmpty( uk.getName() ) );
assertEquals( 2, uk.getColumnSpan() );
Column column = (Column) uk.getColumns().get( 0 );
assertEquals( "brand", column.getName() );
column = (Column) uk.getColumns().get( 1 );
assertEquals( "producer", column.getName() );
assertSame( entity.getTable(), uk.getTable() );
itr = entity.getTable().getIndexIterator();
assertTrue( itr.hasNext() );
Index index = (Index)itr.next();
assertFalse( itr.hasNext() );
assertEquals( "Car_idx", index.getName() );
assertEquals( 1, index.getColumnSpan() );
column = index.getColumnIterator().next();
assertEquals( "since", column.getName() );
assertSame( entity.getTable(), index.getTable() );
}
@Test
public void testSecondaryTableIndex(){
PersistentClass entity = configuration().getClassMapping( Car.class.getName() );
Join join = (Join)entity.getJoinIterator().next();
Iterator<Index> itr = join.getTable().getIndexIterator();
assertTrue( itr.hasNext() );
Index index = itr.next();
assertFalse( itr.hasNext() );
assertTrue( "index name is not generated", StringHelper.isNotEmpty( index.getName() ) );
assertEquals( 2, index.getColumnSpan() );
Iterator<Column> columnIterator = index.getColumnIterator();
Column column = columnIterator.next();
assertEquals( "dealer_name", column.getName() );
column = columnIterator.next();
assertEquals( "rate", column.getName() );
assertSame( join.getTable(), index.getTable() );
}
@Test
public void testCollectionTableIndex(){
PersistentClass entity = configuration().getClassMapping( Car.class.getName() );
Property property = entity.getProperty( "otherDealers" );
Set set = (Set)property.getValue();
Table collectionTable = set.getCollectionTable();
Iterator<Index> itr = collectionTable.getIndexIterator();
assertTrue( itr.hasNext() );
Index index = itr.next();
assertFalse( itr.hasNext() );
assertTrue( "index name is not generated", StringHelper.isNotEmpty( index.getName() ) );
assertEquals( 1, index.getColumnSpan() );
Iterator<Column> columnIterator = index.getColumnIterator();
Column column = columnIterator.next();
assertEquals( "name", column.getName() );
assertSame( collectionTable, index.getTable() );
}
@Test
public void testJoinTableIndex(){
PersistentClass entity = configuration().getClassMapping( Importer.class.getName() );
Property property = entity.getProperty( "cars" );
Bag set = (Bag)property.getValue();
Table collectionTable = set.getCollectionTable();
Iterator<Index> itr = collectionTable.getIndexIterator();
assertTrue( itr.hasNext() );
Index index = itr.next();
assertFalse( itr.hasNext() );
assertTrue( "index name is not generated", StringHelper.isNotEmpty( index.getName() ) );
assertEquals( 1, index.getColumnSpan() );
Iterator<Column> columnIterator = index.getColumnIterator();
Column column = columnIterator.next();
assertEquals( "importers_id", column.getName() );
assertSame( collectionTable, index.getTable() );
}
@Test
public void testTableGeneratorIndex(){
//todo
}
}

View File

@ -23,9 +23,20 @@
*/
package org.hibernate.test.annotations.index.jpa;
import java.util.List;
import java.util.Set;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.ManyToMany;
import javax.persistence.SecondaryTable;
import javax.persistence.Table;
@ -33,13 +44,85 @@ import javax.persistence.Table;
* @author Strong Liu <stliu@hibernate.org>
*/
@Entity
@Table( indexes = {@Index( unique = true, columnList = "brand, producer")
, @Index( name = "Car_idx", columnList = "since DESC")})
@Table(indexes = {
@Index(unique = true, columnList = "brand, producer")
, @Index(name = "Car_idx", columnList = "since DESC")
})
@SecondaryTable(name = "T_DEALER", indexes = @Index(columnList = "dealer_name ASC, rate DESC"))
public class Car {
@Id
long id;
String brand;
String producer;
long since;
private long id;
private String brand;
private String producer;
private long since;
@AttributeOverrides({
@AttributeOverride(name = "name", column = @Column(name = "dealer_name", table = "T_DEALER")),
@AttributeOverride(name = "rate", column = @Column(table = "T_DEALER"))
})
@Embedded
private Dealer dealer;
@ElementCollection
@CollectionTable(name = "CAR_DEALTERS", indexes = @Index(columnList = "name"))
private Set<Dealer> otherDealers;
@ManyToMany(cascade = CascadeType.ALL, mappedBy = "cars")
private List<Importer> importers;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Dealer getDealer() {
return dealer;
}
public void setDealer(Dealer dealer) {
this.dealer = dealer;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public List<Importer> getImporters() {
return importers;
}
public void setImporters(List<Importer> importers) {
this.importers = importers;
}
public Set<Dealer> getOtherDealers() {
return otherDealers;
}
public void setOtherDealers(Set<Dealer> otherDealers) {
this.otherDealers = otherDealers;
}
public String getProducer() {
return producer;
}
public void setProducer(String producer) {
this.producer = producer;
}
public long getSince() {
return since;
}
public void setSince(long since) {
this.since = since;
}
}

View File

@ -23,11 +23,30 @@
*/
package org.hibernate.test.annotations.index.jpa;
import javax.persistence.Entity;
import java.io.Serializable;
import javax.persistence.Embeddable;
/**
* @author Strong Liu <stliu@hibernate.org>
*/
@Entity
public class Dealer {
@Embeddable
public class Dealer implements Serializable {
private String name;
private long rate;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getRate() {
return rate;
}
public void setRate(long rate) {
this.rate = rate;
}
}

View File

@ -0,0 +1,70 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013 by Red Hat Inc and/or its affiliates or by
* third-party contributors as indicated by either @author tags or express
* copyright attribution statements applied by the authors. All
* third-party contributions are distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.annotations.index.jpa;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
/**
* @author Strong Liu <stliu@hibernate.org>
*/
@Entity
public class Importer {
@Id
private long id;
private String name;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable( name = "CAR_IMPORTER",indexes = @Index(columnList = "importers_id"))
private List<Car> cars;
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -53,111 +53,15 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
/**
* @author Strong Liu <stliu@hibernate.org>
*/
public class IndexTest extends BaseCoreFunctionalTestCase {
public class IndexTest extends AbstractJPAIndexTest {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { Car.class,
Book.class,
Summary.class,
WealthyPerson.class,
Person.class,
AddressType.class,
Address.class,
Alias.class,
org.hibernate.test.event.collection.detached.Character.class
return new Class[] {
Car.class,
Dealer.class,
Importer.class
};
}
@Test
public void testTableIndex() {
PersistentClass entity = configuration().getClassMapping( Car.class.getName() );
Iterator itr = entity.getTable().getUniqueKeyIterator();
assertTrue( itr.hasNext() );
UniqueKey uk = (UniqueKey) itr.next();
assertFalse( itr.hasNext() );
assertTrue( StringHelper.isNotEmpty( uk.getName() ) );
assertEquals( 2, uk.getColumnSpan() );
Column column = (Column) uk.getColumns().get( 0 );
assertEquals( "brand", column.getName() );
column = (Column) uk.getColumns().get( 1 );
assertEquals( "producer", column.getName() );
assertSame( entity.getTable(), uk.getTable() );
itr = entity.getTable().getIndexIterator();
assertTrue( itr.hasNext() );
Index index = (Index)itr.next();
assertFalse( itr.hasNext() );
assertEquals( "Car_idx", index.getName() );
assertEquals( 1, index.getColumnSpan() );
column = index.getColumnIterator().next();
assertEquals( "since", column.getName() );
assertSame( entity.getTable(), index.getTable() );
}
@Test
public void testSecondaryTableIndex(){
PersistentClass entity = configuration().getClassMapping( Book.class.getName() );
Join join = (Join)entity.getJoinIterator().next();
Iterator<Index> itr = join.getTable().getIndexIterator();
assertTrue( itr.hasNext() );
Index index = itr.next();
assertFalse( itr.hasNext() );
assertTrue( "index name is not generated", StringHelper.isNotEmpty( index.getName() ) );
assertEquals( 2, index.getColumnSpan() );
Iterator<Column> columnIterator = index.getColumnIterator();
Column column = columnIterator.next();
assertEquals( "summ_size", column.getName() );
column = columnIterator.next();
assertEquals( "text", column.getName() );
assertSame( join.getTable(), index.getTable() );
}
@Test
public void testCollectionTableIndex(){
PersistentClass entity = configuration().getClassMapping( WealthyPerson.class.getName() );
Property property = entity.getProperty( "explicitVacationHomes" );
Set set = (Set)property.getValue();
Table collectionTable = set.getCollectionTable();
Iterator<Index> itr = collectionTable.getIndexIterator();
assertTrue( itr.hasNext() );
Index index = itr.next();
assertFalse( itr.hasNext() );
assertTrue( "index name is not generated", StringHelper.isNotEmpty( index.getName() ) );
assertEquals( 2, index.getColumnSpan() );
Iterator<Column> columnIterator = index.getColumnIterator();
Column column = columnIterator.next();
assertEquals( "countryName", column.getName() );
column = columnIterator.next();
assertEquals( "type_id", column.getName() );
assertSame( collectionTable, index.getTable() );
}
@Test
public void testJoinTableIndex(){
PersistentClass entity = configuration().getClassMapping( Alias.class.getName() );
Property property = entity.getProperty( "characters" );
Bag set = (Bag)property.getValue();
Table collectionTable = set.getCollectionTable();
Iterator<Index> itr = collectionTable.getIndexIterator();
assertTrue( itr.hasNext() );
Index index = itr.next();
assertFalse( itr.hasNext() );
assertTrue( "index name is not generated", StringHelper.isNotEmpty( index.getName() ) );
assertEquals( 1, index.getColumnSpan() );
Iterator<Column> columnIterator = index.getColumnIterator();
Column column = columnIterator.next();
assertEquals( "characters_id", column.getName() );
assertSame( collectionTable, index.getTable() );
}
@Test
public void testTableGeneratorIndex(){
//todo
}
}

View File

@ -0,0 +1,12 @@
package org.hibernate.test.annotations.index.jpa;
/**
* @author Strong Liu <stliu@hibernate.org>
*/
public class OrmXmlIndexTest extends AbstractJPAIndexTest {
@Override
protected String[] getXmlFiles() {
return new String[] { "org/hibernate/test/annotations/index/jpa/orm-index.xml" };
}
}

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.1" >
<package>org.hibernate.test.annotations.index.jpa</package>
<!--<access>FIELD</access>-->
<entity class="Car">
<table name="T_FATHER">
<index unique="true" column-list="brand, producer"/>
<index name="Car_idx" column-list="since DESC"/>
</table>
<secondary-table name="T_DEALER">
<index column-list="dealer_name ASC, rate DESC"/>
</secondary-table>
<attributes>
<id name="id">
<generated-value strategy="AUTO"/>
</id>
<basic name="brand"/>
<basic name="producer"/>
<basic name="since"/>
<many-to-many name="importers" mapped-by="cars">
<cascade><cascade-all/></cascade>
</many-to-many>
<element-collection name="otherDealers">
<collection-table name="CAR_DEALTERS">
<index column-list="name"/>
</collection-table>
</element-collection>
<embedded name="dealer">
<attribute-override name="name">
<column name="dealer_name" table="T_DEALER"/>
</attribute-override>
<attribute-override name="rate">
<column table="T_DEALER"/>
</attribute-override>
</embedded>
</attributes>
</entity>
<entity class="Importer">
<attributes>
<id name="id"/>
<basic name="name"/>
<many-to-many name="cars">
<join-table name="CAR_IMPORTER">
<index column-list="importers_id"/>
</join-table>
<cascade><cascade-all/></cascade>
</many-to-many>
</attributes>
</entity>
<embeddable class="Dealer">
<attributes>
<basic name="name"/>
<basic name="rate"/>
</attributes>
</embeddable>
</entity-mappings>