javajpaplayframeworkebean

JPA Attribute Converter being applied despite autoApply=false and property not annotated with @Convert


The system I'm working on has a bunch of legacy data where boolean values have been stored as 'Y' and 'N'. New tables use a BIT column instead and simply store 0 and 1. No table mixes the two approaches.

To support the legacy tables we have the following converter:

@Converter(autoApply = false)
public class BooleanToStringConverter implements AttributeConverter<Boolean, String> {

    private Logger.ALogger Log = Logger.of(BooleanToStringConverter.class);

    @Override
    public String convertToDatabaseColumn(final Boolean attribute) {
        Log.debug("Converting the boolean value {}", attribute);

        if (attribute == null) {
            return "N";
        }

        return attribute ? "Y" : "N";
    }

    @Override
    public Boolean convertToEntityAttribute(final String dbData) {
        return "Y".equalsIgnoreCase(dbData);
    }

}

As this only needs to apply to certain entities the autoApply property has been set to false.

I'm now creating a brand new entity, with a new table. It has two boolean properties, both using the BIT column style instead of Y/N:

@Entity
@Table(name = "MyEntity")
public class MyEntity {

    @Id
    @Column(name = "MyEntityId")
    private Long id;

    @Column(name = "IsClosed")
    private Boolean closed;

    ...
}

Note that I have not applied the @Convert annotation.

I have a query that needs to filter out any rows where the entity is closed:

query.where().eq(CLOSED, Boolean.FALSE)

It is at this point that my problem arises. Whenever this query is run I see the log message from the BooleanToStringConverter being written to the logs and indeed, if I dump the actual SQL that was executed from the MySQL database then I can see that the converter did actually get applied to the boolean property, creating the following SQL fragment:

select <columns>
  from MyEntity t0
 where <other predicates>
   and t0.IsClosed = 'N'
 order by <order clause>

This is obviously wrong - the converter shouldn't have been applied, it's not set to be automatic and the closed property isn't annotated with @Convert.

I tried to work around this by creating a second converter:

@Converter(autoApply = true)
public class BooleanConverter implements AttributeConverter<Boolean, Boolean> {

    private Logger.ALogger Log = Logger.of(BooleanConverter.class);

    @Override
    public Boolean convertToDatabaseColumn(final Boolean attribute) {
        Log.debug("Processing the value {}.", attribute);
        return attribute;
    }

    @Override
    public Boolean convertToEntityAttribute(final Boolean dbData) {
        return dbData;
    }
}

This resulted in both converters being applied to the property and I see both debug statements appearing in the logs.

2019-07-29 14:19:53,994 [dispatcher-69] DEBUG BooleanConverter     Processing the value false.
2019-07-29 14:19:53,994 [dispatcher-69] DEBUG BooleanToStringConve I'm Converting the boolean value false

Next I tried explicitly setting the converter to use on the entity itself (I hoped this might change the order that the converters were getting applied in so that it'd end up as true/false despite the other converter running):

@Entity
@Table(name = "MyEntity")
public class MyEntity {

    @Id
    @Column(name = "MyEntityId")
    private Long id;

    @Convert(converter = BooleanConverter.class)
    @Column(name = "IsClosed")
    private Boolean closed;

    ...
}

With exactly the same result; both converters are applied to the value sequentially, with the BooleanToStringConverter having the last laugh and mangling the predicate.

I would rather keep the BooleanToStringConverter as it makes dealing with the legacy data a bit less painful, but unless I can figure out why it's being applied when it shouldn't it's looking likely that I'll have to delete it.

I'm using Ebean version 4.1.3 and Play! 2.6.21

How can I stop this rogue converter from applying itself to properties that it has no right to be touching?


Solution

  • This is a (now) known limitation of Ebean, as described by Issue 1777 on Ebean's GitHub page. It is not planned to be fixed at the time of writing.