Merge remote-tracking branch 'upstream/master' into wip/6.0
This commit is contained in:
commit
6d349bac5b
|
@ -230,38 +230,55 @@ public class EnhancerImpl implements Enhancer {
|
|||
|
||||
Implementation isDirty = StubMethod.INSTANCE, getDirtyNames = StubMethod.INSTANCE, clearDirtyNames = StubMethod.INSTANCE;
|
||||
for ( AnnotatedFieldDescription collectionField : collectionFields ) {
|
||||
String collectionFieldName = collectionField.getName();
|
||||
Class adviceIsDirty;
|
||||
Class adviceGetDirtyNames;
|
||||
Class adviceClearDirtyNames;
|
||||
if ( collectionField.getType().asErasure().isAssignableTo( Map.class ) ) {
|
||||
adviceIsDirty = CodeTemplates.MapAreCollectionFieldsDirty.class;
|
||||
adviceGetDirtyNames = CodeTemplates.MapGetCollectionFieldDirtyNames.class;
|
||||
adviceClearDirtyNames = CodeTemplates.MapGetCollectionClearDirtyNames.class;
|
||||
}
|
||||
else {
|
||||
adviceIsDirty = CodeTemplates.CollectionAreCollectionFieldsDirty.class;
|
||||
adviceGetDirtyNames = CodeTemplates.CollectionGetCollectionFieldDirtyNames.class;
|
||||
adviceClearDirtyNames = CodeTemplates.CollectionGetCollectionClearDirtyNames.class;
|
||||
}
|
||||
if ( collectionField.isVisibleTo( managedCtClass ) ) {
|
||||
FieldDescription fieldDescription = collectionField.getFieldDescription();
|
||||
isDirty = Advice.withCustomMapping()
|
||||
.bind( CodeTemplates.FieldName.class, collectionField.getName() )
|
||||
.bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() )
|
||||
.to( CodeTemplates.MapAreCollectionFieldsDirty.class, adviceLocator )
|
||||
.bind( CodeTemplates.FieldName.class, collectionFieldName )
|
||||
.bind( CodeTemplates.FieldValue.class, fieldDescription )
|
||||
.to( adviceIsDirty, adviceLocator )
|
||||
.wrap( isDirty );
|
||||
getDirtyNames = Advice.withCustomMapping()
|
||||
.bind( CodeTemplates.FieldName.class, collectionField.getName() )
|
||||
.bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() )
|
||||
.to( CodeTemplates.MapGetCollectionFieldDirtyNames.class, adviceLocator )
|
||||
.bind( CodeTemplates.FieldName.class, collectionFieldName )
|
||||
.bind( CodeTemplates.FieldValue.class, fieldDescription )
|
||||
.to( adviceGetDirtyNames, adviceLocator )
|
||||
.wrap( getDirtyNames );
|
||||
clearDirtyNames = Advice.withCustomMapping()
|
||||
.bind( CodeTemplates.FieldName.class, collectionField.getName() )
|
||||
.bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() )
|
||||
.to( CodeTemplates.MapGetCollectionClearDirtyNames.class, adviceLocator )
|
||||
.bind( CodeTemplates.FieldName.class, collectionFieldName )
|
||||
.bind( CodeTemplates.FieldValue.class, fieldDescription )
|
||||
.to( adviceClearDirtyNames, adviceLocator )
|
||||
.wrap( clearDirtyNames );
|
||||
}
|
||||
else {
|
||||
CodeTemplates.GetterMapping getterMapping = new CodeTemplates.GetterMapping(
|
||||
collectionField.getFieldDescription() );
|
||||
isDirty = Advice.withCustomMapping()
|
||||
.bind( CodeTemplates.FieldName.class, collectionField.getName() )
|
||||
.bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() )
|
||||
.to( CodeTemplates.CollectionAreCollectionFieldsDirty.class, adviceLocator )
|
||||
.bind( CodeTemplates.FieldName.class, collectionFieldName )
|
||||
.bind( CodeTemplates.FieldValue.class, getterMapping )
|
||||
.to( adviceIsDirty, adviceLocator )
|
||||
.wrap( isDirty );
|
||||
getDirtyNames = Advice.withCustomMapping()
|
||||
.bind( CodeTemplates.FieldName.class, collectionField.getName() )
|
||||
.bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() )
|
||||
.to( CodeTemplates.CollectionGetCollectionFieldDirtyNames.class, adviceLocator )
|
||||
.bind( CodeTemplates.FieldName.class, collectionFieldName )
|
||||
.bind( CodeTemplates.FieldValue.class, getterMapping )
|
||||
.to( adviceGetDirtyNames, adviceLocator )
|
||||
.wrap( getDirtyNames );
|
||||
clearDirtyNames = Advice.withCustomMapping()
|
||||
.bind( CodeTemplates.FieldName.class, collectionField.getName() )
|
||||
.bind( CodeTemplates.FieldValue.class, collectionField.getFieldDescription() )
|
||||
.to( CodeTemplates.CollectionGetCollectionClearDirtyNames.class, adviceLocator )
|
||||
.bind( CodeTemplates.FieldName.class, collectionFieldName )
|
||||
.bind( CodeTemplates.FieldValue.class, getterMapping )
|
||||
.to( adviceClearDirtyNames, adviceLocator )
|
||||
.wrap( clearDirtyNames );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,14 @@ package org.hibernate.mapping;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
|
@ -39,9 +41,10 @@ import org.jboss.logging.Logger;
|
|||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings("deprecation")
|
||||
public class Table implements RelationalModel, Serializable, Exportable {
|
||||
private static final Logger log = Logger.getLogger( Table.class );
|
||||
private static final Column[] EMPTY_COLUMN_ARRAY = new Column[0];
|
||||
|
||||
private Identifier catalog;
|
||||
private Identifier schema;
|
||||
|
@ -50,7 +53,7 @@ public class Table implements RelationalModel, Serializable, Exportable {
|
|||
/**
|
||||
* contains all columns, including the primary key
|
||||
*/
|
||||
private Map columns = new LinkedHashMap();
|
||||
private Map<String, Column> columns = new LinkedHashMap<>();
|
||||
private KeyValue idValue;
|
||||
private PrimaryKey primaryKey;
|
||||
private Map<ForeignKeyKey, ForeignKey> foreignKeys = new LinkedHashMap<>();
|
||||
|
@ -246,7 +249,7 @@ public class Table implements RelationalModel, Serializable, Exportable {
|
|||
}
|
||||
|
||||
public Column getColumn(int n) {
|
||||
Iterator iter = columns.values().iterator();
|
||||
Iterator<Column> iter = columns.values().iterator();
|
||||
for ( int i = 0; i < n - 1; i++ ) {
|
||||
iter.next();
|
||||
}
|
||||
|
@ -282,7 +285,7 @@ public class Table implements RelationalModel, Serializable, Exportable {
|
|||
return columns.size();
|
||||
}
|
||||
|
||||
public Iterator getColumnIterator() {
|
||||
public Iterator<Column> getColumnIterator() {
|
||||
return columns.values().iterator();
|
||||
}
|
||||
|
||||
|
@ -290,7 +293,7 @@ public class Table implements RelationalModel, Serializable, Exportable {
|
|||
return indexes.values().iterator();
|
||||
}
|
||||
|
||||
public Iterator getForeignKeyIterator() {
|
||||
public Iterator<ForeignKey> getForeignKeyIterator() {
|
||||
return foreignKeys.values().iterator();
|
||||
}
|
||||
|
||||
|
@ -412,7 +415,7 @@ public class Table implements RelationalModel, Serializable, Exportable {
|
|||
}
|
||||
|
||||
public void validateColumns(Dialect dialect, Mapping mapping, TableMetadata tableInfo) {
|
||||
Iterator iter = getColumnIterator();
|
||||
Iterator<Column> iter = getColumnIterator();
|
||||
while ( iter.hasNext() ) {
|
||||
Column col = (Column) iter.next();
|
||||
|
||||
|
@ -440,7 +443,7 @@ public class Table implements RelationalModel, Serializable, Exportable {
|
|||
|
||||
}
|
||||
|
||||
public Iterator sqlAlterStrings(
|
||||
public Iterator<String> sqlAlterStrings(
|
||||
Dialect dialect,
|
||||
Metadata metadata,
|
||||
TableInformation tableInfo,
|
||||
|
@ -462,8 +465,8 @@ public class Table implements RelationalModel, Serializable, Exportable {
|
|||
.append( ' ' )
|
||||
.append( dialect.getAddColumnString() );
|
||||
|
||||
Iterator iter = getColumnIterator();
|
||||
List results = new ArrayList();
|
||||
Iterator<Column> iter = getColumnIterator();
|
||||
List<String> results = new ArrayList<>();
|
||||
|
||||
while ( iter.hasNext() ) {
|
||||
final Column column = (Column) iter.next();
|
||||
|
@ -539,7 +542,7 @@ public class Table implements RelationalModel, Serializable, Exportable {
|
|||
pkname = getPrimaryKey().getColumnIterator().next().getQuotedName( dialect );
|
||||
}
|
||||
|
||||
Iterator iter = getColumnIterator();
|
||||
Iterator<Column> iter = getColumnIterator();
|
||||
while ( iter.hasNext() ) {
|
||||
Column col = (Column) iter.next();
|
||||
|
||||
|
@ -667,7 +670,7 @@ public class Table implements RelationalModel, Serializable, Exportable {
|
|||
return uniqueKey;
|
||||
}
|
||||
|
||||
public UniqueKey createUniqueKey(List keyColumns) {
|
||||
public UniqueKey createUniqueKey(List<Column> keyColumns) {
|
||||
String keyName = Constraint.generateName( "UK_", this, keyColumns );
|
||||
UniqueKey uk = getOrCreateUniqueKey( keyName );
|
||||
uk.addColumns( keyColumns.iterator() );
|
||||
|
@ -693,16 +696,16 @@ public class Table implements RelationalModel, Serializable, Exportable {
|
|||
public void createForeignKeys() {
|
||||
}
|
||||
|
||||
public ForeignKey createForeignKey(String keyName, List keyColumns, String referencedEntityName, String keyDefinition) {
|
||||
public ForeignKey createForeignKey(String keyName, List<Column> keyColumns, String referencedEntityName, String keyDefinition) {
|
||||
return createForeignKey( keyName, keyColumns, referencedEntityName, keyDefinition, null );
|
||||
}
|
||||
|
||||
public ForeignKey createForeignKey(
|
||||
String keyName,
|
||||
List keyColumns,
|
||||
List<Column> keyColumns,
|
||||
String referencedEntityName,
|
||||
String keyDefinition,
|
||||
List referencedColumns) {
|
||||
List<Column> referencedColumns) {
|
||||
final ForeignKeyKey key = new ForeignKeyKey( keyColumns, referencedEntityName, referencedColumns );
|
||||
|
||||
ForeignKey fk = foreignKeys.get( key );
|
||||
|
@ -826,14 +829,14 @@ public class Table implements RelationalModel, Serializable, Exportable {
|
|||
return checkConstraints.iterator();
|
||||
}
|
||||
|
||||
public Iterator sqlCommentStrings(Dialect dialect, String defaultCatalog, String defaultSchema) {
|
||||
List comments = new ArrayList();
|
||||
public Iterator<String> sqlCommentStrings(Dialect dialect, String defaultCatalog, String defaultSchema) {
|
||||
List<String> comments = new ArrayList<>();
|
||||
if ( dialect.supportsCommentOn() ) {
|
||||
String tableName = getQualifiedName( dialect, defaultCatalog, defaultSchema );
|
||||
if ( comment != null ) {
|
||||
comments.add( "comment on table " + tableName + " is '" + comment + "'" );
|
||||
}
|
||||
Iterator iter = getColumnIterator();
|
||||
Iterator<Column> iter = getColumnIterator();
|
||||
while ( iter.hasNext() ) {
|
||||
Column column = (Column) iter.next();
|
||||
String columnComment = column.getComment();
|
||||
|
@ -858,40 +861,38 @@ public class Table implements RelationalModel, Serializable, Exportable {
|
|||
return identifier == null ? null : identifier.render();
|
||||
}
|
||||
|
||||
|
||||
public static class ForeignKeyKey implements Serializable {
|
||||
String referencedClassName;
|
||||
List columns;
|
||||
List referencedColumns;
|
||||
private final String referencedClassName;
|
||||
private final Column[] columns;
|
||||
private final Column[] referencedColumns;
|
||||
|
||||
ForeignKeyKey(List columns, String referencedClassName, List referencedColumns) {
|
||||
ForeignKeyKey(List<Column> columns, String referencedClassName, List<Column> referencedColumns) {
|
||||
Objects.requireNonNull( columns );
|
||||
Objects.requireNonNull( referencedClassName );
|
||||
this.referencedClassName = referencedClassName;
|
||||
this.columns = new ArrayList();
|
||||
this.columns.addAll( columns );
|
||||
this.columns = columns.toArray( EMPTY_COLUMN_ARRAY );
|
||||
if ( referencedColumns != null ) {
|
||||
this.referencedColumns = new ArrayList();
|
||||
this.referencedColumns.addAll( referencedColumns );
|
||||
this.referencedColumns = referencedColumns.toArray( EMPTY_COLUMN_ARRAY );
|
||||
}
|
||||
else {
|
||||
this.referencedColumns = Collections.EMPTY_LIST;
|
||||
this.referencedColumns = EMPTY_COLUMN_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return columns.hashCode() + referencedColumns.hashCode();
|
||||
return Arrays.hashCode( columns ) + Arrays.hashCode( referencedColumns );
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
ForeignKeyKey fkk = (ForeignKeyKey) other;
|
||||
return fkk != null && fkk.columns.equals( columns ) && fkk.referencedColumns.equals( referencedColumns );
|
||||
return fkk != null && Arrays.equals( fkk.columns, columns ) && Arrays.equals( fkk.referencedColumns, referencedColumns );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ForeignKeyKey{" +
|
||||
"columns=" + String.join( ",", columns ) +
|
||||
", referencedClassName='" + referencedClassName + '\'' +
|
||||
", referencedColumns=" + String.join( ",", referencedColumns ) +
|
||||
return "ForeignKeyKey{columns=" + Arrays.toString( columns ) +
|
||||
", referencedClassName='" + referencedClassName +
|
||||
"', referencedColumns=" + Arrays.toString( referencedColumns ) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -361,6 +361,7 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
|
|||
columns,
|
||||
columnReaders,
|
||||
columnReaderTemplates,
|
||||
formulaTemplates != null && formulaTemplates.length > 0 ? formulaTemplates : null,
|
||||
factory
|
||||
);
|
||||
}
|
||||
|
@ -373,6 +374,17 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
|
|||
final String[] columnReaders,
|
||||
final String[] columnReaderTemplates,
|
||||
final Mapping factory) throws MappingException {
|
||||
initIdentifierPropertyPaths(path, etype, columns, columnReaders, columnReaderTemplates, null, factory);
|
||||
}
|
||||
|
||||
protected void initIdentifierPropertyPaths(
|
||||
final String path,
|
||||
final EntityType etype,
|
||||
final String[] columns,
|
||||
final String[] columnReaders,
|
||||
final String[] columnReaderTemplates,
|
||||
final String[] formulaTemplates,
|
||||
final Mapping factory) throws MappingException {
|
||||
|
||||
Type idtype = etype.getIdentifierOrUniqueKeyType( factory );
|
||||
String idPropName = etype.getIdentifierOrUniqueKeyPropertyName( factory );
|
||||
|
@ -381,15 +393,15 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
|
|||
if ( etype.isReferenceToPrimaryKey() ) {
|
||||
if ( !hasNonIdentifierPropertyNamedId ) {
|
||||
String idpath1 = extendPath( path, EntityPersister.ENTITY_ID );
|
||||
addPropertyPath( idpath1, idtype, columns, columnReaders, columnReaderTemplates, null, factory );
|
||||
initPropertyPaths( idpath1, idtype, columns, columnReaders, columnReaderTemplates, null, factory );
|
||||
addPropertyPath( idpath1, idtype, columns, columnReaders, columnReaderTemplates, formulaTemplates, factory );
|
||||
initPropertyPaths( idpath1, idtype, columns, columnReaders, columnReaderTemplates, formulaTemplates, factory );
|
||||
}
|
||||
}
|
||||
|
||||
if ( (! etype.isNullable() ) && idPropName != null ) {
|
||||
String idpath2 = extendPath( path, idPropName );
|
||||
addPropertyPath( idpath2, idtype, columns, columnReaders, columnReaderTemplates, null, factory );
|
||||
initPropertyPaths( idpath2, idtype, columns, columnReaders, columnReaderTemplates, null, factory );
|
||||
addPropertyPath( idpath2, idtype, columns, columnReaders, columnReaderTemplates, formulaTemplates, factory );
|
||||
initPropertyPaths( idpath2, idtype, columns, columnReaders, columnReaderTemplates, formulaTemplates, factory );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ public class FetchGraphTest extends BaseEntityManagerFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Entity(name = "Trigger")
|
||||
@Table(name = "Trigger")
|
||||
@Table(name = "TriggerEntity")
|
||||
static class Trigger {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
package org.hibernate.persister.entity;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.annotations.JoinColumnOrFormula;
|
||||
import org.hibernate.annotations.JoinColumnsOrFormulas;
|
||||
import org.hibernate.annotations.JoinFormula;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
@TestForIssue(jiraKey = "HHH-14223")
|
||||
public class JoinFormulaImplicitJoinTest extends BaseEntityManagerFunctionalTestCase {
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class, PersonVersion.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConfigOptions(Map options) {
|
||||
options.put(
|
||||
AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS,
|
||||
Boolean.TRUE
|
||||
);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
final Person person = new Person();
|
||||
entityManager.persist(person);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
final PersonVersion personVersion = new PersonVersion();
|
||||
personVersion.setName("Name" + i);
|
||||
personVersion.setVersion(i);
|
||||
personVersion.setPerson(person);
|
||||
entityManager.persist(personVersion);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected int entityCount() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImplicitJoin() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
entityManager.createQuery(
|
||||
"SELECT person\n" +
|
||||
"FROM Person AS person\n" +
|
||||
" LEFT JOIN FETCH person.latestPersonVersion\n" +
|
||||
"order by person.latestPersonVersion.id desc\n"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<PersonVersion> personVersions;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumnsOrFormulas({
|
||||
@JoinColumnOrFormula(
|
||||
formula = @JoinFormula(
|
||||
value = "(SELECT person_version.id FROM person_version WHERE person_version.person_id = id ORDER BY person_version.version DESC LIMIT 1)",
|
||||
referencedColumnName = "id")
|
||||
)
|
||||
})
|
||||
private PersonVersion latestPersonVersion;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<PersonVersion> getPersonVersions() {
|
||||
return personVersions;
|
||||
}
|
||||
|
||||
public void setPersonVersions(List<PersonVersion> personVersions) {
|
||||
this.personVersions = personVersions;
|
||||
}
|
||||
|
||||
public PersonVersion getLatestPersonVersion() {
|
||||
return latestPersonVersion;
|
||||
}
|
||||
|
||||
public void setLatestPersonVersion(PersonVersion latestPersonVersion) {
|
||||
this.latestPersonVersion = latestPersonVersion;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "PersonVersion")
|
||||
public static class PersonVersion {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Integer version;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "person_id")
|
||||
private Person person;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public Integer getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(Integer version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(Person person) {
|
||||
this.person = person;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.query.criteria.internal;
|
||||
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.Order;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* @author seregamorph
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-13884")
|
||||
public class HHH13884Test {
|
||||
|
||||
@Test
|
||||
public void testDefaultReversedOrderImpl() {
|
||||
Expression<?> expression = mock( Expression.class );
|
||||
|
||||
OrderImpl order = new OrderImpl( expression );
|
||||
|
||||
assertEquals( expression, order.getExpression() );
|
||||
assertTrue( "Order should be ascending by default", order.isAscending() );
|
||||
|
||||
Order reversed = order.reverse();
|
||||
|
||||
assertEquals( expression, reversed.getExpression() );
|
||||
assertFalse( "Reversed Order should be descending", reversed.isAscending() );
|
||||
|
||||
assertNotSame( "Order.reverse() should create new instance by the contract", order, reversed );
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.test.bytecode.enhancement.lazy.proxy.inlinedirtychecking;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedField;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext;
|
||||
|
||||
|
@ -18,4 +19,9 @@ public class DirtyCheckEnhancementContext extends EnhancerTestContext {
|
|||
public boolean doExtendedEnhancement(UnloadedClass classDescriptor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doBiDirectionalAssociationManagement(UnloadedField field) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.bytecode.enhancement.lazy.proxy.inlinedirtychecking;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.Converter;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
@RunWith(BytecodeEnhancerRunner.class)
|
||||
@CustomEnhancementContext({ DirtyCheckEnhancementContext.class })
|
||||
public class DirtyCheckPrivateUnMappedCollectionTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
boolean skipTest;
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
|
||||
ssrb.applySetting( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, "100" );
|
||||
ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources sources) {
|
||||
String byteCodeProvider = Environment.getProperties().getProperty( AvailableSettings.BYTECODE_PROVIDER );
|
||||
if ( byteCodeProvider != null && !Environment.BYTECODE_PROVIDER_NAME_BYTEBUDDY.equals( byteCodeProvider ) ) {
|
||||
// skip the test if the bytecode provider is Javassist
|
||||
skipTest = true;
|
||||
}
|
||||
else {
|
||||
sources.addAnnotatedClass( Measurement.class );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIt() {
|
||||
if ( skipTest ) {
|
||||
return;
|
||||
}
|
||||
inTransaction(
|
||||
session -> {
|
||||
Tag tag = new Tag();
|
||||
tag.setName( "tag1" );
|
||||
|
||||
Measurement measurementDescriptor = new Measurement();
|
||||
measurementDescriptor.addTag( tag );
|
||||
|
||||
session.save( measurementDescriptor );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
public static class AbstractMeasurement {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
@Convert(converter = TagAttributeConverter.class)
|
||||
private List<Tag> tags = new ArrayList<>();
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<Tag> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public void setTags(List<Tag> tags) {
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
public void addTag(Tag tag) {
|
||||
this.tags.add( tag );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Measurement")
|
||||
public static class Measurement extends AbstractMeasurement {
|
||||
}
|
||||
|
||||
public static class Tag {
|
||||
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Converter
|
||||
public static class TagAttributeConverter implements AttributeConverter<List<Tag>, String> {
|
||||
|
||||
@Override
|
||||
public String convertToDatabaseColumn(List<Tag> attribute) {
|
||||
return "empty";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tag> convertToEntityAttribute(String dbData) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -7,13 +7,14 @@
|
|||
package org.hibernate.test.bytecode.enhancement.lazy.proxy.inlinedirtychecking;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedField;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public class NoDirtyCheckEnhancementContext extends EnhancerTestContext {
|
||||
public class NoDirtyCheckEnhancementContext extends EnhancerTestContext {
|
||||
@Override
|
||||
public boolean doDirtyCheckingInline(UnloadedClass classDescriptor) {
|
||||
return false;
|
||||
|
@ -23,4 +24,9 @@ public class NoDirtyCheckEnhancementContext extends EnhancerTestContext {
|
|||
public boolean doExtendedEnhancement(UnloadedClass classDescriptor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doBiDirectionalAssociationManagement(UnloadedField field) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.foreignkeys;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Yanming Zhou
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-14230")
|
||||
public class HHH14230 {
|
||||
|
||||
private static final String TABLE_NAME = "test_entity";
|
||||
private static final String JOIN_COLUMN_NAME = "parent";
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Metadata metadata = new MetadataSources(new StandardServiceRegistryBuilder().build())
|
||||
.addAnnotatedClass(TestEntity.class).buildMetadata();
|
||||
Table table = StreamSupport.stream(metadata.getDatabase().getNamespaces().spliterator(), false)
|
||||
.flatMap(namespace -> namespace.getTables().stream())
|
||||
.filter(t -> t.getName().equals(TABLE_NAME)).findFirst().orElse(null);
|
||||
assertNotNull(table);
|
||||
assertEquals(1, table.getForeignKeys().size());
|
||||
|
||||
// ClassCastException before HHH-14230
|
||||
assertTrue(table.getForeignKeys().keySet().iterator().next().toString().contains(JOIN_COLUMN_NAME));
|
||||
}
|
||||
|
||||
@Entity
|
||||
@javax.persistence.Table(name = TABLE_NAME)
|
||||
public static class TestEntity {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = JOIN_COLUMN_NAME)
|
||||
private TestEntity parent;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public TestEntity getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(TestEntity parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue