support for queries defined in intermediate classes
for our work on the Jakarta Data TCK Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
e21d139a84
commit
f51d8dbe0d
|
@ -0,0 +1,21 @@
|
|||
package org.hibernate.processor.test.data.namedquery;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
public class Author {
|
||||
@Id
|
||||
String ssn;
|
||||
String name;
|
||||
|
||||
// @Embedded
|
||||
// Address address;
|
||||
|
||||
@ManyToMany
|
||||
Set<Book> books;
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package org.hibernate.processor.test.data.namedquery;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
@Table(name = "books")
|
||||
public class Book {
|
||||
@Id
|
||||
String isbn;
|
||||
|
||||
@NaturalId
|
||||
@Basic(optional = false)
|
||||
String title;
|
||||
|
||||
@Basic(optional = false)
|
||||
String text;
|
||||
|
||||
@NaturalId
|
||||
LocalDate publicationDate;
|
||||
|
||||
@ManyToMany(mappedBy = "books")
|
||||
Set<Author> authors;
|
||||
|
||||
BigDecimal price;
|
||||
|
||||
int pages;
|
||||
|
||||
public Book(String isbn, String title, String text) {
|
||||
this.isbn = isbn;
|
||||
this.title = title;
|
||||
this.text = text;
|
||||
}
|
||||
Book() {}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package org.hibernate.processor.test.data.namedquery;
|
||||
|
||||
import jakarta.data.repository.Query;
|
||||
import jakarta.data.repository.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository(dataStore = "myds")
|
||||
public interface BookAuthorRepository$ extends BookAuthorRepository {
|
||||
@Override
|
||||
@Query("from Book where title like :title")
|
||||
List<Book> findByTitleLike(String title);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package org.hibernate.processor.test.data.namedquery;
|
||||
|
||||
import jakarta.data.Limit;
|
||||
import jakarta.data.Order;
|
||||
import jakarta.data.Sort;
|
||||
import jakarta.data.page.CursoredPage;
|
||||
import jakarta.data.page.Page;
|
||||
import jakarta.data.page.PageRequest;
|
||||
import jakarta.data.repository.By;
|
||||
import jakarta.data.repository.Delete;
|
||||
import jakarta.data.repository.Find;
|
||||
import jakarta.data.repository.Insert;
|
||||
import jakarta.data.repository.OrderBy;
|
||||
import jakarta.data.repository.Param;
|
||||
import jakarta.data.repository.Query;
|
||||
import jakarta.data.repository.Repository;
|
||||
import jakarta.data.repository.Save;
|
||||
import jakarta.data.repository.Update;
|
||||
import org.hibernate.StatelessSession;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Repository(dataStore = "myds")
|
||||
public interface BookAuthorRepository {
|
||||
List<Book> findByTitleLike(String title);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.processor.test.data.namedquery;
|
||||
|
||||
import org.hibernate.processor.test.util.CompilationTest;
|
||||
import org.hibernate.processor.test.util.WithClasses;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.processor.test.util.TestUtil.assertMetamodelClassGeneratedFor;
|
||||
import static org.hibernate.processor.test.util.TestUtil.assertNoMetamodelClassGeneratedFor;
|
||||
import static org.hibernate.processor.test.util.TestUtil.getMetaModelSourceAsString;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class NamedQueryTest extends CompilationTest {
|
||||
@Test
|
||||
@WithClasses({ Author.class, Book.class, BookAuthorRepository.class, BookAuthorRepository$.class })
|
||||
public void test() {
|
||||
System.out.println( getMetaModelSourceAsString( Author.class ) );
|
||||
System.out.println( getMetaModelSourceAsString( Book.class ) );
|
||||
System.out.println( getMetaModelSourceAsString( Author.class, true ) );
|
||||
System.out.println( getMetaModelSourceAsString( Book.class, true ) );
|
||||
System.out.println( getMetaModelSourceAsString( BookAuthorRepository.class ) );
|
||||
assertMetamodelClassGeneratedFor( Author.class, true );
|
||||
assertMetamodelClassGeneratedFor( Book.class, true );
|
||||
assertMetamodelClassGeneratedFor( Author.class );
|
||||
assertMetamodelClassGeneratedFor( Book.class );
|
||||
assertMetamodelClassGeneratedFor( BookAuthorRepository.class );
|
||||
assertNoMetamodelClassGeneratedFor( BookAuthorRepository$.class );
|
||||
}
|
||||
}
|
|
@ -314,8 +314,11 @@ public class HibernateProcessor extends AbstractProcessor {
|
|||
context.logMessage( Diagnostic.Kind.OTHER, "Processing repository class '" + element + "'" );
|
||||
final AnnotationMetaEntity metaEntity =
|
||||
AnnotationMetaEntity.create( typeElement, context );
|
||||
if ( metaEntity.isInitialized() ) {
|
||||
context.addMetaAuxiliary( metaEntity.getQualifiedName(), metaEntity );
|
||||
}
|
||||
// otherwise discard it (assume it has query by magical method name stuff)
|
||||
}
|
||||
}
|
||||
else {
|
||||
for ( Element member : typeElement.getEnclosedElements() ) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.antlr.v4.runtime.Token;
|
|||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.grammars.hql.HqlLexer;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.processor.Context;
|
||||
import org.hibernate.processor.ImportContextImpl;
|
||||
import org.hibernate.processor.ProcessLaterException;
|
||||
|
@ -21,7 +22,6 @@ import org.hibernate.processor.util.AccessTypeInformation;
|
|||
import org.hibernate.processor.util.Constants;
|
||||
import org.hibernate.processor.validation.ProcessorSessionFactory;
|
||||
import org.hibernate.processor.validation.Validation;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.query.criteria.JpaEntityJoin;
|
||||
import org.hibernate.query.criteria.JpaRoot;
|
||||
import org.hibernate.query.criteria.JpaSelection;
|
||||
|
@ -212,9 +212,29 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
return jakartaDataStaticModel;
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSimpleName() {
|
||||
return element.getSimpleName().toString();
|
||||
return removeDollar( element.getSimpleName().toString() );
|
||||
}
|
||||
|
||||
private String getConstructorName() {
|
||||
return getSimpleName() + '_';
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is an "intermediate" class providing {@code @Query}
|
||||
* annotations for the query by magical method name crap, then
|
||||
* by convention it will be named with a trailing $ sign. Strip
|
||||
* that off, so we get the standard constructor.
|
||||
*/
|
||||
private static String removeDollar(String simpleName) {
|
||||
return simpleName.endsWith("$")
|
||||
? simpleName.substring(0, simpleName.length()-1)
|
||||
: simpleName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -376,6 +396,16 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
queryMethods.add( method );
|
||||
}
|
||||
}
|
||||
else if ( !isSessionGetter(method)
|
||||
&& !method.getModifiers().contains(Modifier.DEFAULT) ) {
|
||||
final String companionClassName = element.getQualifiedName().toString() + '$';
|
||||
if ( context.getElementUtils().getTypeElement(companionClassName) == null ) {
|
||||
message( method, "repository method cannot be implemented",
|
||||
Diagnostic.Kind.ERROR );
|
||||
}
|
||||
// NOTE EARLY EXIT with initialized = false
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
primaryEntity = primaryEntity( lifecycleMethods );
|
||||
|
@ -483,10 +513,9 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
|
||||
private void addDefaultConstructor() {
|
||||
final String sessionVariableName = getSessionVariableName(sessionType);
|
||||
final String typeName = element.getSimpleName().toString() + '_';
|
||||
putMember("_", new DefaultConstructor(
|
||||
this,
|
||||
typeName,
|
||||
getConstructorName(),
|
||||
sessionVariableName,
|
||||
sessionType,
|
||||
sessionVariableName,
|
||||
|
@ -633,13 +662,12 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
final String sessionType = method == null ? this.sessionType : method.getReturnType().toString();
|
||||
final String sessionVariableName = getSessionVariableName( sessionType );
|
||||
final String name = method == null ? sessionVariableName : method.getSimpleName().toString();
|
||||
final String typeName = element.getSimpleName().toString() + '_';
|
||||
|
||||
if ( method == null || !method.isDefault() ) {
|
||||
putMember( name,
|
||||
new RepositoryConstructor(
|
||||
this,
|
||||
typeName,
|
||||
getConstructorName(),
|
||||
name,
|
||||
sessionType,
|
||||
sessionVariableName,
|
||||
|
@ -664,18 +692,15 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
* and in HR, we define the static session getter.
|
||||
*/
|
||||
private String setupQuarkusDaoConstructor() {
|
||||
final String typeName = element.getSimpleName().toString() + '_';
|
||||
final String sessionVariableName = getSessionVariableName( sessionType );
|
||||
|
||||
if ( context.usesQuarkusOrm() ) {
|
||||
String name = "getEntityManager";
|
||||
putMember( name,
|
||||
new RepositoryConstructor(
|
||||
this,
|
||||
typeName,
|
||||
getConstructorName(),
|
||||
name,
|
||||
sessionType,
|
||||
sessionVariableName,
|
||||
getSessionVariableName( sessionType ),
|
||||
dataStore(),
|
||||
context.addInjectAnnotation(),
|
||||
context.addNonnullAnnotation(),
|
||||
|
@ -2093,13 +2118,6 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
@Nullable TypeElement containerType,
|
||||
AnnotationMirror mirror,
|
||||
boolean isNative) {
|
||||
|
||||
final AnnotationValue value = getAnnotationValue( mirror, "value" );
|
||||
if ( value != null ) {
|
||||
final Object query = value.getValue();
|
||||
if ( query instanceof String ) {
|
||||
final String queryString = (String) query;
|
||||
|
||||
// The following is quite fragile!
|
||||
final String containerTypeName;
|
||||
if ( containerType == null ) {
|
||||
|
@ -2124,6 +2142,24 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
containerTypeName = containerType.getQualifiedName().toString();
|
||||
}
|
||||
|
||||
final AnnotationValue value = getAnnotationValue( mirror, "value" );
|
||||
if ( value != null ) {
|
||||
final Object queryString = value.getValue();
|
||||
if ( queryString instanceof String ) {
|
||||
addQueryMethod(method, returnType, containerTypeName, mirror, isNative, value, (String) queryString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addQueryMethod(
|
||||
ExecutableElement method,
|
||||
@Nullable TypeMirror returnType,
|
||||
@Nullable String containerTypeName,
|
||||
AnnotationMirror mirror,
|
||||
boolean isNative,
|
||||
AnnotationValue value,
|
||||
String queryString) {
|
||||
|
||||
final List<String> paramNames = parameterNames(method);
|
||||
final List<String> paramTypes = parameterTypes(method);
|
||||
|
||||
|
@ -2132,7 +2168,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
|
||||
final String[] sessionType = sessionTypeFromParameters( paramNames, paramTypes );
|
||||
final DeclaredType resultType = resultType(method, returnType, mirror, value);
|
||||
final List<OrderBy> orderBys = resultType == null
|
||||
final List<OrderBy> orderBys =
|
||||
resultType == null
|
||||
? emptyList()
|
||||
: orderByList( method, (TypeElement) resultType.asElement() );
|
||||
|
||||
|
@ -2167,8 +2204,6 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
);
|
||||
putMember( attribute.getPropertyName() + paramTypes, attribute );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String returnTypeClass(TypeMirror returnType) {
|
||||
switch (returnType.getKind()) {
|
||||
|
|
Loading…
Reference in New Issue