question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ScalarTypeWrapper doesn't handle "nullValue" correctly

See original GitHub issue

I have a column using a custom type with a converter as:

    @Convert(converter = CustomDateConverter.class)
    CustomDate somedate;
@Converter
public class CustomDateConverter implements ScalarTypeConverter<CustomDate, Date> {
    @Override
    public CustomDate getNullValue() {
        // Return null value or null object here will cause either reading or binding issue
        return CustomDate.nullDate; 
    }

    @Override
    public Date unwrapValue(CustomDate attribute) {
        return attribute != null ? attribute.toDate() : null;
    }

    @Override
    public CustomDate wrapValue(Date dbData) {
        return (dbData != null) ? CustomDate.fromDate(dbData) : CustomDate.nullDate;
    }
}

From my investigation, I can see that ebean can’t wrap / unwrap value correctly due to the following code in ScalaTypeWrapper:

  @Override
  public B read(DataReader reader) throws SQLException {
    S sv = scalarType.read(reader);
    if (sv == null) {
      return nullValue;
    }
    return converter.wrapValue(sv);
  }

  public Object toJdbcType(Object value) {
    Object sv = converter.unwrapValue((B) value);
    if (sv == null) {
      return nullValue;
    }
    return scalarType.toJdbcType(sv);
  }
  • If the value from database is “null”, the converter doesn’t have chance to wrap it into a “none” at custom type
  • If the value from the entity property is “none”, it never gets chance to translate into “null” at JDBC type

The fix would be:

  @Override
  public B read(DataReader reader) throws SQLException {
    S sv = scalarType.read(reader);
    return converter.wrapValue(sv);
  }

  public Object toJdbcType(Object value) {
    Object sv = converter.unwrapValue((B) value);
    return scalarType.toJdbcType(sv);
  }

… which leaves the handling of null value / null object to the converter instead.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:15 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
rbygravecommented, Mar 18, 2021

Pushed a fix for - “standard JPA AttributeConverter which doesn’t have the getNullValue method, he/she can’t convert null to a custom null object”

The fix is for AttributeConverterAdapter to probe the AttributeConverter for the nullValue rather than just assuming it is null. I’m happy with this approach and keeps it in line with what we have. We still need to ponder if ScalarTypeConverter should be deprecated at some point but no rush on this.

1reaction
rbygravecommented, Mar 17, 2021

uses standard JPA AttributeConverter which doesn’t have the getNullValue method, he/she can’t convert null to a custom null object

Yes, I can see that now.

I am pondering if this part of the issue is more a design issue in terms of this subtle difference between ScalarTypeConverter and AttributeConverter.

For Ebean ScalarTypeConverter the javadoc says:

 * Matches the functionality of javax.persistence.AttributeConverter
 * <p>
 * In general AttributeConverter should be used in preference to this
 * ScalarTypeConverter as it is JPA standard and offers the same functionality.
 * </p>
 * <p>
 * For Ebean we will look to deprecate this interface in preference to AttributeConverter.
 * </p>

Edit: The javadoc doesn’t talk about “null treatment”

Ultimately there is a subtle design mismatch between these 2 API’s with Ebean ScalarTypeConverter having the additional getNullValue() method (which is not present on JPA AttributeConverter).

I’m pondering if the correct thing to do is actually remove the ScalarTypeConverter.getNullValue() method with the thought to make these interfaces exactly compatible wrt null treatment. In theory this would make it clear that “null conversion logic” needs to be in the wrapValue() and unwrapValue() methods [rather than outside in ScalarTypeWrapper].

Status:

  1. I’ll push the commit for the “fix the parameter binding in case we use ScalarTypeConverter”
  2. We have an issue for AttributeConverter with a custom null value
  3. Longer term we have design issue in terms of subtle difference between ScalarTypeConverter and AttributeConverter and maybe should look to actually deprecate ScalarTypeConverter (once we sort 2).

Next steps: Failing test case for AttributeConverter with a custom null value.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to return NULL object in C++ - Stack Overflow
The NULL return value would only be valid if you were returning a pointer to a Normal object, NULL represents a null pointer,...
Read more >
How to handle null values | Apache Pinot Recipes
In this Apache Pinot Recipe, we'll learn how to handle null values in Apache Pinot tables.
Read more >
Why We Should Love 'null' - CodeProject
This article looks at popular techniques used to avoid null pointer errors and answers the question: Which is the best solution you should ......
Read more >
Can an array store null values? - Quora
An array of Integer (the object wrapper of int ) will be initially filled with null ... can store null values as long...
Read more >
2. Working with Data: Literals, Values, Variables, and Types
If no type is specified the Scala compiler will use type inference to determine the correct type to assign to your variable. Unlike...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found