Having read about embeddable inheritance here:
I wanted to try in my own project, which uses the following:
- Java 21
- Spring Boot 3.4.1 (also tried with 3.4.0)
- Spring Data JPA
- Hibernate 6.6.4 (3.4.0 uses 6.6.2, I believe)
- AWS Aurora Postgres
I use orm.xml instead of annotations.
When I run a Spring DataJpaTest against an embeddable H2 database, everything works great. When I run against the real Aurora Postgres DB, however, the application fails to start as indicated by this exception:
Caused by: jakarta.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is java.lang.NullPointerException: Cannot invoke “org.hibernate.sql.model.ast.builder.ColumnValuesTableMutationBuilder.addValueColumn(org.hibernate.metamodel.mapping.SelectableMapping)” because “mutationBuilder” is null.
I tracked this down through debugging to MappingGroupBuilder (line 78)
@Override
public void accept(int selectionIndex, SelectableMapping selectableMapping) {
final AbstractEntityPersister entityPersister = (AbstractEntityPersister) mutationTarget.getTargetPart()
.getEntityPersister();
final String tableNameForMutation = entityPersister.physicalTableNameForMutation( selectableMapping );
final ColumnValuesTableMutationBuilder mutationBuilder = findTableDetailsBuilder( tableNameForMutation );
mutationBuilder.addValueColumn( selectableMapping );
}
The best that I could tell is that
entityPersister.physicalTableNameForMutation( selectableMapping );
returns a tableNameForMutation without the schema name prefix for the mapping that includes the default discriminator column. For example, if I had schema “myschema” and table “foo” and column “bar”, I would see a SelectableMapping with these values:
- tableExpression - myschema.foo
- mappedColumnExpression - bar
This would yield a tableNameForMutation value of “myschema.foo”.
However, if Foo has an embeddable hierarchy - Item as a superclass, Snack as an Item child, Diamond as another Item child, with a discriminator columnName “Item_dtype”-- the SelectableMapping (ExplcitColumnDiscriminatorMappingImpl) tableExpression is only the table name “foo” without the schema name prefix.
This would yield a tableNameForMutation of “foo”.
findTableDetailsBuilder method (called by the accept method shown above) relies on tableNameForMutation as a key to find a ColumnValuesTableMutationBuilder in a map.
The map has the key “myschema.foo” instead of “foo”. accept() assumes it will get a mutationBuilder from findTableDetailsBuilder(). This results in an NPE.
I realize that adding Spring Boot/Spring Data JPA adds another layer of complexity. I suppose the H2 test works because there’s no schema name involved, or at least it appears that way.
I don’t have a test project to reproduce this yet. I’ve only my real project, which, of course, I can’t publish here. In the meantime, does anyone have any insights into this issue? It seems there needs to be a way to prefix the table name discriminator column mapping with the schema name.
Since this is a Spring Boot application, I’m setting the default hibernate schema with this property: spring.jpa.properties.hibernate.default_schema.