"No value extractors" on startup

Versions:
Hibernate: 5.6.3.Final
Hibernate Search with Elasticsearch: 6.0.8.Final

Problem:
We have a bidirectional OneToOne relation between two classes Person and HumanName, where HumanName is the “parent” side with the mappedBy-annotation. Person is @Indexed, with an @IndexedEmbedded on its name field.
Due to the way Hibernate deals with these cases, this results in an N+1-problem every time a List<Person> with their names is returned in a query. We tried this workaround, implementing PersistentAttributeInterceptable in our HumanName class. This successfully deals with the N+1 problem; however, the creation of the search index then fails with the following error. Removing the methods $$_hibernate_getInterceptor() and $$_hibernate_setInterceptor fixes the Hibernate Search error, but reintroduces the N+1 error. Is there a way to to make this work with Hibernate Search?

Caused by: org.hibernate.search.util.common.SearchException: HSEARCH000520: Hibernate Search encountered failures during bootstrap. Failures:

    Hibernate ORM mapping: 
        type 'com.example.entitygraphtest.model.Person': 
            path '.name<no value extractors>.firstName': 
                failures: 
                  - HSEARCH700079: Exception while retrieving property type model for 'firstName' on 'com.example.entitygraphtest.model.HumanName'.

The model classes look like this:

@Indexed
@Getter
@Setter
@Entity
@NoArgsConstructor
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Person {

    @Id
    @GeneratedValue
    UUID id;

    @IndexedEmbedded(includeEmbeddedObjectId = true)
    @AssociationInverseSide(inversePath = @ObjectPath(@PropertyValue(propertyName = "person")))
    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    HumanName name;

}
@Getter
@Setter
@Entity
public class HumanName implements PersistentAttributeInterceptable {

    @Id
    @GeneratedValue
    UUID id;

    @KeywordField
    String firstName;

    @ElementCollection
    private List<String> middleNames;

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "name")
    @LazyToOne(LazyToOneOption.NO_PROXY)
    Person person;

    public Person getPerson() {
        if (interceptor != null) {
            return (Person) interceptor.readObject(this, "person", person);
        }
        return person;
    }

    public void setPerson(Person person) {
        if (interceptor != null) {
            this.person = (Person) interceptor.writeObject(this, "person", this.person, person);
        } else {
            this.person = person;
        }
    }

    @Transient
    private PersistentAttributeInterceptor interceptor;

    @Override
    public PersistentAttributeInterceptor $$_hibernate_getInterceptor() {
        return interceptor;
    }

    @Override
    public void $$_hibernate_setInterceptor(final PersistentAttributeInterceptor interceptor) {
        this.interceptor = interceptor;
    }

}

Hello.

First, please post the full stack trace. It should appear higher up in your logs.

Second, I’m not quite sure your workaround is warranted here. I’m not sure it’s correct either, but that might just be because I’m not familiar with it.

Usually I would include the name of a person inside the Person entity, because I’m likely to need the name every time I read a person, and unlikely to ever need the name without the person. You can use embeddables if what you want is to model first + last name with an object.

If you really need to make the name a separate entity for some reason, consider making the person -> name association eager, perhaps also using @Fetch(FetchMode.SUBSELECT). Or you can use batch fetching.

If that doesn’t solve your N+1, please show me a snippet of code that triggers that N+1.