如何摆脱间歇性IllegalArgumentException通过反射使用方法调用

问题描述

我需要将POJO对象转换为其相应的protobuf消息。我正在编写一个实用程序,它将使用反射并生成protobuf消息。

我有以下POJO模型-

public class Person {
   int id;
   Map<String,String> properties;
   String name;
   Address address;
   Gender gender;
}

public class Address {
   private String line1;
   private String line2;
   private String line3;
   private String City;
   private String state;
}

public enum Gender {
   MALE,FEMALE
}

相应的原始消息-

message PersonMsg {
  int32 id = 1;
  map<string,string> properties = 2;
  string name = 3;
  AddressMsg address = 4;
  Gender gender = 5;
}

message AddressMsg {
  string line1 = 1;
  string line2 = 2;
  string line3 = 3;
  string city = 4;
  string state = 5;
  string country = 6;
  string pincode = 7;

}

enum Gender{
  Gender_DEFAULT = 0;
  Gender_MALE = 1;
  Gender_FEMALE = 2;
}

转换器逻辑就像-对于标量/原始类型动态地调用gette / setter并在protobuf构建器中填充数据。 如果字段是自定义类型(在本例中为“地址”字段),则递归调用方法并填充字段-

private static GeneratedMessageV3 getMessage(Object o) throws ClassNotFoundException
    String protoName = o.getClass().getName()+"Proto";
    Class outerClass = Class.forName(protoName);
    String msgName = protoName+"$"+ o.getClass().getSimpleName()+"Msg";
    Class modelClass = o.getClass();
    Class protoMsg = Class.forName(msgName);

    try {
        Method method = protoMsg.getmethod("newBuilder",null);
        com.google.protobuf.GeneratedMessageV3.Builder builder =  (com.google.protobuf.GeneratedMessageV3.Builder)method.invoke(null,null);

        Field[] fields = o.getClass().getDeclaredFields();
        for(Field field : fields){
            if(field.getType().isPrimitive() || field.getType().isAssignableFrom(String.class)){
                Method getmethod = modelClass.getmethod("get"+ CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL,field.getName()));
                Object value = getmethod.invoke(o,null);
                Method setMethod = findSetterMethod(builder.getClass(),field);
                setMethod.invoke(builder,value);
            } else if(field.getType().isEnum()){
                Method getmethod = modelClass.getmethod("get"+ CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL,field.getName()));
                Enum modelEnumValue = (Enum) getmethod.invoke(o,null);
                String protoEnumClassName = field.getType().getName()+"Proto$"+field.getType().getSimpleName();
                Class protoEnumClass = Class.forName(protoEnumClassName);
                Method enumMethod = protoEnumClass.getDeclaredMethod("values",null);
                Enum[] protovalues = (Enum[]) enumMethod.invoke(null,null);
                Enum protovalue = null;
                for(Enum value : protovalues){
                    if(value.name().replace(field.getType().getSimpleName()+"_","").equals(modelEnumValue.name())){
                        protovalue = value;
                    }
                }
                if(protovalue!=null) {
                    Method setMethod = findSetterMethod(builder.getClass(),field);
                    setMethod.invoke(builder,protovalue);
                }
            } else if(Collection.class.isAssignableFrom(field.getType()) || Map.class.isAssignableFrom(field.getType())){
                if(Map.class.isAssignableFrom(field.getType())){
                    populateMap(o,field,builder);
                }
            } else{
                System.out.println("Field is custom type :"+ field.getName());
                Method getmethod = modelClass.getmethod("get"+ CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL,field.getName()));
                System.out.println("Found Getter Method :"+ getmethod);
                Object modelValue = getmethod.invoke(o,null);
                System.out.println("Model Value :"+ modelValue);
                Method setMethod = findSetterMethod(builder.getClass(),getMessage(modelValue));
            }
        }
        GeneratedMessageV3 msg = (GeneratedMessageV3) builder.build();
        return msg;
    } catch (NoSuchMethodException e) {
        e.printstacktrace();
        throw new RuntimeException(e);
    } catch (illegalaccessexception e) {
        e.printstacktrace();
        throw new RuntimeException(e);
    } catch (InvocationTargetException e) {
        e.printstacktrace();
        throw new RuntimeException(e);
    } catch (ClassNotFoundException e) {
        e.printstacktrace();
        throw new RuntimeException(e);
    }
}```

代码可以正常工作,并将pojo对象转换为protobuf消息。 但是有时它会在运行时间歇性地失败,并带有-java.lang.IllegalArgumentException:参数类型不匹配”

这在第-行上失败-“ setMethod.invoke(builder,getMessage(modelValue));”

如果在运行之间完全不更改代码,为什么会失败呢?如何摆脱/解决此异常?

解决方法

“ findSetterMethod”方法中的逻辑是按名称搜索setter方法。因此,如果名称匹配,则返回找到的第一个方法。 Protobuf生成相同的名称方法,但是接受不同的参数-Builder,Protobuf自行发送消息。所以,当选择使用错误类型的方法,它曾经失败。修复了检查正确的参数类型及其现在可以正常工作的代码。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...