2012-11-26 20 views
5

Mam listę tabel VO. Obiekty te mają wiele właściwości i odpowiednie metody get/set. Chcę posortować listę tablic na podstawie właściwości, którą otrzymam w czasie wykonywania. Pozwól mi wyjaśnić szczegółowo. Moja VO jest jak tenposortuj listę obiektów na podstawie właściwości środowiska wykonawczego

public class Employee { 
    String name; 
    String id; 

    private String getName() { 
     return name; 
    } 

    private String getId() { 
     return id; 
    } 
} 

będę coraz ciąg „” w czasie wykonywania sortType, który może być albo „id” lub „nazwa”. Chcę posortować listę na podstawie wartości ciągu.

Próbowałem użyć komparatora i odbicia razem, ale bez powodzenia. Być może nie użyłem go poprawnie. Nie chcę używać pętli if i tworzyć nowych klas komparatorów. Jakieś inne myśli?

Próbny haczyk powinien znajdować się w nowej klasie. Oto działający kod. Jeśli chcesz użyć oddzielnej klasy dla komparatora, znajdź ją w komentarzu @ Bohemian poniżej.

 String sortType = "name"; // determined at runtime 
     Collections.sort(results, new Comparator<Employee>() { 
     public int compare(Employee c1, Employee c2) { 
      try{ 
      Method m = c1.getClass().getMethod("get" + StringUtils.capitalize(sortType)); 
      String s1 = (String)m.invoke(c1); 
      String s2 = (String)m.invoke(c2); 
      return s1.compareTo(s2); 
      } 
      catch (Exception e) { 
       return 0; 
      } 
     } 
     }); 
+2

proszę użyj odpowiedniego znacznika języka. – NPE

+0

Ups .. Dodałem go teraz. – jijo

+0

Jeśli umieścisz swój kod, który używał odbicia, być może będziemy w stanie powiedzieć, co poszło nie tak ... – akuhn

Odpowiedz

15

Tworzenie Comparator dla zadania:

public class EmployeeComparator implements Comparator<Employee> { 

    private final String type; 

    public EmployeeComparator (String type) { 
     this.type = type; 
    } 

    public int compare(Employee e1, Employee e2) { 
     if (type.equals("name")) { 
      return e1.getName().compareTo(e2.getName()); 
     } 
     return e1.getId().compareTo(e2.getId()); 
    } 

} 

Potem go używać

String type = "name"; // determined at runtime 
Collections.sort(list, new EmployeeComparator(type)); 

Wersja odblaskowe byłaby podobna, z wyjątkiem będziesz szukał metody na obiekcie typu "get" + (pisane wielkimi literami) i wywołaj to i mocno rzuć na porównywalne i użyj compareTo (postaram się pokazać kod, ale używam mojego iPhone'a i jego trochę rozciągnięcia, b ut tu idzie)

public class DynamicComparator implements Comparator<Object> { 
    private final String type; 
    // pass in type capitalised, eg "Name" 
    // ie the getter method name minus the "get" 
    public DynamicComparator (String type) { 
     this.type = type; 
    } 
    public int compare(Object o1, Object o2) { 
     // try-catch omitted 
     Method m = o1.getClass().getMethod("get" + type); 
     String s1 = (String)m.invoke(o1); 
     String s2 = (String)m.invoke(o2); 
     return s1.compareTo(s2); 
    } 
} 

OK ... Oto jak to zrobić bez tworząc klasę, za pomocą anonimowej klasy (z wyjątkiem obsługi tak kod kompiluje):

List<?> list; 
final String attribute = "Name"; // for example. Also, this is case-sensitive 
Collections.sort(list, new Comparator<Object>() { 
    public int compare(Object o1, Object o2) { 
     try { 
      Method m = o1.getClass().getMethod("get" + attribute); 
      // Assume String type. If different, you must handle each type 
      String s1 = (String) m.invoke(o1); 
      String s2 = (String) m.invoke(o2); 
      return s1.compareTo(s2); 
     // simply re-throw checked exceptions wrapped in an unchecked exception 
     } catch (SecurityException e) { 
      throw new RuntimeException(e); 
     } catch (NoSuchMethodException e) { 
      throw new RuntimeException(e); 
     } catch (IllegalAccessException e) { 
      throw new RuntimeException(e); 
     } catch (InvocationTargetException e) { 
      throw new RuntimeException(e); 
     } 
    } 
}); 
+1

To wygląda dobrze i prosto. Dzięki !! Spróbuję i dam ci znać. – jijo

+0

To zdecydowanie bardziej czysto, +1 za to ... –

+0

Awesome man .. !! Właśnie tego szukałem!Pozwól mi spróbować. – jijo

0

Keep it simple!

Jeśli wybór jest tylko id lub name -use if.

Wybór pomiędzy dwoma opcjami. Tak, jeśli został wymyślony.

Lub, jeśli ma wiele właściwości, użyj odbicia lub przechowuj dane najpierw w postaci Map. Czasami Map jest lepszy niż klasa. W szczególności, jeśli Twoja VO nie ma metod innych niż pobierające i ustawiające.

Jednak ostrożność przy użyciu odbicia może być w tym przypadku niebezpieczna, ponieważ klient może wstrzyknąć dowolny termin w parametrach CGI w ataku podobnym do iniekcji SQL.

+0

OP stwierdza, że ​​jego klasa ma _many_ właściwości. Myślę, że właśnie pokazał dwóm z nich, aby zachować prostotę. – jahroy

+0

To jest problem. To nie tylko id i nazwa, moja VO jest dość duża, zawiera około 10 obiektów. – jijo

+0

Dodano racjonalne uzasadnienie * NIE * za pomocą odbicia. – akuhn

1

wykonaj następujące czynności:

  • uzyskać nazwę pola z klientem
  • budować nazwę getter -> "get" + nazwa pola (po czerpanie pierwszy znak)
  • starają się znaleźć sposób z refleksji za pomocą Class.getDeclaredMethod()
  • w przypadku stwierdzenia, powołać zwrócony obiekt Method na dwóch wystąpień swojej VO klasy
  • wykorzystać wyniki tych przywoływanych getter do sortowania
+0

Równie dobrze możesz uzyskać dostęp do pól (jeśli pobierające są naprawdę takie banalne). – akuhn

Powiązane problemy