Search code examples
javajpametamodel

Generic way to get JPA entity version


I have an unknown JPA entity and need to know it's version. I could not find a way to do this generically.

I tried the metamodel, but don't know what to pass to getVersion() method:

Object entity = ...;
Metamodel metamodel = entityManager.getMetamodel();
IdentifiableType<?> metaClass = 
    (IdentifiableType<?>)metamodel.managedType(entity.getClass());
metaClass.getVersion(<what to put here?>);

Same pattern is used in metaClass.getId(), but there is a complementary method getIdType() -- getVersionType() is missing.

Secondly, there is entityManagerFactory.getPersistenceUnitUtil().getIdentifier(entity) method, but not getVersion(entity) method.

Is there some way to get version from an unknown entity?


Solution

  • I solved it in the following way: The javax.persistence.Version class specifies supported datatypes, only seven are supported, so I try all of them one after other. The JPA spec apparently misses the getVersionType() method, I think it is a bug.

    /**
     * Finds the version attribute for ManagedType instance.
     * @param managedType The metaobject
     * @return The version attribute or null, if it does not have one
     * @throws UnsupportedOperationException
     * If it has a version attribute, but is not one of supported types, as specified in {@link Version} documentation
     * (currently int, Integer, short, Short, long, Long, Timestamp).
     */
    private static <T> SingularAttribute<? super T, ?> findVersionAttribute(ManagedType<T> managedType) {
        if ( !(managedType instanceof IdentifiableType))
            return null;
    
        IdentifiableType<T> identifiableType = (IdentifiableType<T>)managedType;
        if ( ! identifiableType.hasVersionAttribute())
            return null;
    
        try {
            return identifiableType.getVersion(int.class);
        } catch (IllegalArgumentException e) {
            try {
                return identifiableType.getVersion(Integer.class);
            } catch (IllegalArgumentException e1) {
                try {
                    return identifiableType.getVersion(long.class);
                } catch (IllegalArgumentException e2) {
                    try {
                        return identifiableType.getVersion(Long.class);
                    } catch (IllegalArgumentException e3) {
                        try {
                            return identifiableType.getVersion(short.class);
                        } catch (IllegalArgumentException e4) {
                            try {
                                return identifiableType.getVersion(Short.class);
                            } catch (IllegalArgumentException e5) {
                                try {
                                    return identifiableType.getVersion(Timestamp.class);
                                } catch (IllegalArgumentException e6) {
                                    throw new UnsupportedOperationException("The version attribute is not of supported type");
                                }
                            }
                        }
                    }
                }
            }
        }
    }