Skip to content

Commit 19d5895

Browse files
committed
finally sort out handling of @id and @Version in query validator
also remove 'this' hacks made obsolete by Steve's work on core
1 parent d6ab2fd commit 19d5895

File tree

15 files changed

+288
-90
lines changed

15 files changed

+288
-90
lines changed

hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractIdentifiableType.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,11 +423,10 @@ else if ( id != null ) {
423423
}
424424
else {
425425
assert type instanceof EmbeddableDomainType;
426-
final EmbeddableDomainType<?> compositeType = (EmbeddableDomainType<?>) type;
427426
return new EmbeddedSqmPathSource<>(
428427
EntityIdentifierMapping.ID_ROLE_NAME,
429428
(SqmPathSource) id,
430-
compositeType,
429+
(EmbeddableDomainType<?>) type,
431430
Bindable.BindableType.SINGULAR_ATTRIBUTE,
432431
id.isGeneric()
433432
);

hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2999,17 +2999,22 @@ public SqmPath<?> visitEntityIdReference(HqlParser.EntityIdReferenceContext ctx)
29992999

30003000
final SqmPath<?> sqmPath = consumeDomainPath( ctx.path() );
30013001
final DomainType<?> sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType();
3002-
3003-
if ( sqmPathType instanceof IdentifiableDomainType<?> ) {
3004-
final SqmPathSource<?> identifierDescriptor = ( (IdentifiableDomainType<?>) sqmPathType ).getIdentifierDescriptor();
3002+
if ( sqmPathType instanceof IdentifiableDomainType<?> identifiableType ) {
3003+
final SqmPathSource<?> identifierDescriptor = identifiableType.getIdentifierDescriptor();
3004+
if ( identifierDescriptor == null ) {
3005+
// mainly for benefit of Hibernate Processor
3006+
throw new FunctionArgumentException( "Argument '" + sqmPath.getNavigablePath()
3007+
+ "' of 'id()' is a '" + identifiableType.getTypeName()
3008+
+ "' and does not have a well-defined '@Id' attribute" );
3009+
}
30053010
return sqmPath.get( identifierDescriptor.getPathName() );
30063011
}
30073012
else if ( sqmPath instanceof SqmAnyValuedSimplePath<?> ) {
30083013
return sqmPath.resolvePathPart( AnyKeyPart.KEY_NAME, true, processingStateStack.getCurrent().getCreationState() );
30093014
}
30103015
else {
30113016
throw new FunctionArgumentException( "Argument '" + sqmPath.getNavigablePath()
3012-
+ "' of 'id()' function does not resolve to an entity type" );
3017+
+ "' of 'id()' does not resolve to an entity type" );
30133018
}
30143019
}
30153020

@@ -3022,26 +3027,21 @@ public SqmExpression<?> visitEntityVersionExpression(HqlParser.EntityVersionExpr
30223027
public SqmPath<?> visitEntityVersionReference(HqlParser.EntityVersionReferenceContext ctx) {
30233028
final SqmPath<?> sqmPath = consumeDomainPath( ctx.path() );
30243029
final DomainType<?> sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType();
3025-
3026-
if ( sqmPathType instanceof IdentifiableDomainType<?> ) {
3027-
@SuppressWarnings("unchecked")
3028-
final IdentifiableDomainType<Object> identifiableType = (IdentifiableDomainType<Object>) sqmPathType;
3029-
final SingularPersistentAttribute<Object, ?> versionAttribute = identifiableType.findVersionAttribute();
3030-
if ( versionAttribute == null ) {
3031-
throw new FunctionArgumentException(
3032-
String.format(
3033-
"Argument '%s' of 'version()' function resolved to entity type '%s' which does not have a '@Version' attribute",
3034-
sqmPath.getNavigablePath(),
3035-
identifiableType.getTypeName()
3036-
)
3037-
);
3030+
if ( sqmPathType instanceof IdentifiableDomainType<?> identifiableType ) {
3031+
if ( !identifiableType.hasVersionAttribute() ) {
3032+
throw new FunctionArgumentException( "Argument '" + sqmPath.getNavigablePath()
3033+
+ "' of 'version()' is a '" + identifiableType.getTypeName()
3034+
+ "' and does not have a '@Version' attribute" );
30383035
}
3039-
3036+
@SuppressWarnings("unchecked")
3037+
final SingularPersistentAttribute<Object, ?> versionAttribute =
3038+
(SingularPersistentAttribute<Object, ?>) identifiableType.findVersionAttribute();
30403039
return sqmPath.get( versionAttribute );
30413040
}
3042-
3043-
throw new FunctionArgumentException( "Argument '" + sqmPath.getNavigablePath()
3044-
+ "' of 'version()' function does not resolve to an entity type" );
3041+
else {
3042+
throw new FunctionArgumentException( "Argument '" + sqmPath.getNavigablePath()
3043+
+ "' of 'version()' does not resolve to an entity type" );
3044+
}
30453045
}
30463046

30473047
@Override
@@ -3060,35 +3060,29 @@ public SqmPath<?> visitEntityNaturalIdReference(HqlParser.EntityNaturalIdReferen
30603060

30613061
if ( sqmPathType instanceof IdentifiableDomainType<?> ) {
30623062
@SuppressWarnings("unchecked")
3063-
final IdentifiableDomainType<Object> identifiableType = (IdentifiableDomainType<? super Object>) sqmPathType;
3063+
final IdentifiableDomainType<Object> identifiableType = (IdentifiableDomainType<Object>) sqmPathType;
30643064
final List<? extends PersistentAttribute<Object, ?>> attributes = identifiableType.findNaturalIdAttributes();
30653065
if ( attributes == null ) {
3066-
throw new FunctionArgumentException(
3067-
String.format(
3068-
"Argument '%s' of 'naturalid()' function resolved to entity type '%s' which does not have a natural id",
3069-
sqmPath.getNavigablePath(),
3070-
identifiableType.getTypeName()
3071-
)
3066+
throw new FunctionArgumentException( "Argument '" + sqmPath.getNavigablePath()
3067+
+ "' of 'naturalid()' is a '" + identifiableType.getTypeName()
3068+
+ "' and does not have a natural id"
30723069
);
30733070
}
30743071
else if ( attributes.size() >1 ) {
3075-
throw new FunctionArgumentException(
3076-
String.format(
3077-
"Argument '%s' of 'naturalid()' function resolved to entity type '%s' which has a composite natural id",
3078-
sqmPath.getNavigablePath(),
3079-
identifiableType.getTypeName()
3080-
)
3072+
throw new FunctionArgumentException( "Argument '" + sqmPath.getNavigablePath()
3073+
+ "' of 'naturalid()' is a '" + identifiableType.getTypeName()
3074+
+ "' and has a composite natural id"
30813075
);
30823076
}
30833077

30843078
@SuppressWarnings("unchecked")
3085-
SingularAttribute<Object, ?> naturalIdAttribute
3079+
final SingularAttribute<Object, ?> naturalIdAttribute
30863080
= (SingularAttribute<Object, ?>) attributes.get(0);
30873081
return sqmPath.get( naturalIdAttribute );
30883082
}
30893083

30903084
throw new FunctionArgumentException( "Argument '" + sqmPath.getNavigablePath()
3091-
+ "' of 'naturalid()' function does not resolve to an entity type" );
3085+
+ "' of 'naturalid()' does not resolve to an entity type" );
30923086
}
30933087
//
30943088
// @Override

tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/basic/Concrete.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
import jakarta.data.repository.Repository;
44

55
@Repository
6-
public interface Concrete extends IdOperations<Book> {
6+
public interface Concrete extends IdOperations<Thing> {
77
}

tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/basic/DataTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*/
2020
public class DataTest extends CompilationTest {
2121
@Test
22-
@WithClasses({ Author.class, Book.class, BookAuthorRepository.class, IdOperations.class, Concrete.class })
22+
@WithClasses({ Author.class, Book.class, BookAuthorRepository.class, IdOperations.class, Concrete.class, Thing.class })
2323
public void test() {
2424
System.out.println( getMetaModelSourceAsString( Author.class ) );
2525
System.out.println( getMetaModelSourceAsString( Book.class ) );

tooling/metamodel-generator/src/jakartaData/java/org/hibernate/processor/test/data/basic/IdOperations.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@
2323
import jakarta.data.Sort;
2424
import jakarta.data.repository.Query;
2525

26-
/**
27-
* This interface contains common operations for the NaturalNumbers and AsciiCharacters repositories.
28-
*
29-
* @param <T> type of entity.
30-
*/
3126
public interface IdOperations<T> {
3227
@Query("where id(this) between ?1 and ?2")
3328
Stream<T> findByIdBetween(long minimum, long maximum, Sort<T> sort);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.hibernate.processor.test.data.basic;
2+
3+
import jakarta.persistence.Entity;
4+
import jakarta.persistence.Id;
5+
6+
@Entity
7+
public class Thing {
8+
@Id long id;
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.hibernate.processor.test.data.versioned;
2+
3+
import jakarta.persistence.Entity;
4+
5+
@Entity
6+
public class SpecialVersioned extends Versioned {
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.hibernate.processor.test.data.versioned;
2+
3+
import jakarta.data.repository.Query;
4+
import jakarta.data.repository.Repository;
5+
6+
@Repository
7+
public interface SpecialVersionedRepo {
8+
@Query("where id(this) = ?1")
9+
SpecialVersioned forId(long id);
10+
11+
@Query("where id(this) = ?1 and version(this) = ?2")
12+
SpecialVersioned forIdAndVersion(long id, int version);
13+
14+
@Query("select count(this) from SpecialVersioned")
15+
long count();
16+
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.hibernate.processor.test.data.versioned;
2+
3+
import jakarta.persistence.Entity;
4+
import jakarta.persistence.Id;
5+
import jakarta.persistence.Version;
6+
7+
@Entity
8+
public class Versioned {
9+
@Id long id;
10+
@Version int version;
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.hibernate.processor.test.data.versioned;
2+
3+
import jakarta.data.repository.Query;
4+
import jakarta.data.repository.Repository;
5+
6+
@Repository
7+
public interface VersionedRepo {
8+
@Query("where id(this) = ?1")
9+
Versioned forId(long id);
10+
11+
@Query("where id(this) = ?1 and version(this) = ?2")
12+
Versioned forIdAndVersion(long id, int version);
13+
14+
@Query("select count(this) from Versioned")
15+
long count();
16+
17+
}

0 commit comments

Comments
 (0)