Skip to content

Missing native reflection hint for custom repository queries #2717

Closed
@cmdjulian

Description

@cmdjulian

I have the following entities:

Tag:

@Entity
@Table(name = "tag")
class Tag(@Id val name: String, var color: Color) {

    @ManyToMany(mappedBy = "tags", fetch = FetchType.LAZY)
    private val notebooks: Set<Notebook> = emptySet()

    @PreRemove
    fun preRemove() {
        notebooks.forEach { notebook -> notebook.tags.remove(this) }
    }

    override fun equals(other: Any?): Boolean = when {
        this === other -> true
        other == null || Hibernate.getClass(this) != Hibernate.getClass(other) -> false
        else -> other is Tag && name != other.name
    }

    override fun hashCode(): Int = name.hashCode()
}

enum class Color {
    RED, GREEN, BLUE
}

Notebook:

@Entity
@Table(name = "notebook")
@EntityListeners(AuditingEntityListener::class)
class Notebook(
    @Column(length = 128, nullable = false) var title: String,
    @Column(length = 1024) var description: String?
) {

    @Id
    @Column(columnDefinition = "uuid")
    var id: UUID = UUID.randomUUID()

    @Column(updatable = false, nullable = false)
    val createdAt: OffsetDateTime = OffsetDateTime.now()

    @LastModifiedDate
    @Column(nullable = false)
    lateinit var lastModified: OffsetDateTime

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
        name = "notebook_tag",
        joinColumns = [JoinColumn(name = "notebook_id")],
        inverseJoinColumns = [JoinColumn(name = "tag_id")]
    )
    var tags: MutableSet<Tag> = mutableSetOf()
        set(value) {
            field.clear()
            field.addAll(value)
        }

    override fun equals(other: Any?) = when {
        this === other -> true
        other == null || Hibernate.getClass(this) != Hibernate.getClass(other) -> false
        else -> other is Notebook && id == other.id
    }

    override fun hashCode() = id.hashCode()

    override fun toString() = "Notebook(id=$id, title='$title', description=$description, createdAt=$createdAt, " +
        "lastModified=$lastModified)"
}

This is my repository:

interface TagRepository : JpaRepository<Tag, String> {
    fun findByNameIgnoreCase(name: String): Tag?
    fun existsByNameIgnoreCase(name: String): Boolean
}

I noticed that having a custom method, yields in the following error on startup:

Error creating bean with name 'tagRepository': Could not create query for public abstract com.example.app.tag.domain.Tag com.example.app.tag.application.TagRepository.findByNameIgnoreCase(java.lang.String); Reason: Type not found: org.springframework.data.repository.query.FluentQuery$FetchableFluentQuery<S>
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:349) ~[na:na]
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArguments(BeanInstanceSupplier.java:265) ~[na:na]
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:208) ~[na:na]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[notes:6.0.0-M6]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1210) ~[notes:6.0.0-M6]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1157) ~[notes:6.0.0-M6]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[notes:6.0.0-M6]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[notes:6.0.0-M6]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[notes:6.0.0-M6]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[notes:6.0.0-M6]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[notes:6.0.0-M6]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[notes:6.0.0-M6]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:931) ~[notes:6.0.0-M6]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:926) ~[notes:6.0.0-M6]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:592) ~[notes:6.0.0-M6]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[notes:3.0.0-M5]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:751) ~[notes:3.0.0-M5]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:442) ~[notes:3.0.0-M5]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) ~[notes:3.0.0-M5]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1323) ~[notes:3.0.0-M5]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312) ~[notes:3.0.0-M5]
	at de.etalytics.notes.NotesApplicationKt.main(NotesApplication.kt:13) ~[notes:na]

Adding FluentQuery.FetchableFluentQuery constructor as type hint solved the problem:

class AotConfig : RuntimeHintsRegistrar {
    override fun registerHints(hints: RuntimeHints, classLoader: ClassLoader?) {
        hints.reflection().registerType(FetchableFluentQuery::class.java, *MemberCategory.values())
    }
}

I'm using the newest Spring Snapshot from the snapshot repository (16.10.2022). I saw it references Spring Data 3.0.0-RC1.

For reference: spring-projects/spring-framework#29327

Metadata

Metadata

Labels

theme: aotAn issue related to Ahead-Of-Time processingtype: bugA general bug

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions