JPA Name der konkreten Klasse

Saheeda

Top Contributor
Hallo,

ich habe mehrere Interfaces, welche das JpaRepository implementieren.
Da einige Programmteile identisch sind, habe ich folgende generische Methode:

Java:
    private <T extends Entity<T>, ID extends Serializable> Set<T> translate(final List<ID> list,
            final JpaRepository<T, ID> repository) {

        Set<T> objects = new HashSet<>();
        for (ID t : list) {
            T object = repository.findOne(t);
            if (object == null) {
                throw new IllegalArgumentException(MessageFormat.format("no object with id {0} found in {1} repository.",
                        t,
                        repository.getClass().getName()));
            }           
            objects.add(object);
        }
        return objects;
    }

Ich möchte in der Fehlermeldung gern den Namen des konkreten Repositorys (bzw. der Entität) stehen haben. repository.getClass().getName() liefert aber nur "$Proxy1...".

Hat jemand ne Idee, wie ich die Fehlermeldung bauen kann? Den Repositorynamen als String mit in die Methode hineinzugeben finde ich mehr als nur dreckig :-/.
 

stg

Top Contributor
Mir ist nicht klar, was genau du erwartest. Willst du nun den konkreten Typ von T zur Laufzeit wissen, oder welche spezielle Implementierung von JPARepository genau übergeben wird?
In letzterem Fall wird ja offenbar nicht deine Instanz direkt übergeben, sondern diese wird hinter einem Proxy-Objekt "versteckt". Da musst du nun erstmal herausfinden, wer dafür genau verantwortlich ist und ob das verwendete Framework ggfls auch Möglichkeiten bereitstellt auf das hinter dem Proxy liegende Objekt direkt zuzugreifen.
Mit Spring kenn ich mich nicht wirklich aus, aber vielleicht hilft dir AOPUtils:
https://docs.spring.io/spring/docs/...opUtils.html#getTargetClass-java.lang.Object-
Ist es ein WELD-Proxy, dann kannst du mal probieren die superClass abzufragen
Code:
repository.getClass().getSuperClass().getName()
, aber das ist auch nicht schön.
Wie man an das Object hinter dem Proxy bekommt hängt wie schon gesagt vom Framework (und der Art und Weise, wie dieser erstellt wird) ab.

Die einfachste Variante für den ersten Fall wäre die Klasse als Instanzvariable schon im Konstruktor zu setzen. Hab ich auch schon oft gesehen.
Du kannst dir aber auch ParameterizedType mal anschauen.
 

Saheeda

Top Contributor
Hi,

Momentan steht in der Fehlermeldung "no object with id 1 found for $Proxy123". Für eine vernünftige Rückmeldung bzw. um die Fehlersuche zu erleichtern wäre es besser, wenn in der Fehlermeldung auch stehen würde, wo/für welche Entität/in welcher Tabelle der gesuchte Eintrag nicht gefunden werden konnte.
Ich hätte also gern sowas wie "no object with id 1 found for User" oder "no object with id 1 found for UserRepository". Eben irgendein genauerer Hinweis, welche Parameter des Requests falsch ist.

Zum JpaRepository selbst gibt es im Code keine konkreten Instanzen, es gibt eigene Interfaces, welche das JpaRepository erweitern, die "Magic" wird von Spring übernommen.
T wiederum ist der konkrete Typ der Entität/des Domainobjekts, welches durch das Repository verarbeitet wird.

Java:
public interface UserRepository extends JpaRepository<User, Long>{

    List<User> findByName(String name);
}

Ich hätte jetzt erwartet, dass es irgendwie möglich ist, an "de.blubberblaba.repository.UserRepository" oder "de.blubberblabal.domain.User" heranzukommen.

Ich hab mir jetzt erstmal so beholfen, finde es aber nach wie vor nicht wirklich schön.
Java:
private<T extends Entity<T>, ID extends Serializable> Set<T> translate(final List<ID> list,
           final JpaRepository<T, ID> repository, final Class<T> entityClass){

        Set<T> objects =new HashSet<>();
       for(ID t : list){
            T object = repository.findOne(t);
           if(object ==null){               
                  throw new IllegalArgumentException(MessageFormat.format("no object with id {0} found for {1}.",
                    t,
                    entityClass.getName()));
           }         
            objects.add(object);
       }
       return objects;
   }
 

stg

Top Contributor
Mal ganz doof ... was liefert denn
Code:
object.getClass()
zurück?

Ganz einfacher (und hässlicher :) )Test-Case:

Java:
  static <T> void doTest(List<T> list) { 
      T item = list.get(0);
      System.out.println(item.getClass()); 
  }
 
  public static void main(String ... args) {
      List<Integer> i = new ArrayList<>(); 
      i.add(3);
      doTest(i);
  }

Liefert mir als Ausgabe:
Code:
class java.lang.Integer

Das ist doch das, wonach du suchst, wenn ich dich nun richtig verstanden habe?
 

stg

Top Contributor
Ja, stimmt, das sit natürlich blöd. Ist mir irgendwie entgangen.
Ohne eine konkrete Instanz von T zu haben sehe ich dann mit Java-Boardmitteln (auch mit Reflection) keine Möglichkeit an den tatsächlichen Typ von T zu kommen.
An deiner Stelle würde ich den Weg einschlagen und versuchen herauszufinden, wie Spring die Proxys umsetzt. Im einfachsten Fall geschieht das einfach über Vererbung und ein Aufruf von
Code:
repository.getClass().getSuperClass()
liefert schon das gewünschte zurück (hast du das denn mal probiert?) Geschieht das über Komposition, dann geh doch mal mittels Reflection alle Typen durch, von denen dein Proxy-Objekt ist (das ist etwas schwammig ausgedrückt, hoffentlich verstehst du trotzdem, was ich meine?!) Vielleicht ist da ein passender Typ bei, auf den du dein Proxy casten kannst, auf welchem du eine Methode wie "getTargetClass()" oder ähnliches aufrufen kannst, um direkt auf des "versteckte" Objekt hinter dem Proxy zugreifen zu können.
 

Ähnliche Java Themen

Neue Themen


Oben