diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java index b506e49816..e9abeef45b 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java @@ -555,7 +555,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol @Override public R toRelationalValue(Boolean domainValue) { - return underlyingJpaConverter.toRelationalValue( !domainValue ); + return underlyingJpaConverter.toRelationalValue( domainValue != null ? !domainValue : null ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BooleanJavaType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BooleanJavaType.java index ec815ab0e9..fc0e62129c 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BooleanJavaType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BooleanJavaType.java @@ -198,10 +198,7 @@ public class BooleanJavaType extends AbstractClassJavaType implements (BasicValueConverter) converter; final Object falseValue = stringConverter.toRelationalValue( false ); final Object trueValue = stringConverter.toRelationalValue( true ); - String[] values = new String[] { - falseValue != null ? falseValue.toString() : null, - trueValue != null ? trueValue.toString() : null - }; + final String[] values = getPossibleStringValues( stringConverter, falseValue, trueValue ); return dialect.getCheckCondition( columnName, values ); } else if ( jdbcType.isInteger() ) { @@ -210,13 +207,48 @@ public class BooleanJavaType extends AbstractClassJavaType implements (BasicValueConverter) converter; final Number falseValue = numericConverter.toRelationalValue( false ); final Number trueValue = numericConverter.toRelationalValue( true ); - Long[] values = new Long[] { - falseValue != null ? Long.valueOf(falseValue.longValue()) : null, - trueValue != null ? Long.valueOf(trueValue.longValue()) : null - }; + Long[] values = getPossibleNumericValues( numericConverter, falseValue, trueValue ); return dialect.getCheckCondition( columnName, values ); } } return null; } + + private static Long[] getPossibleNumericValues( + BasicValueConverter numericConverter, + Number falseValue, + Number trueValue) { + Number nullValue = null; + try { + nullValue = numericConverter.toRelationalValue( null ); + } + catch ( NullPointerException ignored ) { + } + Long[] values = new Long[nullValue != null ? 3 : 2]; + values[0] = falseValue != null ? falseValue.longValue() : null; + values[1] = trueValue != null ? trueValue.longValue() : null; + if ( nullValue != null ) { + values[2] = nullValue.longValue(); + } + return values; + } + + private static String[] getPossibleStringValues( + BasicValueConverter stringConverter, + Object falseValue, + Object trueValue) { + Object nullValue = null; + try { + nullValue = stringConverter.toRelationalValue( null); + } + catch ( NullPointerException ignored ) { + } + final String[] values = new String[nullValue != null ? 3 : 2]; + values[0] = falseValue != null ? falseValue.toString() : null; + values[1] = trueValue != null ? trueValue.toString() : null; + if ( nullValue != null ) { + values[2] = nullValue.toString(); + } + return values; + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/java/BooleanJavaTypeDescriptorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/java/BooleanJavaTypeDescriptorTest.java index df7831d4f5..227807a498 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/java/BooleanJavaTypeDescriptorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/type/java/BooleanJavaTypeDescriptorTest.java @@ -63,6 +63,15 @@ public class BooleanJavaTypeDescriptorTest { assertEquals("is_active in (0,1)", checkCondition); } + @Test + public void testCheckConditionShouldReturnCorrectStatementWhen1And0AndNullIntegerGiven() { + // given + // when + String checkCondition = underTest.getCheckCondition("is_active", IntegerJdbcType.INSTANCE, new TriStateBooleanConverter(), new AnyDialect()); + // then + assertEquals("is_active in (0,1,-1)", checkCondition); + } + @Test public void testWrapShouldReturnTrueWhenYStringGiven() { // given @@ -176,4 +185,38 @@ public class BooleanJavaTypeDescriptorTest { return IntegerJavaType.INSTANCE; } } + + private static class TriStateBooleanConverter implements AttributeConverter, BasicValueConverter { + @Override + public Integer convertToDatabaseColumn(Boolean attribute) { + if (attribute == null) return -1; + return attribute ? 1 : 0; + } + + @Override + public Boolean convertToEntityAttribute(Integer dbData) { + if (dbData == null || dbData == -1) return null; + return dbData == 1; + } + + @Override + public @Nullable Boolean toDomainValue(@Nullable Integer relationalForm) { + return convertToEntityAttribute(relationalForm); + } + + @Override + public @Nullable Integer toRelationalValue(@Nullable Boolean domainForm) { + return convertToDatabaseColumn(domainForm); + } + + @Override + public JavaType getDomainJavaType() { + return BooleanJavaType.INSTANCE; + } + + @Override + public JavaType getRelationalJavaType() { + return IntegerJavaType.INSTANCE; + } + } } \ No newline at end of file