diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java index 8cae290faa..5a4181fac6 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -579,6 +579,15 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun }; } + /** + * Does this dialect strip trailing spaces from values stored + * in columns of type {@code char(n)}? + * MySQL is the main offender here. + */ + public boolean stripsTrailingSpacesFromChar() { + return false; + } + /** * The SQL type to use in {@code cast( ... as ... )} expressions when * casting to the target type represented by the given JDBC type code. diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java index 10c1090a3b..a32676dd5e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -284,6 +284,16 @@ public class MySQLDialect extends Dialect { }; } + /** + * MySQL strips any trailing space character from a + * value stored in a column of type {@code char(n)}. + * @return {@code true} + */ + @Override + public boolean stripsTrailingSpacesFromChar() { + return true; + } + @Override public boolean useMaterializedLobWhenCapacityExceeded() { // MySQL has no real concept of LOBs, so we can just use longtext/longblob with the materialized JDBC APIs diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CharacterJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CharacterJavaType.java index fbc6bccb72..f240db0f10 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CharacterJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CharacterJavaType.java @@ -63,19 +63,32 @@ public class CharacterJavaType extends AbstractClassJavaType implemen if ( value == null ) { return null; } - if (value instanceof Character character) { + else if (value instanceof Character character) { return character; } - if (value instanceof String string) { - if ( string.length() != 1 ) { - throw new CoercionException( "value must contain exactly one character: '" + string + "'" ); + else if (value instanceof String string) { + switch ( string.length() ) { + case 1: + return string.charAt( 0 ); + case 0: + if ( options.getDialect().stripsTrailingSpacesFromChar() ) { + // we previously stored char values in char(1) columns on MySQL + // but MySQL strips trailing spaces from the value when read + return ' '; + } + else { + throw new CoercionException( "value does not contain a character: '" + string + "'" ); + } + default: + throw new CoercionException( "value contains more than one character: '" + string + "'" ); } - return string.charAt( 0 ); } - if (value instanceof Number number) { + else if (value instanceof Number number) { return (char) number.shortValue(); } - throw unknownWrap( value.getClass() ); + else { + throw unknownWrap( value.getClass() ); + } } @Override