HHH-15960 make @Comment annotation repeatable and properly test it
I didn't quite nail this one first time round :-/
This commit is contained in:
parent
98957c3509
commit
e3f1c2741d
|
@ -9,16 +9,12 @@ package org.hibernate.userguide.pc;
|
|||
import java.util.List;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.NoResultException;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.SecondaryTable;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.Filter;
|
||||
import org.hibernate.annotations.FilterDef;
|
||||
import org.hibernate.annotations.ParamDef;
|
||||
|
@ -92,9 +88,11 @@ public class FilterSqlFragementAliasTest extends BaseEntityManagerFunctionalTest
|
|||
//tag::pc-filter-sql-fragment-alias-example[]
|
||||
@Entity(name = "Account")
|
||||
@Table(name = "account")
|
||||
@Comment(on="account", value = "The account table")
|
||||
@SecondaryTable(
|
||||
name = "account_details"
|
||||
)
|
||||
@Comment(on="account_details", value = "The account details secondary table")
|
||||
@SQLDelete(
|
||||
sql = "UPDATE account_details SET deleted = true WHERE id = ? "
|
||||
)
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.annotations;
|
|||
|
||||
import org.hibernate.binder.internal.CommentBinder;
|
||||
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
@ -51,6 +52,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
@AttributeBinderType(binder = CommentBinder.class)
|
||||
@Target({METHOD, FIELD, TYPE})
|
||||
@Retention(RUNTIME)
|
||||
@Repeatable(Comments.class)
|
||||
public @interface Comment {
|
||||
/**
|
||||
* The text of the comment.
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.annotations;
|
||||
|
||||
import org.hibernate.binder.internal.CommentBinder;
|
||||
import org.hibernate.binder.internal.CommentsBinder;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* A list of {@link Comment}s.
|
||||
* <p>
|
||||
* If there are multiple {@link Comment}s on a class or attribute,
|
||||
* they must have distinct {@link Comment#on() on} members.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
@TypeBinderType(binder = CommentsBinder.class)
|
||||
@AttributeBinderType(binder = CommentsBinder.class)
|
||||
@Target({METHOD, FIELD, TYPE})
|
||||
@Retention(RUNTIME)
|
||||
public @interface Comments {
|
||||
Comment[] value();
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.binder.internal;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.Comments;
|
||||
import org.hibernate.binder.AttributeBinder;
|
||||
import org.hibernate.binder.TypeBinder;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Handles the {@link Comments} annotation.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class CommentsBinder implements TypeBinder<Comments>, AttributeBinder<Comments> {
|
||||
@Override
|
||||
public void bind(Comments comments, MetadataBuildingContext context, PersistentClass entity, Property property) {
|
||||
final CommentBinder commentBinder = new CommentBinder();
|
||||
final Set<String> ons = new HashSet<>( comments.value().length );
|
||||
for ( Comment comment : comments.value() ) {
|
||||
if ( !ons.add( comment.on() ) ) {
|
||||
throw new AnnotationException( "Multiple '@Comment' annotations of '"
|
||||
+ property.getName() + "' had the same 'on'" );
|
||||
}
|
||||
commentBinder.bind( comment, context, entity, property );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(Comments comments, MetadataBuildingContext context, PersistentClass entity) {
|
||||
final CommentBinder commentBinder = new CommentBinder();
|
||||
final Set<String> ons = new HashSet<>( comments.value().length );
|
||||
for ( Comment comment : comments.value() ) {
|
||||
if ( !ons.add( comment.on() ) ) {
|
||||
throw new AnnotationException( "Multiple '@Comment' annotations of entity '"
|
||||
+ entity.getEntityName() + "' had the same 'on'" );
|
||||
}
|
||||
commentBinder.bind( comment, context, entity );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(Comments comments, MetadataBuildingContext context, Component embeddable) {
|
||||
throw new AnnotationException( "Embeddable class '" + embeddable.getComponentClassName()
|
||||
+ "' was annotated '@Comment' (annotate its attributes instead)" );
|
||||
}
|
||||
}
|
|
@ -2035,7 +2035,7 @@ public class EntityBinder {
|
|||
QualifiedTableName logicalName,
|
||||
Table table) {
|
||||
final Join join = new Join();
|
||||
join.setPersistentClass( persistentClass );
|
||||
persistentClass.addJoin( join );
|
||||
|
||||
final InFlightMetadataCollector.EntityTableXref tableXref
|
||||
= context.getMetadataCollector().getEntityTableXref( persistentClass.getEntityName() );
|
||||
|
|
|
@ -803,7 +803,9 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
|
|||
}
|
||||
|
||||
public void addJoin(Join join) {
|
||||
joins.add( join );
|
||||
if ( !joins.contains(join) ) {
|
||||
joins.add( join );
|
||||
}
|
||||
join.setPersistentClass( this );
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* 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.orm.test.annotations.comment;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.SecondaryTable;
|
||||
import jakarta.persistence.Table;
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.junit.BaseUnitTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Currency;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
|
||||
/**
|
||||
* @author Yanming Zhou
|
||||
*/
|
||||
@BaseUnitTest
|
||||
public class CommentsTest {
|
||||
|
||||
private static final String TABLE_NAME = "TestEntity";
|
||||
private static final String SEC_TABLE_NAME = "TestEntity2";
|
||||
private static final String TABLE_COMMENT = "I am a table";
|
||||
private static final String SEC_TABLE_COMMENT = "I am a table too";
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-4369")
|
||||
public void testComments() {
|
||||
StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build();
|
||||
Metadata metadata = new MetadataSources(ssr).addAnnotatedClass(TestEntity.class).buildMetadata();
|
||||
org.hibernate.mapping.Table table = StreamSupport.stream(metadata.getDatabase().getNamespaces().spliterator(), false)
|
||||
.flatMap(namespace -> namespace.getTables().stream()).filter(t -> t.getName().equals(TABLE_NAME))
|
||||
.findFirst().orElse(null);
|
||||
assertThat(table.getComment(), is(TABLE_COMMENT));
|
||||
assertThat(table.getColumns().size(), is(6));
|
||||
for (org.hibernate.mapping.Column col : table.getColumns()) {
|
||||
assertThat(col.getComment(), is("I am " + col.getName()));
|
||||
}
|
||||
table = StreamSupport.stream(metadata.getDatabase().getNamespaces().spliterator(), false)
|
||||
.flatMap(namespace -> namespace.getTables().stream()).filter(t -> t.getName().equals(SEC_TABLE_NAME))
|
||||
.findFirst().orElse(null);
|
||||
assertThat(table.getComment(), is(SEC_TABLE_COMMENT));
|
||||
assertThat(table.getColumns().size(), is(2));
|
||||
long count = table.getColumns().stream().filter(col -> "This is a date".equalsIgnoreCase(col.getComment())).count();
|
||||
assertThat(count, is(1L));
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
@Table(name = TABLE_NAME)
|
||||
@SecondaryTable(name = SEC_TABLE_NAME)
|
||||
@Comment(TABLE_COMMENT)
|
||||
@Comment(value = SEC_TABLE_COMMENT, on = SEC_TABLE_NAME)
|
||||
public static class TestEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@Comment("I am id")
|
||||
private Long id;
|
||||
|
||||
@Comment(on = "firstName", value = "I am firstName")
|
||||
@Comment(on = "lastName", value = "I am lastName")
|
||||
private Name name;
|
||||
|
||||
private Money money;
|
||||
|
||||
@Column(table = SEC_TABLE_NAME)
|
||||
@Comment("This is a date")
|
||||
private LocalDate localDate;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "other")
|
||||
@Comment("I am other")
|
||||
private TestEntity other;
|
||||
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class Name {
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class Money {
|
||||
@Comment("I am amount")
|
||||
private BigDecimal amount;
|
||||
@Comment("I am currency")
|
||||
private Currency currency;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue