HHH-17851 fix three bugs in Jakarta Data impl
- overloaded lifecycle methods - handling of delimited compound names - some missing imports
This commit is contained in:
parent
f898de7e98
commit
3e8b1b37be
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.annotations;
|
||||
|
||||
import org.hibernate.Remove;
|
||||
import org.hibernate.binder.internal.CommentBinder;
|
||||
import org.hibernate.binder.internal.CommentsBinder;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
|
|
@ -42,12 +42,12 @@ public class QualifiedNameParser {
|
|||
|
||||
StringBuilder buff = new StringBuilder();
|
||||
if ( catalogName != null ) {
|
||||
buff.append( catalogName.toString() ).append( '.' );
|
||||
buff.append( catalogName ).append( '.' );
|
||||
}
|
||||
if ( schemaName != null ) {
|
||||
buff.append( schemaName.toString() ).append( '.' );
|
||||
buff.append( schemaName ).append( '.' );
|
||||
}
|
||||
buff.append( objectName.toString() );
|
||||
buff.append( objectName );
|
||||
qualifiedText = buff.toString();
|
||||
}
|
||||
|
||||
|
@ -89,8 +89,8 @@ public class QualifiedNameParser {
|
|||
NameParts that = (NameParts) o;
|
||||
|
||||
return Objects.equals( this.getCatalogName(), that.getCatalogName() )
|
||||
&& Objects.equals( this.getSchemaName(), that.getSchemaName() )
|
||||
&& Objects.equals( this.getObjectName(), that.getObjectName() );
|
||||
&& Objects.equals( this.getSchemaName(), that.getSchemaName() )
|
||||
&& Objects.equals( this.getObjectName(), that.getObjectName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package org.hibernate.processor.test.data.eg;
|
||||
|
||||
import jakarta.persistence.Embeddable;
|
||||
|
||||
@Embeddable
|
||||
public record Address(String street, String city, String postcode) {}
|
|
@ -0,0 +1,23 @@
|
|||
package org.hibernate.processor.test.data.eg;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
public class Author {
|
||||
@Id
|
||||
String ssn;
|
||||
|
||||
@Basic(optional = false)
|
||||
String name;
|
||||
|
||||
Address address;
|
||||
|
||||
@ManyToMany
|
||||
Set<Book> books;
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package org.hibernate.processor.test.data.eg;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
public class Book {
|
||||
@Id
|
||||
String isbn;
|
||||
|
||||
@NaturalId
|
||||
String title;
|
||||
|
||||
@NaturalId
|
||||
LocalDate publicationDate;
|
||||
|
||||
String text;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Basic(optional = false)
|
||||
Type type = Type.Book;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
Publisher publisher;
|
||||
|
||||
@ManyToMany(mappedBy = "books")
|
||||
Set<Author> authors;
|
||||
|
||||
@Basic(optional = false)
|
||||
int pages ;
|
||||
|
||||
BigDecimal price;
|
||||
BigInteger quantitySold;
|
||||
|
||||
public Book(String isbn, String title, String text) {
|
||||
this.isbn = isbn;
|
||||
this.title = title;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
protected Book() {}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return isbn + " : " + title + " [" + type + "]";
|
||||
}
|
||||
}
|
||||
|
|
@ -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.eg;
|
||||
|
||||
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.getMetaModelSourceAsString;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class EgTest extends CompilationTest {
|
||||
@Test
|
||||
@WithClasses({ Publisher.class, Author.class, Book.class, Library.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( Library.class ) );
|
||||
assertMetamodelClassGeneratedFor( Author.class, true );
|
||||
assertMetamodelClassGeneratedFor( Book.class, true );
|
||||
assertMetamodelClassGeneratedFor( Publisher.class, true );
|
||||
assertMetamodelClassGeneratedFor( Author.class );
|
||||
assertMetamodelClassGeneratedFor( Book.class );
|
||||
assertMetamodelClassGeneratedFor( Publisher.class );
|
||||
assertMetamodelClassGeneratedFor( Library.class );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package org.hibernate.processor.test.data.eg;
|
||||
|
||||
import jakarta.data.page.CursoredPage;
|
||||
import jakarta.data.page.PageRequest;
|
||||
import jakarta.data.repository.Delete;
|
||||
import jakarta.data.repository.Find;
|
||||
import jakarta.data.repository.Insert;
|
||||
import jakarta.data.repository.OrderBy;
|
||||
import jakarta.data.repository.Query;
|
||||
import jakarta.data.repository.Repository;
|
||||
import jakarta.data.repository.Save;
|
||||
import jakarta.data.repository.Update;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface Library {
|
||||
|
||||
@Find
|
||||
Book book(String isbn);
|
||||
|
||||
@Find
|
||||
Book books(String title, LocalDate publicationDate);
|
||||
|
||||
@Find
|
||||
@OrderBy("title")
|
||||
List<Book> booksByPublisher(String publisher_name);
|
||||
|
||||
@Query("where title like :titlePattern")
|
||||
List<Book> booksByTitle(String titlePattern);
|
||||
|
||||
// not required by Jakarta Data
|
||||
record BookWithAuthor(Book book, Author author) {}
|
||||
@Query("select b, a from Book b join b.authors a")
|
||||
List<BookWithAuthor> booksWithAuthors();
|
||||
|
||||
@Insert
|
||||
void create(Book book);
|
||||
|
||||
@Update
|
||||
void update(Book book);
|
||||
|
||||
@Delete
|
||||
void delete(Book book);
|
||||
|
||||
@Update
|
||||
void update(Book[] books);
|
||||
|
||||
@Save
|
||||
void upsert(Book book);
|
||||
|
||||
@Find
|
||||
Author author(String ssn);
|
||||
|
||||
@Insert
|
||||
void create(Author author);
|
||||
|
||||
@Update
|
||||
void update(Author author);
|
||||
|
||||
@Find
|
||||
@OrderBy("isbn")
|
||||
CursoredPage<Book> allBooks(PageRequest<Book> pageRequest);
|
||||
|
||||
@Find
|
||||
@OrderBy("name")
|
||||
@OrderBy("address.city") //not working currently
|
||||
List<Author> authors();
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package org.hibernate.processor.test.data.eg;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
public class Publisher {
|
||||
@Id long id;
|
||||
|
||||
@Basic(optional = false)
|
||||
String name;
|
||||
|
||||
@OneToMany(mappedBy = "publisher")
|
||||
Set<Book> books;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package org.hibernate.processor.test.data.eg;
|
||||
|
||||
public enum Type { Book, Magazine, Journal }
|
|
@ -111,8 +111,7 @@ public abstract class AbstractFinderMethod extends AbstractQueryMethod {
|
|||
}
|
||||
}
|
||||
count++;
|
||||
final String path = paramNames.get(i)
|
||||
.replace('$', '.');
|
||||
final String path = paramNames.get(i);
|
||||
declaration
|
||||
.append("{@link ")
|
||||
.append(annotationMetaEntity.importType(entity))
|
||||
|
@ -141,7 +140,7 @@ public abstract class AbstractFinderMethod extends AbstractQueryMethod {
|
|||
}
|
||||
|
||||
String qualifier(String name) {
|
||||
final int index = name.indexOf('$');
|
||||
final int index = name.indexOf('.');
|
||||
return index > 0 ? name.substring(0, index) : name;
|
||||
}
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ public abstract class AbstractQueryMethod implements MetaAttribute {
|
|||
declaration
|
||||
.append(annotationMetaEntity.importType(importReturnTypeArgument(paramType)))
|
||||
.append(" ")
|
||||
.append(paramNames.get(i));
|
||||
.append(paramNames.get(i).replace('.', '$'));
|
||||
}
|
||||
declaration
|
||||
.append(")");
|
||||
|
@ -363,10 +363,10 @@ public abstract class AbstractQueryMethod implements MetaAttribute {
|
|||
}
|
||||
|
||||
void makeKeyedPage(StringBuilder declaration, List<String> paramTypes) {
|
||||
annotationMetaEntity.staticImport("org.hibernate.query.SortDirection", "*");
|
||||
annotationMetaEntity.staticImport(HIB_SORT_DIRECTION, "*");
|
||||
annotationMetaEntity.staticImport(HIB_ORDER, "by");
|
||||
annotationMetaEntity.staticImport(HIB_PAGE, "page");
|
||||
annotationMetaEntity.staticImport("org.hibernate.query.KeyedPage.KeyInterpretation", "*");
|
||||
annotationMetaEntity.staticImport("org.hibernate.query.Order", "by");
|
||||
annotationMetaEntity.staticImport("org.hibernate.query.Page", "page");
|
||||
annotationMetaEntity.staticImport(Collectors.class.getName(), "toList");
|
||||
if ( returnTypeName == null ) {
|
||||
throw new AssertionFailure("entity class cannot be null");
|
||||
|
@ -489,6 +489,7 @@ public abstract class AbstractQueryMethod implements MetaAttribute {
|
|||
.append(">>();\n");
|
||||
// static orders declared using @OrderBy must come first
|
||||
for ( OrderBy orderBy : orderBys ) {
|
||||
annotationMetaEntity.staticImport(HIB_SORT_DIRECTION, "*");
|
||||
declaration
|
||||
.append("\t_orders.add(")
|
||||
.append(annotationMetaEntity.staticImport(HIB_ORDER, "by"))
|
||||
|
@ -528,7 +529,7 @@ public abstract class AbstractQueryMethod implements MetaAttribute {
|
|||
}
|
||||
else if ( type.startsWith(JD_ORDER)
|
||||
|| type.startsWith(JD_PAGE_REQUEST) ) {
|
||||
annotationMetaEntity.staticImport("org.hibernate.query.SortDirection", "*");
|
||||
annotationMetaEntity.staticImport(HIB_SORT_DIRECTION, "*");
|
||||
declaration
|
||||
.append("\tfor (var _sort : ")
|
||||
.append(name)
|
||||
|
@ -546,7 +547,7 @@ public abstract class AbstractQueryMethod implements MetaAttribute {
|
|||
}
|
||||
else if ( type.startsWith(JD_SORT) && type.endsWith("...") ) {
|
||||
// almost identical
|
||||
annotationMetaEntity.staticImport("org.hibernate.query.SortDirection", "*");
|
||||
annotationMetaEntity.staticImport(HIB_SORT_DIRECTION, "*");
|
||||
declaration
|
||||
.append("\tfor (var _sort : ")
|
||||
.append(name)
|
||||
|
@ -563,7 +564,7 @@ public abstract class AbstractQueryMethod implements MetaAttribute {
|
|||
.append("\t}\n");
|
||||
}
|
||||
else if ( type.startsWith(JD_SORT) ) {
|
||||
annotationMetaEntity.staticImport("org.hibernate.query.SortDirection", "*");
|
||||
annotationMetaEntity.staticImport(HIB_SORT_DIRECTION, "*");
|
||||
declaration
|
||||
.append("\t_orders.add(")
|
||||
.append(annotationMetaEntity.staticImport(HIB_ORDER, "by"))
|
||||
|
|
|
@ -851,13 +851,14 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
Diagnostic.Kind.ERROR );
|
||||
}
|
||||
else {
|
||||
final String entity = parameterType.toString();
|
||||
final String methodName = method.getSimpleName().toString();
|
||||
putMember(
|
||||
method.getSimpleName().toString()
|
||||
+ '.' + operation,
|
||||
methodName + '.' + entity,
|
||||
new LifecycleMethod(
|
||||
this,
|
||||
parameterType.toString(),
|
||||
method.getSimpleName().toString(),
|
||||
entity,
|
||||
methodName,
|
||||
parameter.getSimpleName().toString(),
|
||||
getSessionVariableName(),
|
||||
operation,
|
||||
|
@ -1099,13 +1100,16 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
final Boolean ignoreCaseOrNull = (Boolean) getAnnotationValue(orderBy, "ignoreCase");
|
||||
final boolean descending = descendingOrNull != null && descendingOrNull;
|
||||
final boolean ignoreCase = ignoreCaseOrNull != null && ignoreCaseOrNull;
|
||||
if ( memberMatchingPath( entityType, fieldName ) == null ) {
|
||||
final String path = fieldName
|
||||
.replace('$', '.')
|
||||
.replace('_', '.'); //Jakarta Data allows _ here
|
||||
if ( memberMatchingPath( entityType, path ) == null ) {
|
||||
context.message( method, orderBy,
|
||||
"no matching field named '" + fieldName
|
||||
+ "' in entity class '" + entityType.getQualifiedName() + "'",
|
||||
Diagnostic.Kind.ERROR );
|
||||
}
|
||||
return new OrderBy( fieldName, descending, ignoreCase );
|
||||
return new OrderBy( path, descending, ignoreCase );
|
||||
}
|
||||
|
||||
private static @Nullable TypeMirror getTypeArgument(TypeMirror parameterType) {
|
||||
|
@ -1406,8 +1410,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
}
|
||||
|
||||
context.message( param,
|
||||
"no matching field named '"
|
||||
+ parameterName( param ).replace('$', '.')
|
||||
"no matching field named '" + parameterName( param )
|
||||
+ "' in entity class '" + entityType + "'",
|
||||
Diagnostic.Kind.ERROR );
|
||||
return null;
|
||||
|
@ -1435,7 +1438,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
}
|
||||
|
||||
private @Nullable Element memberMatchingPath(TypeElement entityType, String path) {
|
||||
final StringTokenizer tokens = new StringTokenizer( path, "$" );
|
||||
final StringTokenizer tokens = new StringTokenizer( path, "." );
|
||||
return memberMatchingPath( entityType, tokens );
|
||||
}
|
||||
|
||||
|
@ -1947,7 +1950,9 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
if ( name.contains("<error>") ) {
|
||||
throw new ProcessLaterException();
|
||||
}
|
||||
return name.replace('.', '$'); // since the rest of the code assumes $ as the path separator
|
||||
return name
|
||||
.replace('$', '.')
|
||||
.replace('_', '.');
|
||||
}
|
||||
else if ( param != null ) {
|
||||
final String name = (String) castNonNull(getAnnotationValue(param, "value"));
|
||||
|
@ -1957,7 +1962,9 @@ public class AnnotationMetaEntity extends AnnotationMeta {
|
|||
return name;
|
||||
}
|
||||
else {
|
||||
return parameter.getSimpleName().toString();
|
||||
return parameter.getSimpleName().toString()
|
||||
.replace('$', '.')
|
||||
.replace('_', '.');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
|
|||
private static void nullCheck(StringBuilder declaration, String paramName) {
|
||||
declaration
|
||||
.append("\tif (")
|
||||
.append(paramName)
|
||||
.append(paramName.replace('.', '$'))
|
||||
.append(" == null) throw new IllegalArgumentException(\"Null ")
|
||||
.append(paramName)
|
||||
.append("\");\n");
|
||||
|
@ -174,9 +174,10 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
|
|||
private void parameter(StringBuilder declaration, int i, String paramName, String paramType) {
|
||||
declaration
|
||||
.append("\n\t\t\t");
|
||||
final String parameterName = paramName.replace('.', '$');
|
||||
if ( isNullable(i) && !isPrimitive(paramType) ) {
|
||||
declaration
|
||||
.append(paramName)
|
||||
.append(parameterName)
|
||||
.append("==null")
|
||||
.append("\n\t\t\t\t? ")
|
||||
.append("_entity");
|
||||
|
@ -191,12 +192,12 @@ public class CriteriaFinderMethod extends AbstractFinderMethod {
|
|||
declaration
|
||||
.append(", ")
|
||||
//TODO: only safe if we are binding literals as parameters!!!
|
||||
.append(paramName)
|
||||
.append(parameterName)
|
||||
.append(')');
|
||||
}
|
||||
|
||||
private void path(StringBuilder declaration, String paramName) {
|
||||
final StringTokenizer tokens = new StringTokenizer(paramName, "$");
|
||||
final StringTokenizer tokens = new StringTokenizer(paramName, ".");
|
||||
String typeName = entity;
|
||||
while ( typeName!= null && tokens.hasMoreTokens() ) {
|
||||
final String memberName = tokens.nextToken();
|
||||
|
|
|
@ -79,6 +79,7 @@ public final class Constants {
|
|||
public static final String HIB_PAGE = "org.hibernate.query.Page";
|
||||
public static final String HIB_KEYED_PAGE = "org.hibernate.query.KeyedPage";
|
||||
public static final String HIB_KEYED_RESULT_LIST = "org.hibernate.query.KeyedResultList";
|
||||
public static final String HIB_SORT_DIRECTION = "org.hibernate.query.SortDirection";
|
||||
|
||||
public static final String CHECK_HQL = "org.hibernate.annotations.processing.CheckHQL";
|
||||
|
||||
|
|
Loading…
Reference in New Issue