2011-12-15 23 views
52

Tôi viết một lớp java có nhiều getters..now tôi muốn có được tất cả các phương thức getter và gọi chúng đôi khi .. Tôi biết có phương pháp như getMethods() hoặc getMethod (String name, Class ... parameterTypes), nhưng tôi chỉ muốn có được getter thực sự ..., sử dụng regex? bất cứ ai có thể cho tôi biết?Java Reflection: Làm thế nào tôi có thể nhận được tất cả các phương thức getter của một lớp java và gọi chúng

Trả lời

128

Không sử dụng regex, sử dụng Introspector:

for(PropertyDescriptor propertyDescriptor : 
    Introspector.getBeanInfo(yourClass).getPropertyDescriptors()){ 

    // propertyEditor.getReadMethod() exposes the getter 
    // btw, this may be null if you have a write-only property 
    System.out.println(propertyDescriptor.getReadMethod()); 
} 

Thông thường, bạn không muốn tính từ Object.class, vì vậy bạn muốn sử dụng phương pháp này với hai tham số:

Introspector.getBeanInfo(yourClass, stopClass) 
// usually with Object.class as 2nd param 
// the first class is inclusive, the second exclusive 

BTW: có các khung làm điều đó cho bạn và trình bày cho bạn một cái nhìn cấp cao. Ví dụ. commons/beanutils có phương pháp

Map<String, String> properties = BeanUtils.describe(yourObject); 

(docs here) mà không chỉ rằng: tìm và thực hiện tất cả các getter và lưu trữ kết quả trong một bản đồ. Thật không may, BeanUtils.describe() chuyển đổi tất cả các giá trị thuộc tính thành Chuỗi trước khi trở về. WTF. Cảm ơn @danw


Cập nhật:

Dưới đây là một Java 8 phương thức trả về một Map<String, Object> dựa trên thuộc tính bean của một đối tượng.

public static Map<String, Object> beanProperties(Object bean) { 
    try { 
    return Arrays.asList(
     Introspector.getBeanInfo(bean.getClass(), Object.class) 
        .getPropertyDescriptors() 
    ) 
     .stream() 
     // filter out properties with setters only 
     .filter(pd -> Objects.nonNull(pd.getReadMethod())) 
     .collect(Collectors.toMap(
     // bean property name 
     PropertyDescriptor::getName, 
     pd -> { // invoke method to get value 
      try { 
       return pd.getReadMethod().invoke(bean); 
      } catch (Exception e) { 
       // replace this with better error handling 
       return null; 
      } 
     })); 
    } catch (IntrospectionException e) { 
    // and this, too 
    return Collections.emptyMap(); 
    } 
} 

Có thể bạn muốn xử lý lỗi mạnh mẽ hơn. Xin lỗi cho boilerplate, kiểm tra ngoại lệ ngăn cản chúng tôi đi đầy đủ chức năng ở đây.


Chỉ ra rằng Collectors.toMap() ghét giá trị null. Dưới đây là một phiên bản cấp bách hơn về đoạn code trên:

public static Map<String, Object> beanProperties(Object bean) { 
    try { 
     Map<String, Object> map = new HashMap<>(); 
     Arrays.asList(Introspector.getBeanInfo(bean.getClass(), Object.class) 
            .getPropertyDescriptors()) 
       .stream() 
       // filter out properties with setters only 
       .filter(pd -> Objects.nonNull(pd.getReadMethod())) 
       .forEach(pd -> { // invoke method to get value 
        try { 
         Object value = pd.getReadMethod().invoke(bean); 
         if (value != null) { 
          map.put(pd.getName(), value); 
         } 
        } catch (Exception e) { 
         // add proper error handling here 
        } 
       }); 
     return map; 
    } catch (IntrospectionException e) { 
     // and here, too 
     return Collections.emptyMap(); 
    } 
} 

Dưới đây là các chức năng tương tự một cách ngắn gọn hơn, sử dụng JavaSlang:

public static Map<String, Object> javaSlangBeanProperties(Object bean) { 
    try { 
     return Stream.of(Introspector.getBeanInfo(bean.getClass(), Object.class) 
            .getPropertyDescriptors()) 
        .filter(pd -> pd.getReadMethod() != null) 
        .toJavaMap(pd -> { 
         try { 
          return new Tuple2<>(
            pd.getName(), 
            pd.getReadMethod().invoke(bean)); 
         } catch (Exception e) { 
          throw new IllegalStateException(); 
         } 
        }); 
    } catch (IntrospectionException e) { 
     throw new IllegalStateException(); 

    } 
} 

và đây là một phiên bản Ổi:

public static Map<String, Object> guavaBeanProperties(Object bean) { 
    Object NULL = new Object(); 
    try { 
     return Maps.transformValues(
       Arrays.stream(
         Introspector.getBeanInfo(bean.getClass(), Object.class) 
            .getPropertyDescriptors()) 
         .filter(pd -> Objects.nonNull(pd.getReadMethod())) 
         .collect(ImmutableMap::<String, Object>builder, 
           (builder, pd) -> { 
            try { 
             Object result = pd.getReadMethod() 
                 .invoke(bean); 
             builder.put(pd.getName(), 
                firstNonNull(result, NULL)); 
            } catch (Exception e) { 
             throw propagate(e); 
            } 
           }, 
           (left, right) -> left.putAll(right.build())) 
         .build(), v -> v == NULL ? null : v); 
    } catch (IntrospectionException e) { 
     throw propagate(e); 
    } 
} 
+5

Wow. Tôi không biết bạn có thể làm điều đó! Mát mẻ! –

+0

Cảm ơn ..i kiểm tra mã ... kết thúc đầu ra là ** công khai java.lang.Class java.lang.Object.getClass() ** ... tôi không muốn gọi nó. .how để loại bỏ nó? – user996505

+1

@ user996505 Sử dụng Introspector.getBeanInfo (yourClass, Object.class), để tìm kiếm tất cả các lớp bên dưới Object –

9
// Get the Class object associated with this class. 
    MyClass myClass= new MyClass(); 
    Class objClass= myClass.getClass(); 

    // Get the public methods associated with this class. 
    Method[] methods = objClass.getMethods(); 
    for (Method method:methods) 
    { 
     System.out.println("Public method found: " + method.toString()); 
    } 
+1

Có, nhưng bạn cũng sẽ phải kiểm tra từng phương thức công khai, không tĩnh, trả về void, hy vọng không có tham số và tuân theo quy ước get/isXyz name. Introspector làm tất cả những điều đó cho bạn, cộng với nó lưu trữ dữ liệu BeanInfo nội bộ cho các ứng dụng khác. –

+0

không trả lại khoảng trống, tức là –

16

Bạn có thể sử dụng Reflections khuôn khổ cho

này
import org.reflections.ReflectionUtils.*; 
Set<Method> getters = ReflectionUtils.getAllMethods(someClass, 
     ReflectionUtils.withModifier(Modifier.PUBLIC), ReflectionUtils.withPrefix("get")); 
+0

Không phải tất cả các getters đều bắt đầu bằng "get": (1) getters boolean-return có thể bắt đầu bằng "is"; (2) một lớp BeanInfo có thể nói rằng các phương thức bổ sung là getters.Bạn thực sự nên thêm một hạn chế như _if bạn biết rằng tất cả các getters của bạn bắt đầu bằng "get", bạn có thể làm điều này_. – toolforger

-4

Bạn nên duy trì một getter chung trong mọi đậu, do đó để gọi getAttribute1(), bạn sẽ có thể gọi một getter get generic ("Attribute1")

này getter generic sẽ gọi trong-turn getter đúng

Object get(String attribute) 
{ 
    if("Attribute1".equals(attribute) 
    { 
     return getAttribute1(); 
    } 
} 

cách tiếp cận này liên quan đến việc bạn duy trì danh sách riêng biệt này trong mọi đậu nhưng cách này bạn tránh phản chiếu trong đó có vấn đề hiệu suất, vì vậy nếu bạn viết mã sản xuất mà cần phải có hiệu suất tốt, bạn có thể sử dụng trên mẫu cho tất cả các hạt của bạn.Nếu nó là một số mã thử nghiệm hoặc mã tiện ích không có yêu cầu hiệu năng cao thì bạn nên sử dụng các cách tiếp cận khác vì phương pháp này dễ bị lỗi trừ khi bạn có thể viết một số loại trình biên dịch thời gian biên dịch. hoạt động cho tất cả các thuộc tính.

7

Spring cung cấp một cách dễ dàng BeanUtil method cho Bean mẫn:

PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(clazz, property); 
Method getter = pd.getReadMethod(); 
0

Mã này được kiểm tra OK.

private void callAllGetterMethodsInTestModel(TestModel testModelObject) { 
     try { 
      Class testModelClass = Class.forName("com.encoders.eva.testreflectionapi.TestModel"); 
      Method[] methods = testModelClass.getDeclaredMethods(); 
      ArrayList<String> getterResults = new ArrayList<>(); 
      for (Method method : 
        methods) { 
       if (method.getName().startsWith("get")){ 
        getterResults.add((String) method.invoke(testModelObject)); 
       } 
      } 
      Log.d("sayanReflextion", "==>: "+getterResults.toString()); 
     } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException e) { 
      e.printStackTrace(); 
     } 
    } 
Các vấn đề liên quan