Last active
May 9, 2023 07:08
-
-
Save shawnz/8f7308741e2ff6270cc8878ac69b4f6b to your computer and use it in GitHub Desktop.
Hibernate schema validator that outputs warning messages instead of throwing exceptions. Tested with Hibernate 5.3.9
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
spring.jpa.hibernate.ddl-auto = validate | |
spring.jpa.properties.hibernate.schema_management_tool = org.shawnz.WarnValidatorSchemaManagementTool |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.shawnz; | |
import org.hibernate.boot.Metadata; | |
import org.hibernate.boot.model.naming.Identifier; | |
import org.hibernate.boot.model.relational.Sequence; | |
import org.hibernate.dialect.Dialect; | |
import org.hibernate.mapping.Column; | |
import org.hibernate.mapping.Selectable; | |
import org.hibernate.mapping.Table; | |
import org.hibernate.tool.schema.extract.spi.ColumnInformation; | |
import org.hibernate.tool.schema.extract.spi.SequenceInformation; | |
import org.hibernate.tool.schema.extract.spi.TableInformation; | |
import org.hibernate.tool.schema.internal.GroupedSchemaValidatorImpl; | |
import org.hibernate.tool.schema.internal.HibernateSchemaManagementTool; | |
import org.hibernate.tool.schema.spi.ExecutionOptions; | |
import org.hibernate.tool.schema.spi.SchemaFilter; | |
import org.hibernate.type.descriptor.JdbcTypeNameMapper; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import java.util.Iterator; | |
import java.util.Locale; | |
public class WarnSchemaValidator extends GroupedSchemaValidatorImpl { | |
private static Logger log = LoggerFactory.getLogger(WarnSchemaValidator.class); | |
public WarnSchemaValidator(HibernateSchemaManagementTool tool, SchemaFilter validateFilter) { | |
super(tool, validateFilter); | |
} | |
// from https://github.com/hibernate/hibernate-orm/blob/2bcb1b0a6d8600ba3a60eae6460dcb52bf5628e7/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java#L113 | |
@Override | |
protected void validateTable( | |
Table table, | |
TableInformation tableInformation, | |
Metadata metadata, | |
ExecutionOptions options, | |
Dialect dialect) { | |
if ( tableInformation == null ) { | |
log.warn( | |
String.format( | |
"Schema-validation: missing table [%s]", | |
table.getQualifiedTableName().toString() | |
) | |
); | |
// don't validate columns of non-existent table | |
return; | |
} | |
final Iterator selectableItr = table.getColumnIterator(); | |
while ( selectableItr.hasNext() ) { | |
final Selectable selectable = (Selectable) selectableItr.next(); | |
if ( Column.class.isInstance( selectable ) ) { | |
final Column column = (Column) selectable; | |
final ColumnInformation existingColumn = tableInformation.getColumn( Identifier.toIdentifier( column.getQuotedName() ) ); | |
if ( existingColumn == null ) { | |
log.warn(String.format( | |
"Schema-validation: missing column [%s] in table [%s]", | |
column.getName(), | |
table.getQualifiedTableName() | |
) | |
); | |
// don't validate type of non-existent column | |
return; | |
} | |
validateColumnType( table, column, existingColumn, metadata, options, dialect ); | |
} | |
} | |
} | |
@Override | |
protected void validateColumnType( | |
Table table, | |
Column column, | |
ColumnInformation columnInformation, | |
Metadata metadata, | |
ExecutionOptions options, | |
Dialect dialect) { | |
boolean typesMatch = column.getSqlTypeCode( metadata ) == columnInformation.getTypeCode() | |
|| column.getSqlType( dialect, metadata ).toLowerCase(Locale.ROOT).startsWith( columnInformation.getTypeName().toLowerCase(Locale.ROOT) ); | |
if ( !typesMatch ) { | |
log.warn( | |
String.format( | |
"Schema-validation: wrong column type encountered in column [%s] in " + | |
"table [%s]; found [%s (Types#%s)], but expecting [%s (Types#%s)]", | |
column.getName(), | |
table.getQualifiedTableName(), | |
columnInformation.getTypeName().toLowerCase(Locale.ROOT), | |
JdbcTypeNameMapper.getTypeName( columnInformation.getTypeCode() ), | |
column.getSqlType().toLowerCase(Locale.ROOT), | |
JdbcTypeNameMapper.getTypeName( column.getSqlTypeCode( metadata ) ) | |
) | |
); | |
} | |
// this is the old Hibernate check... | |
// | |
// but I think a better check involves checks against type code and then the type code family, not | |
// just the type name. | |
// | |
// See org.hibernate.type.descriptor.sql.JdbcTypeFamilyInformation | |
// todo : this ^^ | |
} | |
@Override | |
protected void validateSequence(Sequence sequence, SequenceInformation sequenceInformation) { | |
if ( sequenceInformation == null ) { | |
log.warn( | |
String.format( "Schema-validation: missing sequence [%s]", sequence.getName() ) | |
); | |
// don't validate properties of non-existent sequence | |
return; | |
} | |
if ( sequenceInformation.getIncrementSize() > 0 | |
&& sequence.getIncrementSize() != sequenceInformation.getIncrementSize() ) { | |
log.warn( | |
String.format( | |
"Schema-validation: sequence [%s] defined inconsistent increment-size; found [%s] but expecting [%s]", | |
sequence.getName(), | |
sequenceInformation.getIncrementSize(), | |
sequence.getIncrementSize() | |
) | |
); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.shawnz; | |
import org.hibernate.boot.registry.selector.spi.StrategySelector; | |
import org.hibernate.cfg.AvailableSettings; | |
import org.hibernate.tool.schema.internal.DefaultSchemaFilterProvider; | |
import org.hibernate.tool.schema.internal.HibernateSchemaManagementTool; | |
import org.hibernate.tool.schema.spi.SchemaFilterProvider; | |
import org.hibernate.tool.schema.spi.SchemaValidator; | |
import java.util.Map; | |
public class WarnValidatorSchemaManagementTool extends HibernateSchemaManagementTool { | |
@Override | |
public SchemaValidator getSchemaValidator(Map options) { | |
return new WarnSchemaValidator(this, getSchemaFilterProvider( options ).getValidateFilter()); | |
} | |
// from https://github.com/hibernate/hibernate-orm/blob/2bcb1b0a6d8600ba3a60eae6460dcb52bf5628e7/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java#L95 | |
private SchemaFilterProvider getSchemaFilterProvider(Map options) { | |
final Object configuredOption = (options == null) | |
? null | |
: options.get( AvailableSettings.HBM2DDL_FILTER_PROVIDER ); | |
return getServiceRegistry().getService( StrategySelector.class ).resolveDefaultableStrategy( | |
SchemaFilterProvider.class, | |
configuredOption, | |
DefaultSchemaFilterProvider.INSTANCE | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Additionally, to see missing constraints, set the following properties:
This will output a file "update.sql" with the missing constraints in the root directory of the app.