Problems with extracting null value

Previously (in version 5.6) my custom type was implemented via CustomType. As a result, when I got null from the database, the nullSafeGet method in CustomType class was called when extracting it. My custom type itself called nullSafeGet from StringType and in case of null converted null to an empty object.

*CustomType.class*

	@Override
	public Object nullSafeGet(
			ResultSet rs,
			String[] names,
			SharedSessionContractImplementor session,
			Object owner) throws SQLException {
		return getUserType().nullSafeGet( rs, names, session, owner);
	}

move to this

*MyCustomType.class*

public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException {
        String sqlString = (String)StringType.INSTANCE.nullSafeGet(rs, names[0], session);
        if (sqlString == null || sqlString.trim().length() == 0) {
            if(this.isNullable()){
                return null;
            }else{
                return getId(” ”);
            }
        } else {
            StringId id = this.getId(sqlString);
            return (id.isNull() && this.isNullable()) ? null : id;
        }

When I switched to 6.4, I tried to keep the old code, which caused the following problem: Now the BasicResultAssembler class is called during extraction, which directly calls BasicExtractor. My class ends up converting null to an empty object, and then the code in BasicExtractor returns it to null.

*BasicExtractor.class*

if ( value == null || rs.wasNull() ) {
			if ( JdbcExtractingLogging.LOGGER.isTraceEnabled() ) {
				JdbcExtractingLogging.logNullExtracted(
						paramIndex,
						getJdbcType().getDefaultSqlTypeCode()
				);
			}
			return null;
		}

How to avoid forcing the value to null in BasicExtractor and return the old behavior?

I don’t see this code that you’re pointing to. If you use a UserType, you’re in full control.

BasicResultAssembler calls extractRawValue which in turn calls RowProcessingStateStandardImpl#getJdbcValue(int)JdbcValuesResultSetImpl#getCurrentRowValueUserTypeSqlTypeAdapter.ValueExtractorImpl#extractUserType#nullSafeGet.

There is no null handling along that way. So whatever you did in your application setup, your config seems wrong.

I looked more closely at the chain of calls. Yes, you are correct, however:
UserTypeSqlTypeAdapter.ValueExtractorImpl#extract-> UserType#nullSafeGet.

In my case, this is a solution like MutableType by Vlad Mihalcea (hypersistence-utils/hypersistence-utils-hibernate-60/src/main/java/io/hypersistence/utils/hibernate/type/MutableType.java at master · vladmihalcea/hypersistence-utils · GitHub)

@Override
    public T nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException {
        return jdbcTypeDescriptor.getExtractor(javaTypeDescriptor).extract(rs, position, session);
    }

This leads to a call to org.hibernate.type.descriptor.jdbc.BasicExtractor#extract(java.sql.ResultSet, int, org.hibernate.type.descriptor.WrapperOptions)

Where null is inevitably put if I received null from the database (rs.wasNull() )

	@Override
	public J extract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
		final J value = doExtract( rs, paramIndex, options );
		if ( value == null || rs.wasNull() ) {
			if ( JdbcExtractingLogging.LOGGER.isTraceEnabled() ) {
				JdbcExtractingLogging.logNullExtracted(
						paramIndex,
						getJdbcType().getDefaultSqlTypeCode()
				);
			}
			return null;
		}

Should I make my jdbc type with a modification of BasicExtractor?

I don’t know what that means and I also don’t know what this MutableType thing does. All I can tell you is that if you use a regular UserType this will just work.

I may have confused you. Let’s say again the very essence:
my type uses VarcharJdbcType. VarcharJdbcType returns BasicExtractor in the getExtractor method.

BasicExtractor by default won’t let me convert null from a column in the DB to an empty java object (because it additionally checks that the DB column was not equal to null), although my CustomJavaType does so.

The only solution I see is to make my own CustomJdbcType where I override the getExtractor method, returning BasicExtractor with an extract method that won’t do the rs.wasNull() check.

Is there no other way where I don’t have to make a VarcharJdbcType inheritor?

Either you create a custom JdbcType or you create a UserType which is a mix of both JavaType and JdbcType.