We are trying to use a type binder for the following entity model. We want to be able to search EntityToSearch using the fullName in the ConcreteClassA (extends AbstractEntity) using a TypeBinder. The main problem is that the @OneToOne association between ConcreteClassA and EntityToSearch is inherited from the abstract super class.
public class EntityToSearch {
@OneToOne
@IndexedEmbedded(includeEmbeddedObjectId = true)
private AbstractEntity parentEntity;
//other fields
}
// No field to search here
@Inheritance(strategy = InheritanceType.JOINED)
@TypeBinding(binder = @TypeBinderRef(type = FullNameBinder.class))
public abstract class AbstractEntity {
@OneToOne(mappedBy = "parentEntity")
private EntityToSearch entityToSearch ;
//other fields
}
@PrimaryKeyJoinColumn(name = "concreteClassA _id")
ConcreteClassA extends AbstractEntity {
//Field to search
@KeywordField
private String fullName;
}
public class FullNameBinder implements TypeBinder {
@Override
public void bind(final TypeBindingContext context) {
IndexFieldReference<String> fullName= context.indexSchemaElement().field("fullName", IndexFieldTypeFactory::asString).toReference();
context.bridge(ConcreteClassA.class, new MyBridge(fullName));
}
private static class MyBridge implements TypeBridge<AbstractEntity> {
private final IndexFieldReference<String> fullName;
private MyBridge(IndexFieldReference<String> fullNameField) {
this.fullName= fullNameField;
}
@Override
public void write(DocumentElement target, AbstractEntity abstractEntity , TypeBridgeWriteContext context) {
if (abstractEntity instanceof ConcreteClassA ) {
target.addValue(this.fullName, ((ConcreteClassA ) abstractEntity ).getFullName());
}
}
}
}
Our main problem for this bridge to work is the bind function, we first tried to use the dependencies().useRootOnly(), but as indicated in the documentation that means declaring no dependency at all. We tried now to use context.dependencies().fromOtherEntity(ConcreteClassA .class, "?") or context.dependencies().use() but we don’t understand how and witch one to use in our case.
Hello, thanks for the ticket creation and for your fast answer, unforunately this solution is not working for our case. Now the hibernate mapping seems good but if the fullName value is updated, elastic index is not updated. Also, is it possible to change the context.dependencies().fromOtherEntity( ConcreteClassA.class, “self” )
.use(“fullName”); depending on the context.bridgeElement, In our case we got some specific field to ConcreteClassA, but also some to another class ConcreteClassB.
I guess it would look like :
@Override
public void bind(final TypeBindingContext context) {
if (context.bridgedElement instance of ConcreteClassA) {
IndexFieldReference<String> fullName= context.indexSchemaElement().field("fullName", IndexFieldTypeFactory::asString).toReference();
// Hack, see https://discourse.hibernate.org/t/runtime-polymophism-with-typebinder-bridge/6057
context.dependencies().fromOtherEntity( ConcreteClassA.class, "self" )
.use("fullName");
context.bridge(AbstractEntity.class, new MyBridge(fullName, null));
} else if (context.bridgedElement instance of ConcreteClassB) {
IndexFieldReference<String> firstName= context.indexSchemaElement().field("firstName", IndexFieldTypeFactory::asString).toReference();
context.dependencies().fromOtherEntity( ConcreteClassB.class, "self" )
.use("firstName");
context.bridge(AbstractEntity.class, new MyBridge(null, firstName));
}
}
Maybe check that you implemented exactly the solution I provided. If you can’t find a difference, try to come up with a reproducer (you can start from this template), and I’ll have a look.
Yes, it’s possible, and actually that’s exactly what I did in the original solution (the one provided in the other topic I linked to).
No. When bind is called, you don’t have a bridgeElement to test. bind is called on bootstrap, but you want runtime polymorphism.
Thank you for responding so quickly, I did not pay attention enough and did not implement exactly your response, everything if working as expected, thanks for your support.