spring-data-mongodb icon indicating copy to clipboard operation
spring-data-mongodb copied to clipboard

ClassCastException when using PropertyValueConverter with generic types

Open MrHurniak opened this issue 1 year ago • 3 comments

Dear friends, On our project we faced with issue when using PropertyValueConverter that cause ClassCastException. Here are some code snippets: Entity class with ValueConverter annotation:

@Document("user")
@Data
public class User {

    @ValueConverter(WriteInLowerCase.class)
    private String email;

}

Converter implementation:

public class WriteInLowerCase implements PropertyValueConverter<String, String, ValueConversionContext<?>> {

    @Override
    public String read(String value, ValueConversionContext<?> context) {
        return value;
    }

    @Override
    public String write(String value, ValueConversionContext<?> context) {
        return value.toLowerCase();
    }
}

And SpringData repository:

@Repository
public interface UserRepository extends MongoRepository<User, String> {

    List<AccessEntity> findAllByEmailIgnoreCase(String email);
}

After calling findAllByEmailIgnoreCase we got and exception:

java.lang.ClassCastException: class java.util.regex.Pattern cannot be cast to class java.lang.String (java.util.regex.Pattern and java.lang.String are in module java.base of loader 'bootstrap')
	at com.epam.adminpanel.repo.mongo.converter.WriteInLowerCase.write(WriteInLowerCase.java:6) ~[main/:na]
	at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedValue(QueryMapper.java:440) ~[spring-data-mongodb-4.0.0.jar:4.0.0]
	at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObjectForField(QueryMapper.java:337) ~[spring-data-mongodb-4.0.0.jar:4.0.0]
	at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObject(QueryMapper.java:164) ~[spring-data-mongodb-4.0.0.jar:4.0.0]
	at org.springframework.data.mongodb.core.QueryOperations$QueryContext.getMappedQuery(QueryOperations.java:348) ~[spring-data-mongodb-4.0.0.jar:4.0.0]
	at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:2463) ~[spring-data-mongodb-4.0.0.jar:4.0.0]
	at org.springframework.data.mongodb.core.ExecutableFindOperationSupport$ExecutableFindSupport.doFind(ExecutableFindOperationSupport.java:171) ~[spring-data-mongodb-4.0.0.jar:4.0.0]
	at org.springframework.data.mongodb.core.ExecutableFindOperationSupport$ExecutableFindSupport.all(ExecutableFindOperationSupport.java:134) ~[spring-data-mongodb-4.0.0.jar:4.0.0]
	at org.springframework.data.mongodb.repository.query.AbstractMongoQuery.lambda$getExecution$3(AbstractMongoQuery.java:169) ~[spring-data-mongodb-4.0.0.jar:4.0.0]
	at org.springframework.data.mongodb.repository.query.AbstractMongoQuery.doExecute(AbstractMongoQuery.java:143) ~[spring-data-mongodb-4.0.0.jar:4.0.0]
	at org.springframework.data.mongodb.repository.query.AbstractMongoQuery.execute(AbstractMongoQuery.java:118) ~[spring-data-mongodb-4.0.0.jar:4.0.0]
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:136) ~[spring-data-commons-3.0.0.jar:3.0.0]
	at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:120) ~[spring-data-commons-3.0.0.jar:3.0.0]
	......

The solution from our side was to update implementation of WriteInLowerCase to be without generic implementation:

public class WriteInLowerCase implements PropertyValueConverter {

    @Override
    public Object read(Object value, ValueConversionContext context) {
        return value;
    }

    @Override
    public Object write(Object value, ValueConversionContext context) {
        if (value instanceof String stringValue) {
            return stringValue.toLowerCase();
        }
        return value;
    }
}

But I believe, that types should not be ignored.

MrHurniak avatar Mar 27 '23 16:03 MrHurniak

Thanks for reporting! That's an interesting one since the PartTreeMongoQuery will create a BsonRegularExpression for IgnoreCase which then violates the PropertyValueConverter. Will take it to the team.

christophstrobl avatar Mar 28 '23 05:03 christophstrobl

Ideally, we fix the issue initially on the converter level by checking whether the value is assignable to the property type.

Going forward, if we capture values in other types (e.g. create a Pattern from a String), we should investigate whether we can apply conversions before the Pattern is created.

mp911de avatar Mar 28 '23 08:03 mp911de

Thanks for reporting @MrHurniak. I ran into this same problem and using the broader Object is working for now.

camac avatar Aug 29 '23 02:08 camac