简体   繁体   English

使用 java 反射调用 setter 方法

[英]Invoking setter method using java reflection

I need to invoke the setter methods of a class using reflection, and the code is as below:我需要使用反射调用一个class的setter方法,代码如下:

try {             
   Method method = myObj.getClass().getMethod("set" + fieldName, new Class[] { value.getClass() });               
   method.invoke(myObj, value);
     } catch (Exception ex) {
         ex.printStackTrace();
     }

The value is an ArrayList and the setter method is as below: value是一个ArrayList ,setter方法如下:

public void setNames(List<String> names){
    this.names = names;
}

A java.lang.NoSuchMethodException is thrown when running this code, but when the setter method parameter type is changed to ArrayList from List it executes fine.运行此代码时抛出java.lang.NoSuchMethodException ,但是当 setter 方法参数类型从List更改为ArrayList时,它执行正常。 Is there a way to keep the setter method parameter in super type and still use reflection without manually giving the type of the parameter when getting the method from the class?从 class 获取方法时,有没有办法让 setter 方法参数保持在超类型中,并且仍然使用反射而无需手动给出参数类型?

If you happen to use spring framework , you could use the PropertyAccessorFactory for retrieving an implementation of the PropertyAccessor interface:如果您碰巧使用spring 框架,您可以使用PropertyAccessorFactory来检索PropertyAccessor接口的实现:

Accessing properties directly直接访问属性

PropertyAccessor myAccessor = PropertyAccessorFactory.forDirectFieldAccess(object);
// set the property directly, bypassing the mutator (if any)
myAccessor.setPropertyValue("someProperty", "some value");

Accessing properties through accessors/mutators通过访问器/修改器访问属性

If you need to access your properties using their getters and setters , you could use instead the forBeanPropertyAccess method:如果您需要使用它们的gettersetter访问您的属性,您可以改用forBeanPropertyAccess方法:

PropertyAccessor myAccessor = PropertyAccessorFactory.forBeanPropertyAccess(object);
// a `setSomeProperty()` method will be used
myAccessor.setPropertyValue("someProperty", "some value");

You could use BeanUtils :你可以使用BeanUtils

Step #1步骤1

Customer customer = new Customer();

Step #2第2步

BeanUtils.setProperty(customer,"firstName","Paul Young");

You could iterate all class members using reflection and set values accordingly, assuming customer object has:您可以使用反射迭代所有 class 成员并相应地设置值,假设客户 object 具有:

private String firstName;
// Getter and Setter are defined

Contrary to other answers, there is a really simple solution.与其他答案相反,有一个非常简单的解决方案。 See java.beans.Statement .请参阅java.beans.Statement It gives you a way to execute arbitrary reflective code without having to worry about actual vs formal types (and a few other things).它为您提供了一种执行任意反射代码的方法,而不必担心实际类型与正式类型(以及其他一些事情)。

There is a simple solution , but that simplicity comes at the cost of performance.有一个简单的解决方案,但这种简单性是以性能为代价的。

I'm using this monster instead:我正在使用这个怪物:

public static Method findMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {

    // First try the trivial approach. This works usually, but not always.
    try {
        return clazz.getMethod(methodName, parameterTypes);
    } catch (NoSuchMethodException ex) {
    }

    // Then loop through all available methods, checking them one by one.
    for (Method method : clazz.getMethods()) {

        String name = method.getName();
        if (!methodName.equals(name)) { // The method must have right name.
            continue;
        }

        Class<?>[] acceptedParameterTypes = method.getParameterTypes();
        if (acceptedParameterTypes.length != parameterTypes.length) { // Must have right number of parameters.
            continue;
        }

        boolean match = true;
        for (int i = 0; i < acceptedParameterTypes.length; i++) { // All parameters must be right type.
            if (null != parameterTypes[i] && !acceptedParameterTypes[i].isAssignableFrom(parameterTypes[i])) {
                match = false;
                break;
            }
            if (null == parameterTypes[i] && acceptedParameterTypes[i].isPrimitive()) { // Accept null except for primitive fields.
                match = false;
                break;
            }
        }

        if (match) {
            return method;
        }

    }

    // None of our trials was successful!
    throw new NoSuchMethodException();
}

parameterTypes are what you get from your value.getClass() . parameterTypes是您从value.getClass()获得的。 Some or all of them can be also null. Then they are treated as matces for any non-primitive parameter fields.其中一些或全部也可以是 null。然后将它们视为任何非原始参数字段的矩阵。

Even this isn't quit perfect: If there are several methods that are polymorphically suitable but none of which matches exactly, then the returned method is chosen arbitrarily (the first match in the array that clazz.getMethods() returns is taken).即使这样也不是完美的:如果有多个方法在多态上合适但没有一个完全匹配,则返回的方法是任意选择的(采用clazz.getMethods()返回的数组中的第一个匹配项)。 This behavior differs from Java the Language behavior, in which the "closest match" is always used.此行为不同于 Java 语言行为,其中始终使用“最接近的匹配”。

If getting the method by name is sufficient (ie you assume that the parameters are suitable if the name matches), then you can manage with much simpler (and somewhat faster):如果通过名称获取方法就足够了(即假设名称匹配时参数是合适的),那么您可以使用更简单(并且更快一些)的方式进行管理:

public static Method findMethod(Class<?> clazz, String methodName) {
  for (Method method : clazz.getMethods()) {
    if (method.getName().equals(methodName)) {
      return method;
    }
  }
  throw new NoSuchMethodException();
} 

To further boost it up, consider some sort of cache.为了进一步提升它,考虑某种缓存。

Reflection Class is sometimes called as dynamic invocation.反射 Class 有时被称为动态调用。

for example, lets look around getter methods using reflection例如,让我们看看使用反射的 getter 方法

consider there is a class called MyReflectionClass and has a method called getreflect() .考虑有一个名为 MyReflectionClass 的MyReflectionClass并且有一个名为getreflect()的方法。 (eg type string) lets see how to use reflection classes (例如类型字符串)让我们看看如何使用反射类

MyReflectionClass  obj = new MyReflectionClass();

<? extends MyReflectionClass> tempClass = obj.getClass();
String a = (String) obj.getMethod("getreflect").invoke(obj);

now setter method现在设置方法

(String) obj.getDeclaredMethod("setreflect", String.class).invoke(obj,"MyString");

if you need to do the same operation with sequence of string then如果您需要对字符串序列执行相同的操作,则

    (String) obj.getDeclaredMethod("setreflect",
 new String.class{}).invoke(obj,"MyString1","MyString2");

hope it may be useful希望它可能有用

Example set All filds using the setters methods geting the values with ResultSet.使用 setter 方法设置所有字段的示例,使用 ResultSet 获取值。

private Object setAllSetters(Object ob, ResultSet rs) throws SQLException{
    // MZ: Find the correct method
    Class cls = ob.getClass();
    while (rs.next()) {
        for (Field field : cls.getDeclaredFields()){
            for (Method method : cls.getMethods())
            {
                if ((method.getName().startsWith("set")) && (method.getName().length() == (field.getName().length() + 3)))
                {
                    if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase()))
                    {
                        // MZ: Method found, run it
                        try
                        {
                            method.setAccessible(true);
                            if(field.getType().getSimpleName().toLowerCase().endsWith("integer"))
                                method.invoke(ob,rs.getInt(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("long"))
                                method.invoke(ob,rs.getLong(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("string"))
                                method.invoke(ob,rs.getString(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("boolean"))
                                method.invoke(ob,rs.getBoolean(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("timestamp"))
                                method.invoke(ob,rs.getTimestamp(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("date"))
                                method.invoke(ob,rs.getDate(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("double"))
                                method.invoke(ob,rs.getDouble(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("float"))
                                method.invoke(ob,rs.getFloat(field.getName().toLowerCase()));
                            else if(field.getType().getSimpleName().toLowerCase().endsWith("time"))
                                method.invoke(ob,rs.getTime(field.getName().toLowerCase()));
                            else 
                                method.invoke(ob,rs.getObject(field.getName().toLowerCase()));
                        }
                        catch (IllegalAccessException | InvocationTargetException | SQLException e)
                        {
                            System.err.println(e.getMessage());
                        }
                    }
                }
            }
        }
    }
    return ob;
}

Detecting Method Names using String Handling might not look like right way of doing it.使用字符串处理检测方法名称可能看起来不太正确。 Consider this as one of the solutions.将此视为解决方案之一。

    try {
            Animal animal = new Animal();
            BeanInfo beaninfo = Introspector.getBeanInfo(Animal.class);
            PropertyDescriptor pds[] = beaninfo.getPropertyDescriptors();
            Method setterMethod=null;
            for(PropertyDescriptor pd : pds) { 
                setterMethod = pd.getWriteMethod(); // For Setter Method

           /*
               You can get Various property of Classes you want. 
           */

                System.out.println(pd.getName().toString()+ "--> "+pd.getPropertyType().toString()+"--Setter Method:->"+pd.getWriteMethod().toString());

                if(setterMethod == null) continue;
                else
                    setterMethod.invoke(animal, "<value>");
            }
        }catch(Exception e) {e.printStackTrace();}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM