【问题标题】:Getting a property/field name using getter method of a pojo/java bean?使用 pojo/java bean 的 getter 方法获取属性/字段名称?
【发布时间】:2012-11-02 09:42:10
【问题描述】:

我有一个下面的类,我需要使用 java 反射从 getter 方法获取字段名称。 是否可以使用 getter 方法获取字段名或属性名?

class A {

    private String name;
    private String salary;

    // getter and setter methods
}

我的问题是:我可以通过 getter 方法获取字段/属性名称吗?如果我使用 getName(),我可以获得 name 属性吗?我需要 name 属性,但不需要它的值。是否可以通过java反射?

【问题讨论】:

  • 如果你得到有用的答案......你应该接受它:)

标签: java reflection


【解决方案1】:

是的,这是 100% 可能的......

public static String getFieldName(Method method)
{
    try
    {
        Class<?> clazz=method.getDeclaringClass();
        BeanInfo info = Introspector.getBeanInfo(clazz);  
        PropertyDescriptor[] props = info.getPropertyDescriptors();  
        for (PropertyDescriptor pd : props) 
        {  
            if(method.equals(pd.getWriteMethod()) || method.equals(pd.getReadMethod()))
            {
                System.out.println(pd.getDisplayName());
                return pd.getName();
            }
        }
    }
    catch (IntrospectionException e) 
    {
        e.printStackTrace();
    }
    catch (Exception e) 
    {
        e.printStackTrace();
    }


    return null;
}

【讨论】:

  • 如何将方法作为参数发送?? getFieldName(cls.getProperty()) 将给出价值
  • 如果属性名称不同于取出“get”并将其余部分资本化,那么这将不起作用。例如,如果我有一个 getName() getter 并且该属性称为 _name 或 m_name 等
  • 如果你有一个名为arg1 的字段并且getter-method 被命名为getAge (可以说是脏的,但是100% pojo-bean),这不是100% 可能的没有了。
  • 如何使 getName 是作为参数发送给该方法的方法
【解决方案2】:

reflection-util 库提供了一种以类型安全的方式确定属性(名称)的方法。 例如使用 getter 方法:

String propertyName = PropertyUtils.getPropertyName(A.class, A::getSalary);

在这种情况下,propertyName 的值将是 "salary"

免责声明:我是reflection-util 库的作者之一。

【讨论】:

  • 不要使用反射工具,它会通过瞬态依赖使用“不安全”,并且不能在 jdk > 8 上工作。
  • @rumatoest:我不知道反射实用程序在 jdk > 8 上不起作用。你能在项目中提出问题吗?
【解决方案3】:

仅删除“get”或“is”前缀并将第一个字母小写是不够的。例如,getID 的适当 bean 名称应该是 ID 而不是 iD。

获取 bean 名称的最简单方法是去掉 get 或 is 前缀,然后将结果传递给 Introspector.decapitalize

这是我写的一个方法来做这件事:

private String getBeanName(String methodName)
{
    // Assume the method starts with either get or is.
    return Introspector.decapitalize(methodName.substring(methodName.startsWith("is") ? 2 : 3));
}

【讨论】:

  • 一个名为 ID 的变量(和一个名为 getID 的 getter)不遵循 Java Bean 命名约定。变量名应以小写字母开头。
  • @NamelessVoice,变量应该以小写字母开头是正确的。但是,我们不是在谈论变量。我们在谈论属性。请参阅 Javabean 标准的第 8.8 节:download.oracle.com/otn-pub/jcp/…
  • 糟糕,我不知道这种极端情况。
【解决方案4】:

您无法使用反射检查代码的作用。

您可以假设getName() 方法读取了一个名为name 的字段并且不执行任何其他操作。但是,没有要求这样做。例如字段名称可能是 m_name_namenameField 甚至不是字段。

【讨论】:

    【解决方案5】:

    你可以

    Field[] declaredFields = A.class.getDeclaredFields();
            for(Field f:declaredFields){
                System.out.println(f.getName());
            }
    

    【讨论】:

    • 这仅给出所有字段的列表,而不是与 getter 关联的字段。
    • @Adam 你需要列出所有的获取方法并使用该方法你可以获取文件
    • 这是 OP 想要的。我认为没有属性描述符是不可能的。
    【解决方案6】:

    你可以使用lombok's@FieldNameConstants注解。

    注释你的类:

    import lombok.experimental.FieldNameConstants;
    import lombok.AccessLevel;
    
    @FieldNameConstants
    public class FieldNameConstantsExample {
      private final String name;
      private final int rank;
    }
    

    在后台生成以下代码:

    public class FieldNameConstantsExample {
      private final String name;
      private final int rank;
      
      public static final class Fields {
        public static final String name = "name";
        public static final String rank = "rank";
      }
    }
    

    因此您可以通过以下方式访问属性名称:

    FieldNameConstantsExample.Fields.name
    

    这是字符串"name"

    【讨论】:

    • 如果您使用“lombok”,它的方法又好又干净。
    【解决方案7】:

    如果您的 bean 遵循 JavaBean 约定,那么您使用反射来获取所有“get”和“is”方法,并从检索到的方法名称中删除“get”或“is”前缀,然后您就有了字段名称。

    更新

    // 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)
        {
            String name=method.getName();
            if(name.startsWith("get") || name.startsWith("is"))
            {
               //...code to remove the prefixes
            }
        }
    

    【讨论】:

      【解决方案8】:

      使用反射 API,可以按如下方式检索 POJO 字段。继承的类可能会在这里发现问题。

      TestClass testObject= new TestClass().getClass();
      Fields[] fields = testObject.getFields();
      for (Field field:fields)
      {
          String name=field.getName();
          System.out.println(name);
      }
      

      或者通过使用反射 API,也可以检索类中的所有方法并遍历它以查找属性名称(标准 POJO 方法以 get/is/set 开头)......这种方法对我来说适用于继承类结构。

      TestClass testObject= new TestClass().getClass();
      Method[] methods = testObject.getMethods();
      for (Method method:methods)
      {
          String name=method.getName();
          if(name.startsWith("get"))
          {
              System.out.println(name.substring(3));
          }else if(name.startsWith("is"))
          {
              System.out.println(name.substring(2));
          }
      }
      

      不过更有趣的方法如下:

      在 Jackson 库的帮助下,我能够找到 String/integer/double 类型的所有类属性,以及 Map 类中的相应值。 (全部不使用反射 api!

      TestClass testObject = new TestClass();
      com.fasterxml.jackson.databind.ObjectMapper m = new com.fasterxml.jackson.databind.ObjectMapper();
      
      Map<String,Object> props = m.convertValue(testObject, Map.class);
      
      for(Map.Entry<String, Object> entry : props.entrySet()){
          if(entry.getValue() instanceof String || entry.getValue() instanceof Integer || entry.getValue() instanceof Double){
              System.out.println(entry.getKey() + "-->" + entry.getValue());
          }
      }
      

      【讨论】:

        【解决方案9】:

        您应该通过该方法访问。目前,getter 将返回成员 name但将来可能会改变。它可以懒惰地从数据库或网络服务中实例化它,从名字/姓氏等构建它。name 字段很可能不存在。

        所以总是通过方法(甚至通过反射)

        【讨论】:

          【解决方案10】:

          如果你知道方法的名字,你只需要去掉“get”,把后面的字母转换成小写,就不需要反思了。

          如果 getter 方法 (getName()) 返回名称与“name”不同的属性,则无法从方法名称中获取属性名称。

          如果你不知道方法的名字,通过反射你可以获得所有的方法,你也可以获得所有名字的属性。

          【讨论】:

            【解决方案11】:

            试试下面的

            class A{
            
                   private String name;
                   private String salary;
            
               //getter and setter methods
            
                   public void setName(String name){
                      this.name = name;
                    }
            
                   public void setSalary(String salary){
                       this.salary = salary;
            
                     }
            
                    public String getName(){
                      return name;
                      }
            
                    public String getSalary(){
                      return salary;
                      }
            

            }

            get 方法用于从程序方法或数据库中动态检索数据。它将仅反映值而不是值的属性。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2013-07-07
              • 1970-01-01
              • 2021-02-15
              • 1970-01-01
              • 1970-01-01
              • 2019-02-03
              • 2020-01-25
              相关资源
              最近更新 更多