HHH-8167 - Adding @NotNull to a @ManyToOne association with @JoinColumnsOrFormulas logs a ClassCastException
This commit is contained in:
parent
53f7b73adb
commit
c259e157b0
|
@ -4890,7 +4890,7 @@ Changes in version 0.9.5 (8.2.2002)
|
|||
* fixed potential bug related to cacheing of compiled queries
|
||||
* major rewrite of code relating to O-R mappings
|
||||
* Session.copy() and Session.equals() as convenience for users
|
||||
* fixed repeated invocations of hasNext() on iterator + iterators now always work with distinct SQL resultsets
|
||||
* fixed repeated invocations of hasNext() on iterator + wrappedIterators now always work with distinct SQL resultsets
|
||||
* McKoi dialect was contributed by Gabe Hicks
|
||||
|
||||
Changes in version 0.9.4 (29.1.2002)
|
||||
|
|
|
@ -26,6 +26,8 @@ import java.util.HashMap;
|
|||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.MappingException;
|
||||
|
@ -33,12 +35,15 @@ import org.hibernate.mapping.Column;
|
|||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
|
||||
/**
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class CopyIdentifierComponentSecondPass implements SecondPass {
|
||||
private static final Logger log = Logger.getLogger( CopyIdentifierComponentSecondPass.class );
|
||||
|
||||
private final String referencedEntityName;
|
||||
private final Component component;
|
||||
private final Mappings mappings;
|
||||
|
@ -113,7 +118,7 @@ public class CopyIdentifierComponentSecondPass implements SecondPass {
|
|||
final SimpleValue referencedValue = (SimpleValue) referencedProperty.getValue();
|
||||
value.setTypeName( referencedValue.getTypeName() );
|
||||
value.setTypeParameters( referencedValue.getTypeParameters() );
|
||||
final Iterator<Column> columns = referencedValue.getColumnIterator();
|
||||
final Iterator<Selectable> columns = referencedValue.getColumnIterator();
|
||||
|
||||
if ( joinColumns[0].isNameDeferred() ) {
|
||||
joinColumns[0].copyReferencedStructureAndCreateDefaultJoinColumns(
|
||||
|
@ -124,7 +129,12 @@ public class CopyIdentifierComponentSecondPass implements SecondPass {
|
|||
else {
|
||||
//FIXME take care of Formula
|
||||
while ( columns.hasNext() ) {
|
||||
Column column = columns.next();
|
||||
final Selectable selectable = columns.next();
|
||||
if ( ! Column.class.isInstance( selectable ) ) {
|
||||
log.debug( "Encountered formula definition; skipping" );
|
||||
continue;
|
||||
}
|
||||
final Column column = (Column) selectable;
|
||||
final Ejb3JoinColumn joinColumn;
|
||||
String logicalColumnName = null;
|
||||
if ( isExplicitReference ) {
|
||||
|
|
|
@ -60,6 +60,7 @@ import org.hibernate.mapping.Column;
|
|||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.SingleTableSubclass;
|
||||
|
||||
/**
|
||||
|
@ -156,6 +157,7 @@ class TypeSafeActivator {
|
|||
}
|
||||
|
||||
applyRelationalConstraints(
|
||||
factory,
|
||||
activationContext.getConfiguration().createMappings().getClasses().values(),
|
||||
properties,
|
||||
activationContext.getServiceRegistry().getService( JdbcServices.class ).getDialect()
|
||||
|
@ -163,8 +165,11 @@ class TypeSafeActivator {
|
|||
}
|
||||
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
public static void applyRelationalConstraints(Collection<PersistentClass> persistentClasses, Properties properties, Dialect dialect) {
|
||||
ValidatorFactory factory = getValidatorFactory( properties );
|
||||
public static void applyRelationalConstraints(
|
||||
ValidatorFactory factory,
|
||||
Collection<PersistentClass> persistentClasses,
|
||||
Properties properties,
|
||||
Dialect dialect) {
|
||||
Class<?>[] groupsArray = new GroupsPerOperation( properties ).get( GroupsPerOperation.Operation.DDL );
|
||||
Set<Class<?>> groups = new HashSet<Class<?>>( Arrays.asList( groupsArray ) );
|
||||
|
||||
|
@ -305,14 +310,23 @@ class TypeSafeActivator {
|
|||
private static boolean applyNotNull(Property property, ConstraintDescriptor<?> descriptor) {
|
||||
boolean hasNotNull = false;
|
||||
if ( NotNull.class.equals( descriptor.getAnnotation().annotationType() ) ) {
|
||||
// single table inheritance should not be forced to null due to shared state
|
||||
if ( !( property.getPersistentClass() instanceof SingleTableSubclass ) ) {
|
||||
//single table should not be forced to null
|
||||
if ( !property.isComposite() ) { //composite should not add not-null on all columns
|
||||
@SuppressWarnings( "unchecked" )
|
||||
Iterator<Column> iter = property.getColumnIterator();
|
||||
//composite should not add not-null on all columns
|
||||
if ( !property.isComposite() ) {
|
||||
final Iterator<Selectable> iter = property.getColumnIterator();
|
||||
while ( iter.hasNext() ) {
|
||||
iter.next().setNullable( false );
|
||||
hasNotNull = true;
|
||||
final Selectable selectable = iter.next();
|
||||
if ( Column.class.isInstance( selectable ) ) {
|
||||
Column.class.cast( selectable ).setNullable( false );
|
||||
}
|
||||
else {
|
||||
LOG.debugf(
|
||||
"@NotNull was applied to attribute [%s] which is defined (at least partially) " +
|
||||
"by formula(s); formula portions will be skipped",
|
||||
property.getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,46 +24,35 @@
|
|||
*/
|
||||
package org.hibernate.internal.util.collections;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An JoinedIterator is an Iterator that wraps a number of Iterators.
|
||||
*
|
||||
* This class makes multiple iterators look like one to the caller.
|
||||
* When any method from the Iterator interface is called, the JoinedIterator
|
||||
* will delegate to a single underlying Iterator. The JoinedIterator will
|
||||
* invoke the Iterators in sequence until all Iterators are exhausted.
|
||||
* An Iterator implementation that wraps other Iterators, and presents them all as one
|
||||
* continuous Iterator. When any method from Iterator is called, we delegate to each
|
||||
* wrapped Iterator in turn until all wrapped Iterators are exhausted.
|
||||
*
|
||||
* @author Gavine King
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JoinedIterator implements Iterator {
|
||||
public class JoinedIterator<T> implements Iterator<T> {
|
||||
private Iterator<T>[] wrappedIterators;
|
||||
|
||||
private static final Iterator[] ITERATORS = {};
|
||||
|
||||
// wrapped iterators
|
||||
private Iterator[] iterators;
|
||||
|
||||
// index of current iterator in the wrapped iterators array
|
||||
private int currentIteratorIndex;
|
||||
private Iterator<T> currentIterator;
|
||||
private Iterator<T> lastUsedIterator;
|
||||
|
||||
// the current iterator
|
||||
private Iterator currentIterator;
|
||||
|
||||
// the last used iterator
|
||||
private Iterator lastUsedIterator;
|
||||
|
||||
public JoinedIterator(List iterators) {
|
||||
this( (Iterator[]) iterators.toArray(ITERATORS) );
|
||||
@SuppressWarnings("unchecked")
|
||||
public JoinedIterator(List<Iterator<T>> wrappedIterators) {
|
||||
this( wrappedIterators.toArray( new Iterator[ wrappedIterators.size() ]) );
|
||||
}
|
||||
|
||||
public JoinedIterator(Iterator[] iterators) {
|
||||
if( iterators==null )
|
||||
throw new NullPointerException("Unexpected NULL iterators argument");
|
||||
this.iterators = iterators;
|
||||
}
|
||||
|
||||
public JoinedIterator(Iterator first, Iterator second) {
|
||||
this( new Iterator[] { first, second } );
|
||||
public JoinedIterator(Iterator<T>... iteratorsToWrap) {
|
||||
if( iteratorsToWrap == null ) {
|
||||
throw new NullPointerException( "Iterators to join were null" );
|
||||
}
|
||||
this.wrappedIterators = iteratorsToWrap;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
|
@ -71,7 +60,7 @@ public class JoinedIterator implements Iterator {
|
|||
return currentIterator.hasNext();
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
public T next() {
|
||||
updateCurrentIterator();
|
||||
return currentIterator.next();
|
||||
}
|
||||
|
@ -85,22 +74,21 @@ public class JoinedIterator implements Iterator {
|
|||
// call this before any Iterator method to make sure that the current Iterator
|
||||
// is not exhausted
|
||||
protected void updateCurrentIterator() {
|
||||
|
||||
if (currentIterator == null) {
|
||||
if( iterators.length==0 ) {
|
||||
currentIterator = EmptyIterator.INSTANCE;
|
||||
if ( currentIterator == null ) {
|
||||
if( wrappedIterators.length == 0 ) {
|
||||
currentIterator = Collections.emptyIterator();
|
||||
}
|
||||
else {
|
||||
currentIterator = iterators[0];
|
||||
currentIterator = wrappedIterators[0];
|
||||
}
|
||||
// set last used iterator here, in case the user calls remove
|
||||
// before calling hasNext() or next() (although they shouldn't)
|
||||
lastUsedIterator = currentIterator;
|
||||
}
|
||||
|
||||
while (! currentIterator.hasNext() && currentIteratorIndex < iterators.length - 1) {
|
||||
while (! currentIterator.hasNext() && currentIteratorIndex < wrappedIterators.length - 1) {
|
||||
currentIteratorIndex++;
|
||||
currentIterator = iterators[currentIteratorIndex];
|
||||
currentIterator = wrappedIterators[currentIteratorIndex];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.mapping;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
@ -365,8 +366,8 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
}
|
||||
}
|
||||
|
||||
public Iterator getColumnIterator() {
|
||||
return EmptyIterator.INSTANCE;
|
||||
public Iterator<Selectable> getColumnIterator() {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
public int getColumnSpan() {
|
||||
|
|
|
@ -106,7 +106,7 @@ public class Component extends SimpleValue implements MetaAttributable {
|
|||
}
|
||||
return n;
|
||||
}
|
||||
public Iterator getColumnIterator() {
|
||||
public Iterator<Selectable> getColumnIterator() {
|
||||
Iterator[] iters = new Iterator[ getPropertySpan() ];
|
||||
Iterator iter = getPropertyIterator();
|
||||
int i=0;
|
||||
|
|
|
@ -76,7 +76,7 @@ public class OneToMany implements Value {
|
|||
// no foreign key element of for a one-to-many
|
||||
}
|
||||
|
||||
public Iterator getColumnIterator() {
|
||||
public Iterator<Selectable> getColumnIterator() {
|
||||
return associatedClass.getKey().getColumnIterator();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,9 +22,13 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.mapping;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.function.SQLFunctionRegistry;
|
||||
|
||||
/**
|
||||
* Models the commonality between a column and a formula (computed value).
|
||||
*/
|
||||
public interface Selectable {
|
||||
public String getAlias(Dialect dialect);
|
||||
public String getAlias(Dialect dialect, Table table);
|
||||
|
|
|
@ -75,7 +75,8 @@ public class SimpleValue implements KeyValue {
|
|||
|
||||
private final Mappings mappings;
|
||||
|
||||
private final List columns = new ArrayList();
|
||||
private final List<Selectable> columns = new ArrayList<Selectable>();
|
||||
|
||||
private String typeName;
|
||||
private Properties identifierGeneratorProperties;
|
||||
private String identifierGeneratorStrategy = DEFAULT_ID_GEN_STRATEGY;
|
||||
|
@ -132,7 +133,7 @@ public class SimpleValue implements KeyValue {
|
|||
public int getColumnSpan() {
|
||||
return columns.size();
|
||||
}
|
||||
public Iterator getColumnIterator() {
|
||||
public Iterator<Selectable> getColumnIterator() {
|
||||
return columns.iterator();
|
||||
}
|
||||
public List getConstraintColumns() {
|
||||
|
|
|
@ -41,7 +41,7 @@ import org.hibernate.type.Type;
|
|||
*/
|
||||
public interface Value extends Serializable {
|
||||
public int getColumnSpan();
|
||||
public Iterator getColumnIterator();
|
||||
public Iterator<Selectable> getColumnIterator();
|
||||
public Type getType() throws MappingException;
|
||||
public FetchMode getFetchMode();
|
||||
public Table getTable();
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @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.formulajoin;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity
|
||||
public class AnnotatedDetail {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
// because otherwise schema export would not know about it...
|
||||
@Column( name = "detail_domain" )
|
||||
private String domain;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @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.formulajoin;
|
||||
|
||||
import org.hibernate.cfg.Configuration;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class AnnotatedFormWithBeanValidationNotNullTest extends BaseUnitTestCase {
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-8167" )
|
||||
public void testAnnotatedFormWithBeanValidationNotNull() {
|
||||
Configuration cfg = new Configuration();
|
||||
cfg.addAnnotatedClass( AnnotatedMaster.class ).addAnnotatedClass( AnnotatedDetail.class );
|
||||
cfg.buildSessionFactory();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @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.formulajoin;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
import org.hibernate.annotations.JoinColumnOrFormula;
|
||||
import org.hibernate.annotations.JoinColumnsOrFormulas;
|
||||
import org.hibernate.annotations.JoinFormula;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity
|
||||
public class AnnotatedMaster {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
@ManyToOne(fetch= FetchType.EAGER, optional=false)
|
||||
@JoinColumnsOrFormulas({
|
||||
@JoinColumnOrFormula(formula=@JoinFormula(value="my_domain_key'", referencedColumnName="detail_domain")),
|
||||
@JoinColumnOrFormula(column=@JoinColumn(name="detail", referencedColumnName="id"))
|
||||
})
|
||||
@Fetch(FetchMode.JOIN)
|
||||
@NotNull
|
||||
private AnnotatedDetail detail;
|
||||
}
|
|
@ -30,6 +30,8 @@ import org.hibernate.Session;
|
|||
import org.hibernate.Transaction;
|
||||
import org.hibernate.dialect.PostgreSQL81Dialect;
|
||||
import org.hibernate.dialect.PostgreSQLDialect;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -111,6 +113,5 @@ public class FormulaJoinTest extends BaseCoreFunctionalTestCase {
|
|||
s.close();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue