spring-projects / spring-data-neo4j

Provide support to increase developer productivity in Java when using Neo4j. Uses familiar Spring concepts such as a template classes for core API usage and lightweight repository style data access.
http://spring.io/projects/spring-data-neo4j
Apache License 2.0
825 stars 619 forks source link

IgnoreCase does not work in Kotlin [DATAGRAPH-1200] #1762

Closed spring-projects-issues closed 3 years ago

spring-projects-issues commented 5 years ago

manuelprinz opened DATAGRAPH-1200 and commented

When creating a repository interface in Kotlin, using IgnoreCase will fail with the following error message:

Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: Unable to ignore case of java.lang.String types, the property 'label' must reference a String; nested exception is java.lang.IllegalStateException: Unable to ignore case of java.lang.String types, the property 'label' must reference a String

This seems to be due to the compiled class being a kotlin.String instead of java.lang.String.

Using Kotlin strings in NodeEntities seems to work fine, so I expected these types of strings being equivalent everywhere.

Example:

interface FooRepository {
    fun findAllByLabelIgnoreCase(label: String): Iterable<Foo>
}

Please get back to me if you need more information or examples!


Affects: 5.1.5 (Lovelace SR5)

spring-projects-issues commented 5 years ago

Gerrit Meier commented

Thanks for reporting this. It would be really helpful to get an example that reproduces the error you are facing. Simply creating a domain class and repository with a method you mentioned above does work for me. This is probably not the nicest Kotlin code ever written, but should match what you are targeting:

interface PersonRepository : Neo4jRepository<Person, Long> {
    fun findByNameIgnoreCase(label: String): List<Person>
}

@NodeEntity
class Person(var name: String) {
    @Id
    @GeneratedValue
    var id: Long? = null
}

@RunWith(SpringRunner::class)
@ContextConfiguration(classes = [KotlinIntegrationTest.Config::class])
@Transactional
open class KotlinIntegrationTest {
    @Autowired
    lateinit var repository: PersonRepository

    @Test
    fun firstKotlinTest() {
        val name = "personsName"
        val person = Person(name)
        repository.save(person)

        val result = repository.findByNameIgnoreCase(name)
        assertThat(result).hasSize(1)
    }

    @Configuration
    @EnableNeo4jRepositories
    @EnableTransactionManagement
    internal open class Config {
        @Bean
        open fun transactionManager(): PlatformTransactionManager {
            return Neo4jTransactionManager(sessionFactory())
        }

        @Bean
        open fun sessionFactory(): SessionFactory {
            return SessionFactory(
                    org.neo4j.ogm.config.Configuration.Builder()
                            .uri("bolt://localhost")
                            .credentials("neo4j", "neo4j")
                            .build(),
                    "org.springframework.data.neo4j.integration.kotlin")
        }
    }
}
michael-simons commented 3 years ago

Hi @manuelprinz. I hope this is you. If not, sorry and please ignore the notification.

If you trying to match by the label of a node, this is not gonna work through derived finder methods. You can do this with a custom query around the following idea:

match (n) where any (label IN labels(n) WHERE toLower(label) = 'movie') return n

Here: All nodes that have a label movie. Of course all string operations, like regex etc, can be applied as well.

For the example @meistermeier added above, find the project attached. I tested it with 5.1.x, 5.2.x and 5.3.x (through Spring Boot 2.1.x, 2.2.x and 2.3.x), works as expected.

gh1762.zip

Thanks for your contribution.