Java: 标准库将字段名("firstName")转换为访问器方法名("getFirstName")

15
有没有标准库(例如org.apache.commons.beanutils或java.beans),可以将一个字符串字段名转换为标准方法名?我已经寻找了很久,但找不到一个简单的字符串转换实用程序。

1
你可以用一行代码自己完成这个任务。 - RoflcoptrException
2
+1,正是我想知道的。即使自己编写代码很简单,如果存在标准库实用程序,使用它也是有意义的。 - Jonik
8个回答

18

JavaBean Introspector是可能最好的选择。它处理布尔类型的“is” getter以及带有一个参数的“getter”和没有或两个参数的setter以及其他边缘情况。它很适合获取类的JavaBean字段列表。

以下是一个示例:

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;

public class SimpleBean
{
    private final String name = "SimpleBean";
    private int size;

    public String getName()
    {
        return this.name;
    }

    public int getSize()
    {
        return this.size;
    }

    public void setSize( int size )
    {
        this.size = size;
    }

    public static void main( String[] args )
            throws IntrospectionException
    {
        BeanInfo info = Introspector.getBeanInfo( SimpleBean.class );
        for ( PropertyDescriptor pd : info.getPropertyDescriptors() )
            System.out.println( pd.getName() );
    }
}

这将打印

class
name
size

class 来自于从 Object 继承的 getClass()

编辑:要获取getter或setter及其名称。

public static String findGetterName(Class clazz, String name) throws IntrospectionException, NoSuchFieldException, NoSuchMethodException {
    Method getter = findGetter(clazz, name);
    if (getter == null) throw new NoSuchMethodException(clazz+" has no "+name+" getter");
    return getter.getName();
}

public static Method findGetter(Class clazz, String name) throws IntrospectionException, NoSuchFieldException {
    BeanInfo info = Introspector.getBeanInfo(clazz);
    for ( PropertyDescriptor pd : info.getPropertyDescriptors() )
        if (name.equals(pd.getName())) return pd.getReadMethod();
    throw new NoSuchFieldException(clazz+" has no field "+name);
}

public static String findSetterName(Class clazz, String name) throws IntrospectionException, NoSuchFieldException, NoSuchMethodException {
    Method setter = findSetter(clazz, name);
    if (setter == null) throw new NoSuchMethodException(clazz+" has no "+name+" setter");
    return setter.getName();
}

public static Method findSetter(Class clazz, String name) throws IntrospectionException, NoSuchFieldException {
    BeanInfo info = Introspector.getBeanInfo(clazz);
    for ( PropertyDescriptor pd : info.getPropertyDescriptors() )
        if (name.equals(pd.getName())) return pd.getWriteMethod();
    throw new NoSuchFieldException(clazz+" has no field "+name);
}

1
你可以提供一个使用 Introspector 从字段名获取方法名的代码示例吗? - Matt Ball
那只是您链接的教程中的代码;如果向我们展示如何编写从“String”到“String”的方法,则我会给您点赞。 - Matt Ball
一个更困难的问题是使用getter名称获取方法,但使用这种方法实际上是微不足道的。 - Peter Lawrey
1
问题是如何生成字符串“getClass”、“getName”和“getSize”,给定字符串“class”、“name”和“size”。你正在回答如何检索已经存在的方法。 - strickli
对于布尔字段,方法名可以是isFlaggetFlag,这样内省器就可以为您解决。 - Peter Lawrey
@PeterLawrey,确实可以这样做...但是,这仍然不是问题所问的。 内省器将会“内省”现有的bean,并使用现有的方法。而提问者正在询问如何生成尚不存在的方法名称。 - strickli

16

出现了一条野生的单行代码!

String fieldToGetter(String name)
{
    return "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
}

9
除非该getter是一个“isBooleanGetter”,否则不为+0。 - Peter Lawrey
1
@Peter 很好的观点,不过并非所有人都使用 isFoo() 命名约定来表示 boolean 类型字段的 getter 方法。 - Matt Ball
2
错误!“eMail”的getter应该是geteMail()! - JRA_TLL
@JRA_TLL 这取决于你使用的风格。如果你遵循谷歌的驼峰命名风格,那么该字段应该被称为email,因此getter方法应该是getEmail() - Matt Ball
这是一个关于风格的问题,要避免像eMail这样的字段,因为有所提及的警告。但事实上,如果你敢把你的字段命名为eMail,那么getter/setter需要被称为geteMail以符合Java bean规范,并且例如被Hibernate找到。 - JRA_TLL
显示剩余5条评论

16

您可以使用PropertyDescriptor而不需要Inspector(这是由Peter建议的):

final PropertyDescriptor propertyDescriptor = 
    new PropertyDescriptor("name", MyBean.class);
System.out.println("getter: " + propertyDescriptor.getReadMethod().getName());
System.out.println("setter: " + propertyDescriptor.getWriteMethod().getName());

2
String fieldToSetter(String name)
{
    return "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
}

由Matt Ball版权所有


那是我回答的复制-粘贴-改一个字符版本吗? :P - Matt Ball
我本来可以自己写的,但我不想用不同的语法把问题搞混了 :P - RoflcoptrException

1

我修改了上面的方法,去掉下划线并将下一个字符大写化...例如,如果字段名称是"validated_id",则getter方法名称将为"getValidatedId"

private String fieldToGetter(String name) {
    Matcher matcher = Pattern.compile("_(\\w)").matcher(name);
    while (matcher.find()) {
        name = name.replaceFirst(matcher.group(0), matcher.group(1).toUpperCase());
    }

    return "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
}

private String fieldToSetter(String name) {
    Matcher matcher = Pattern.compile("_(\\w)").matcher(name);
    while (matcher.find()) {
        name = name.replaceFirst(matcher.group(0), matcher.group(1).toUpperCase());
    }

    return "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
}

1
String fieldToGetter(Field field) {
    final String name = field.getName();
    final boolean isBoolean = (field.getType() == Boolean.class || field.getType() == boolean.class);
    return (isBoolean ? "is" : "get") + name.substring(0, 1).toUpperCase() + name.substring(1);
}

String fieldToGetter(boolean isBoolean, String name) {
    return (isBoolean ? "is" : "get") + name.substring(0, 1).toUpperCase() + name.substring(1);
}

1
Guava的CaseFormat可以帮你完成这个任务。
例如,从lower_underscore -> LowerUnderscore。
CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, str)

0
在下面的示例中,有两个字段名为exampleeXample,它们的getter方法是getExamplegeteExample,但只有当它们是由Eclipse生成时才成立。然而,这与PropertyDescriptor("eXample",...).getReadMethod().getName()不兼容,因为它期望的有效getter名称是getEXample
public class XX {

    private Integer example;
    private Integer eXample;


    public Integer getExample() {
        return example;
    }

    public Integer geteXample() {
        return eXample;
    }

    public void setExample(Integer example) {
        this.example = example;
    }

    public void seteXample(Integer eXample) {
        this.eXample = eXample;
    }

    public static void main(String[] args) {
        try {
            System.out.println("Getter: " + new PropertyDescriptor("example", ReflTools.class).getReadMethod().getName());
            System.out.println("Getter: " + new PropertyDescriptor("eXample", ReflTools.class).getReadMethod().getName());
        } catch (IntrospectionException e) {
            e.printStackTrace();
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接