HHH-4369 Introduce @Comment for comment on column

This commit is contained in:
Yanming Zhou 2020-10-23 15:08:36 +08:00 committed by Sanne Grinovero
parent 5ffed50f1f
commit 99f027166d
8 changed files with 159 additions and 2 deletions

View File

@ -0,0 +1,28 @@
/*
* 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 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.RetentionPolicy.RUNTIME;
/**
* SQL column comment which can be defined at property level.
*
* @author Yanming Zhou
*/
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface Comment {
/**
* The comment string.
*/
String value();
}

View File

@ -83,6 +83,7 @@ import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.Check; import org.hibernate.annotations.Check;
import org.hibernate.annotations.CollectionId; import org.hibernate.annotations.CollectionId;
import org.hibernate.annotations.Columns; import org.hibernate.annotations.Columns;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DiscriminatorFormula; import org.hibernate.annotations.DiscriminatorFormula;
import org.hibernate.annotations.DiscriminatorOptions; import org.hibernate.annotations.DiscriminatorOptions;
import org.hibernate.annotations.Fetch; import org.hibernate.annotations.Fetch;
@ -1998,6 +1999,7 @@ public final class AnnotationBinder {
elementColumns = Ejb3Column.buildColumnFromAnnotation( elementColumns = Ejb3Column.buildColumnFromAnnotation(
new Column[] { ann }, new Column[] { ann },
formulaAnn, formulaAnn,
property.getAnnotation( Comment.class ),
nullability, nullability,
propertyHolder, propertyHolder,
virtualProperty, virtualProperty,
@ -2010,6 +2012,7 @@ public final class AnnotationBinder {
elementColumns = Ejb3Column.buildColumnFromAnnotation( elementColumns = Ejb3Column.buildColumnFromAnnotation(
anns.columns(), anns.columns(),
null, null,
property.getAnnotation( Comment.class ),
nullability, nullability,
propertyHolder, propertyHolder,
virtualProperty, virtualProperty,
@ -2021,6 +2024,7 @@ public final class AnnotationBinder {
elementColumns = Ejb3Column.buildColumnFromAnnotation( elementColumns = Ejb3Column.buildColumnFromAnnotation(
null, null,
null, null,
property.getAnnotation( Comment.class ),
nullability, nullability,
propertyHolder, propertyHolder,
virtualProperty, virtualProperty,
@ -2050,6 +2054,7 @@ public final class AnnotationBinder {
Ejb3Column[] mapColumns = Ejb3Column.buildColumnFromAnnotation( Ejb3Column[] mapColumns = Ejb3Column.buildColumnFromAnnotation(
keyColumns, keyColumns,
null, null,
property.getAnnotation( Comment.class ),
Nullability.FORCED_NOT_NULL, Nullability.FORCED_NOT_NULL,
propertyHolder, propertyHolder,
isJPA2 ? inferredData : mapKeyVirtualProperty, isJPA2 ? inferredData : mapKeyVirtualProperty,
@ -2098,6 +2103,7 @@ public final class AnnotationBinder {
PropertyData mapKeyVirtualProperty = new WrappedInferredData( inferredData, "mapkey" ); PropertyData mapKeyVirtualProperty = new WrappedInferredData( inferredData, "mapkey" );
Ejb3JoinColumn[] mapJoinColumns = Ejb3JoinColumn.buildJoinColumnsWithDefaultColumnSuffix( Ejb3JoinColumn[] mapJoinColumns = Ejb3JoinColumn.buildJoinColumnsWithDefaultColumnSuffix(
joinKeyColumns, joinKeyColumns,
property.getAnnotation( Comment.class ),
null, null,
entityBinder.getSecondaryTables(), entityBinder.getSecondaryTables(),
propertyHolder, propertyHolder,

View File

@ -998,6 +998,7 @@ public class BinderHelper {
Ejb3Column[] metaColumns = Ejb3Column.buildColumnFromAnnotation( Ejb3Column[] metaColumns = Ejb3Column.buildColumnFromAnnotation(
new javax.persistence.Column[] { metaColumn }, new javax.persistence.Column[] { metaColumn },
null, null,
null,
nullability, nullability,
propertyHolder, propertyHolder,
inferredData, inferredData,

View File

@ -17,6 +17,7 @@ import javax.persistence.OneToOne;
import org.hibernate.AnnotationException; import org.hibernate.AnnotationException;
import org.hibernate.annotations.Columns; import org.hibernate.annotations.Columns;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.Formula; import org.hibernate.annotations.Formula;
import org.hibernate.annotations.JoinColumnOrFormula; import org.hibernate.annotations.JoinColumnOrFormula;
import org.hibernate.annotations.JoinColumnsOrFormulas; import org.hibernate.annotations.JoinColumnsOrFormulas;
@ -78,6 +79,7 @@ class ColumnsBuilder {
columns = Ejb3Column.buildColumnFromAnnotation( columns = Ejb3Column.buildColumnFromAnnotation(
new Column[] { ann }, new Column[] { ann },
formulaAnn, formulaAnn,
property.getAnnotation( Comment.class ),
nullability, nullability,
propertyHolder, propertyHolder,
inferredData, inferredData,
@ -90,6 +92,7 @@ class ColumnsBuilder {
columns = Ejb3Column.buildColumnFromAnnotation( columns = Ejb3Column.buildColumnFromAnnotation(
anns.columns(), anns.columns(),
null, null,
property.getAnnotation( Comment.class ),
nullability, nullability,
propertyHolder, propertyHolder,
inferredData, inferredData,
@ -115,6 +118,7 @@ class ColumnsBuilder {
""; "";
joinColumns = Ejb3JoinColumn.buildJoinColumns( joinColumns = Ejb3JoinColumn.buildJoinColumns(
null, null,
property.getAnnotation( Comment.class ),
mappedBy, mappedBy,
entityBinder.getSecondaryTables(), entityBinder.getSecondaryTables(),
propertyHolder, propertyHolder,
@ -131,6 +135,7 @@ class ColumnsBuilder {
columns = Ejb3Column.buildColumnFromAnnotation( columns = Ejb3Column.buildColumnFromAnnotation(
null, null,
null, null,
property.getAnnotation( Comment.class ),
nullability, nullability,
propertyHolder, propertyHolder,
inferredData, inferredData,
@ -154,6 +159,7 @@ class ColumnsBuilder {
if ( joinTableAnn != null ) { if ( joinTableAnn != null ) {
joinColumns = Ejb3JoinColumn.buildJoinColumns( joinColumns = Ejb3JoinColumn.buildJoinColumns(
joinTableAnn.inverseJoinColumns(), joinTableAnn.inverseJoinColumns(),
property.getAnnotation( Comment.class ),
null, null,
entityBinder.getSecondaryTables(), entityBinder.getSecondaryTables(),
propertyHolder, propertyHolder,
@ -174,6 +180,7 @@ class ColumnsBuilder {
: null; : null;
joinColumns = Ejb3JoinColumn.buildJoinColumns( joinColumns = Ejb3JoinColumn.buildJoinColumns(
null, null,
property.getAnnotation( Comment.class ),
mappedBy, mappedBy,
entityBinder.getSecondaryTables(), entityBinder.getSecondaryTables(),
propertyHolder, propertyHolder,
@ -203,6 +210,7 @@ class ColumnsBuilder {
if ( joinColumnAnnotations != null ) { if ( joinColumnAnnotations != null ) {
return Ejb3JoinColumn.buildJoinColumns( return Ejb3JoinColumn.buildJoinColumns(
joinColumnAnnotations, joinColumnAnnotations,
property.getAnnotation( Comment.class ),
null, null,
entityBinder.getSecondaryTables(), entityBinder.getSecondaryTables(),
propertyHolder, propertyHolder,

View File

@ -13,6 +13,7 @@ import org.hibernate.AssertionFailure;
import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.ColumnTransformer; import org.hibernate.annotations.ColumnTransformer;
import org.hibernate.annotations.ColumnTransformers; import org.hibernate.annotations.ColumnTransformers;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.Index; import org.hibernate.annotations.Index;
import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.Identifier;
@ -70,6 +71,8 @@ public class Ejb3Column {
private String defaultValue; private String defaultValue;
private String comment;
public void setTable(Table table) { public void setTable(Table table) {
this.table = table; this.table = table;
} }
@ -193,6 +196,14 @@ public class Ejb3Column {
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
} }
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Ejb3Column() { public Ejb3Column() {
} }
@ -209,6 +220,9 @@ public class Ejb3Column {
if ( defaultValue != null ) { if ( defaultValue != null ) {
mappingColumn.setDefaultValue( defaultValue ); mappingColumn.setDefaultValue( defaultValue );
} }
if ( StringHelper.isNotEmpty( comment ) ) {
mappingColumn.setComment (comment );
}
if ( LOG.isDebugEnabled() ) { if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Binding column: %s", toString() ); LOG.debugf( "Binding column: %s", toString() );
} }
@ -471,6 +485,7 @@ public class Ejb3Column {
public static Ejb3Column[] buildColumnFromAnnotation( public static Ejb3Column[] buildColumnFromAnnotation(
javax.persistence.Column[] anns, javax.persistence.Column[] anns,
org.hibernate.annotations.Formula formulaAnn, org.hibernate.annotations.Formula formulaAnn,
Comment commentAnn,
Nullability nullability, Nullability nullability,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
PropertyData inferredData, PropertyData inferredData,
@ -479,6 +494,7 @@ public class Ejb3Column {
return buildColumnFromAnnotation( return buildColumnFromAnnotation(
anns, anns,
formulaAnn, formulaAnn,
commentAnn,
nullability, nullability,
propertyHolder, propertyHolder,
inferredData, inferredData,
@ -490,6 +506,7 @@ public class Ejb3Column {
public static Ejb3Column[] buildColumnFromAnnotation( public static Ejb3Column[] buildColumnFromAnnotation(
javax.persistence.Column[] anns, javax.persistence.Column[] anns,
org.hibernate.annotations.Formula formulaAnn, org.hibernate.annotations.Formula formulaAnn,
Comment commentAnn,
Nullability nullability, Nullability nullability,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
PropertyData inferredData, PropertyData inferredData,
@ -525,6 +542,7 @@ public class Ejb3Column {
suffixForDefaultColumnName, suffixForDefaultColumnName,
secondaryTables, secondaryTables,
propertyHolder, propertyHolder,
commentAnn,
nullability, nullability,
context context
); );
@ -601,6 +619,9 @@ public class Ejb3Column {
column.setNullable( column.setNullable(
col.nullable() col.nullable()
); //TODO force to not null if available? This is a (bad) user choice. ); //TODO force to not null if available? This is a (bad) user choice.
if ( commentAnn != null ) {
column.setComment( commentAnn.value() );
}
column.setUnique( col.unique() ); column.setUnique( col.unique() );
column.setInsertable( col.insertable() ); column.setInsertable( col.insertable() );
column.setUpdatable( col.updatable() ); column.setUpdatable( col.updatable() );
@ -676,12 +697,17 @@ public class Ejb3Column {
String suffixForDefaultColumnName, String suffixForDefaultColumnName,
Map<String, Join> secondaryTables, Map<String, Join> secondaryTables,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
Comment comment,
Nullability nullability, Nullability nullability,
MetadataBuildingContext context) { MetadataBuildingContext context) {
Ejb3Column column = new Ejb3Column(); Ejb3Column column = new Ejb3Column();
Ejb3Column[] columns = new Ejb3Column[1]; Ejb3Column[] columns = new Ejb3Column[1];
columns[0] = column; columns[0] = column;
if ( comment != null ) {
column.setComment( comment.value() );
}
//not following the spec but more clean //not following the spec but more clean
if ( nullability != Nullability.FORCED_NULL if ( nullability != Nullability.FORCED_NULL
&& inferredData.getClassOrElement().isPrimitive() && inferredData.getClassOrElement().isPrimitive()

View File

@ -17,6 +17,7 @@ import javax.persistence.PrimaryKeyJoinColumn;
import org.hibernate.AnnotationException; import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.JoinColumnOrFormula; import org.hibernate.annotations.JoinColumnOrFormula;
import org.hibernate.annotations.JoinFormula; import org.hibernate.annotations.JoinFormula;
import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XClass;
@ -98,6 +99,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
private Ejb3JoinColumn( private Ejb3JoinColumn(
String sqlType, String sqlType,
String name, String name,
String comment,
boolean nullable, boolean nullable,
boolean unique, boolean unique,
boolean insertable, boolean insertable,
@ -114,6 +116,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
setImplicit( isImplicit ); setImplicit( isImplicit );
setSqlType( sqlType ); setSqlType( sqlType );
setLogicalColumnName( name ); setLogicalColumnName( name );
setComment( comment );
setNullable( nullable ); setNullable( nullable );
setUnique( unique ); setUnique( unique );
setInsertable( insertable ); setInsertable( insertable );
@ -150,7 +153,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
} }
else { else {
joinColumns[i] = buildJoinColumns( joinColumns[i] = buildJoinColumns(
new JoinColumn[] { join.column() }, mappedBy, joins, propertyHolder, propertyName, buildingContext new JoinColumn[] { join.column() }, null, mappedBy, joins, propertyHolder, propertyName, buildingContext
)[0]; )[0];
} }
} }
@ -181,18 +184,20 @@ public class Ejb3JoinColumn extends Ejb3Column {
public static Ejb3JoinColumn[] buildJoinColumns( public static Ejb3JoinColumn[] buildJoinColumns(
JoinColumn[] anns, JoinColumn[] anns,
Comment comment,
String mappedBy, String mappedBy,
Map<String, Join> joins, Map<String, Join> joins,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
String propertyName, String propertyName,
MetadataBuildingContext buildingContext) { MetadataBuildingContext buildingContext) {
return buildJoinColumnsWithDefaultColumnSuffix( return buildJoinColumnsWithDefaultColumnSuffix(
anns, mappedBy, joins, propertyHolder, propertyName, "", buildingContext anns, comment, mappedBy, joins, propertyHolder, propertyName, "", buildingContext
); );
} }
public static Ejb3JoinColumn[] buildJoinColumnsWithDefaultColumnSuffix( public static Ejb3JoinColumn[] buildJoinColumnsWithDefaultColumnSuffix(
JoinColumn[] anns, JoinColumn[] anns,
Comment comment,
String mappedBy, String mappedBy,
Map<String, Join> joins, Map<String, Join> joins,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
@ -207,6 +212,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
return new Ejb3JoinColumn[] { return new Ejb3JoinColumn[] {
buildJoinColumn( buildJoinColumn(
null, null,
comment,
mappedBy, mappedBy,
joins, joins,
propertyHolder, propertyHolder,
@ -222,6 +228,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
for (int index = 0; index < size; index++) { for (int index = 0; index < size; index++) {
result[index] = buildJoinColumn( result[index] = buildJoinColumn(
actualColumns[index], actualColumns[index],
comment,
mappedBy, mappedBy,
joins, joins,
propertyHolder, propertyHolder,
@ -239,6 +246,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
*/ */
private static Ejb3JoinColumn buildJoinColumn( private static Ejb3JoinColumn buildJoinColumn(
JoinColumn ann, JoinColumn ann,
Comment comment,
String mappedBy, Map<String, Join> joins, String mappedBy, Map<String, Join> joins,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
String propertyName, String propertyName,
@ -252,6 +260,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
); );
} }
Ejb3JoinColumn joinColumn = new Ejb3JoinColumn(); Ejb3JoinColumn joinColumn = new Ejb3JoinColumn();
joinColumn.setComment( comment != null ? comment.value() : null );
joinColumn.setBuildingContext( buildingContext ); joinColumn.setBuildingContext( buildingContext );
joinColumn.setJoinAnnotation( ann, null ); joinColumn.setJoinAnnotation( ann, null );
if ( StringHelper.isEmpty( joinColumn.getLogicalColumnName() ) if ( StringHelper.isEmpty( joinColumn.getLogicalColumnName() )
@ -376,6 +385,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
return new Ejb3JoinColumn( return new Ejb3JoinColumn(
sqlType, sqlType,
name, name,
null,
false, false,
false, false,
true, true,
@ -395,6 +405,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
return new Ejb3JoinColumn( return new Ejb3JoinColumn(
null, null,
defaultName, defaultName,
null,
false, false,
false, false,
true, true,

View File

@ -72,6 +72,7 @@ public class IdBagBinder extends BagBinder {
Ejb3Column[] idColumns = Ejb3Column.buildColumnFromAnnotation( Ejb3Column[] idColumns = Ejb3Column.buildColumnFromAnnotation(
collectionIdAnn.columns(), collectionIdAnn.columns(),
null, null,
null,
Nullability.FORCED_NOT_NULL, Nullability.FORCED_NOT_NULL,
propertyHolder, propertyHolder,
propertyData, propertyData,

View File

@ -0,0 +1,76 @@
/*
* 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.test.annotations.comment;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import java.util.Iterator;
import java.util.stream.StreamSupport;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
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.mapping.Column;
import org.hibernate.mapping.Table;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.junit.Test;
/**
* @author Yanming Zhou
*/
public class CommentTest extends BaseUnitTestCase {
private static final String TABLE_NAME = "TestEntity";
private static final String TABLE_COMMENT = "I am table";
@Test
@TestForIssue(jiraKey = "HHH-4369")
public void testComments() {
StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build();
Metadata metadata = new MetadataSources(ssr).addAnnotatedClass(TestEntity.class).buildMetadata();
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));
Iterator<Column> it = table.getColumnIterator();
while (it.hasNext()) {
Column col = it.next();
assertThat(col.getComment(), is("I am " + col.getName()));
}
}
@Entity(name = "Person")
@javax.persistence.Table(name = TABLE_NAME)
@org.hibernate.annotations.Table(comment = TABLE_COMMENT, appliesTo = TABLE_NAME)
public static class TestEntity {
@Id
@GeneratedValue
@Comment("I am id")
private Long id;
@Comment("I am name")
@javax.persistence.Column(length = 50)
private String name;
@ManyToOne
@JoinColumn(name = "other")
@Comment("I am other")
private TestEntity other;
}
}