How to get Column names of JPA entity

22,744

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();

Share:
22,744
Aman
Author by

Aman

Updated on August 09, 2022

Comments

  • Aman
    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 type SecureString

    2) Column name of that particular field in DB (The field may or may not have @Column annotation)

    3) The value of id field

    Note that when the delete() method is invoked, we don't know for which entity it is invoked, it may be for MyEntity1, 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
    MJBZA almost 4 years
    sessionFactory.getClassMetadata is deprecated, it suggest to use EntityManagerFactory.getMetamodel(). Do you have any idea that how can we use it and retrieve the AbstractEntityPersister?
  • MJBZA
    MJBZA almost 4 years
    I found it: ((AbstractEntityPersister)((MetamodelImplementor) entityManager.getEntityManagerFactory().unwrap( SessionFactory.class).getMetamodel()).entityPersister(baseEn‌​tity.getClass()))
  • MJBZA
    MJBZA almost 4 years
    Anyway your solution has a canonical problem! The getFields method only return public fields and normally columns in a JPA entity are private! We must use getDeclaredFields instead