4

I want to get a list of all NamedQueries within my application and I also want to invoke them generically at runtime. Is there an option to get the list as well as some kind of meta-data (generally speaking some kind of Reflection)?

Another Thread provided some kind of solution for NHibernate ... can't find the similar at JPA even if using Hibernate as implementation.

Thx in advance El Subcomandante

Subcomandante
  • 403
  • 1
  • 6
  • 14
  • You're down to specifics of an implementation. DataNucleus JPA would provide a way easy enough, but no idea for Hibernate – DataNucleus Oct 01 '12 at 06:54

3 Answers3

3

I don't think there's anything that does that in one step built in. But you can do it with the metamodel in JPA2, plus some simple reflection:

private static Set<NamedQuery> findAllNamedQueries(EntityManagerFactory emf) {
    Set<NamedQuery> allNamedQueries = new HashSet<NamedQuery>();

    Set<ManagedType<?>> managedTypes = emf.getMetamodel().getManagedTypes();
    for (ManagedType<?> managedType: managedTypes) {
        if (managedType instanceof IdentifiableType) {
            @SuppressWarnings("rawtypes")
            Class<? extends ManagedType> identifiableTypeClass = managedType.getClass();

            NamedQueries namedQueries = identifiableTypeClass.getAnnotation(NamedQueries.class);
            if (namedQueries != null) {
                allNamedQueries.addAll(Arrays.asList(namedQueries.value()));
            }

            NamedQuery namedQuery = identifiableTypeClass.getAnnotation(NamedQuery.class);
            if (namedQuery != null) {
                allNamedQueries.add(namedQuery);
            }
        }
    }
    return allNamedQueries;
}
Tom Anderson
  • 46,189
  • 17
  • 92
  • 133
  • Curses! I can't see any way to get at those without finding and parsing the XML files, which does not sound like fun. – Tom Anderson Sep 30 '12 at 18:42
  • hmmm, doesn't look to be much fun to get the things done ... I was thinking of something provided by Adam Bien in his Pattern book (@see: http://www.adam-bien.com/roller/abien/entry/generic_crud_service_aka_dao, the method's signature: public List findWithNamedQuery(String namedQueryName, Map parameters,int resultLimit)) and it might be helpful to know in advance (at least for the UI components) which named queries exist and to invoke them 'some kind of reflection style' on the fly. – Subcomandante Oct 01 '12 at 20:55
3

Tom Anderson's answer has a mistake: it tries to find annotations on JPA implementation's ManagedType classes, instead of actual entity classes. Here's the corrected version.

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.EntityManagerFactory;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.metamodel.EntityType;

private static Set<NamedQuery> findAllNamedQueries(EntityManagerFactory emf) {
    Set<NamedQuery> allNamedQueries = new HashSet<NamedQuery>();

    Set<EntityType<?>> entityTypes = emf.getMetamodel().getEntities();
    for (EntityType<?> entityType : entityTypes) {
        Class<?> entityClass = entityType.getBindableJavaType();

        NamedQueries namedQueries = entityClass.getAnnotation(NamedQueries.class);
        if (namedQueries != null) {
            allNamedQueries.addAll(Arrays.asList(namedQueries.value()));
        }

        NamedQuery namedQuery = entityClass.getAnnotation(NamedQuery.class);
        if (namedQuery != null) {
            allNamedQueries.add(namedQuery);
        }
    }
    return allNamedQueries;
}

This is still pure JPA2.

Vsevolod Golovanov
  • 4,068
  • 3
  • 31
  • 65
  • I tried editing Tom's answer, but the reviewers don't know what they're doing: http://stackoverflow.com/review/suggested-edits/9231490 – Vsevolod Golovanov Aug 20 '15 at 17:08
  • Does this work if I add named queries directly on the entity manager factory e.g. `emf.addNamedQuery("State.all", em.createNamedQuery("FROM com.my.State", State.class));.`? – bonapart3 Dec 11 '20 at 12:05
  • @bonapart3, doubtful, since this works by looking at the annotations. There is a `NamedQueryRepository` class in Hibernate, which you can get from the `SessionFactory`, and then you can use reflection to read its `namedQueryDefinitionMap` field (this is going by Hibernate 5.3.7). – Vsevolod Golovanov Dec 11 '20 at 16:35
0

I don't understand the question, you already given the solution? You simply can scan the classes and use reflection.

This gives you all annotaions of a class. http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getAnnotations%28%29

Now iterate through that list to get NamedQueries. I guess you don't have to scan all your Classes, it is enough if you read your persistance.xml file and only scan your defined Entities.

Here is a detailed example: http://tutorials.jenkov.com/java-reflection/annotations.html

You should be able to cast the Annotation to the NamedQuery and then simply access name/query attributes.

Sebastian

seba.wagner
  • 3,800
  • 4
  • 28
  • 52