How to get Column names of JPA entity
Hibernate can use different naming strategies to map property names, which are defined implicitly (without @Column(name = "...")). To have a 'physical' names you need to dive into Hibernate internals. First, you have to wire an EntityManagerFactory
to your service.
@Autowired
private EntityManagerFactory entityManagerFactory;
Second, you have to retrieve an AbstractEntityPersister
for your class
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
AbstractEntityPersister persister = ((AbstractEntityPersister)sessionFactory.getClassMetadata(baseEntity.getClass()));
Third, you're almost there with your code. You just have to handle both cases - with and without @Column annotation. Try this:
for (Field field : baseEntity.getClass().getFields()) {
if (SecureString.class.isAssignableFrom(field.getType())) {
String columnName;
if (field.isAnnotationPresent(Column.class)) {
columnName = field.getAnnotation(Column.class).name();
} else {
String[] columnNames = persister.getPropertyColumnNames(field.getName());
if (columnNames.length > 0) {
columnName = columnNames[0];
}
}
}
}
Note that getPropertyColumnNames()
retrieves only 'property' fields, that are not a part of primary key. To retrieve key column names, use getKeyColumnNames()
.
And about id
field. Do you really need to have all @Id's in child classes? Maybe would better to move @Id to Entity
class and mark this class with @MappedSuperclass annotation? Then you can retrieve it just with baseEntity.getId();
Aman
Updated on August 09, 2022Comments
-
Aman over 1 year
All my JPA entity classes implement an interface called Entity which is defined like this:
public interface Entity extends Serializable { // some methods }
Some of the fields of my JPA entity have
@Column
annotation on top of them and some don't.MyEntity
class is defined like below:@Entity public class MyEntity implements Entity { @Id private Long id; // Assume that it is auto-generated using a sequence. @Column(name="field1") private String field1; private SecureString field2; //SecureString is a custom class //getters and setters }
My delete method accepts an Entity.
@Override public void delete(Entity baseEntity) { em.remove(baseEntity); //em is entityManager }
Whenever the delete method is invoked I want three things inside my delete method:
1) Fields of
MyEntity
that are of typeSecureString
2) Column name of that particular field in DB (The field may or may not have
@Column
annotation)3) The value of
id
fieldNote that when the
delete()
method is invoked, we don't know for which entity it is invoked, it may be forMyEntity1
,MyEntity2
etc.I have tried doing something like below:
for (Field field : baseEntity.getClass().getFields()) { if (SecureString.class.isAssignableFrom(field.getType())) { // But the field doesn't have annotation @Column specified Column column = field.getAnnotation(Column.class); String columnName = column.name(); } }
But this will only work if the field has
@Column
annotation. Also it doesn't get me other two things that I need. Any ideas? -
MJBZA almost 4 years
sessionFactory.getClassMetadata
is deprecated, it suggest to useEntityManagerFactory.getMetamodel()
. Do you have any idea that how can we use it and retrieve theAbstractEntityPersister
? -
MJBZA almost 4 yearsI found it:
((AbstractEntityPersister)((MetamodelImplementor) entityManager.getEntityManagerFactory().unwrap( SessionFactory.class).getMetamodel()).entityPersister(baseEntity.getClass()))
-
MJBZA almost 4 yearsAnyway your solution has a canonical problem! The
getFields
method only return public fields and normally columns in a JPA entity areprivate
! We must usegetDeclaredFields
instead