Java反射如何调用依赖类中匹配JsonProperty的getter/setter方法
答案
完全可以通过反射实现该需求,核心需要额外处理泛型集合类型的实际类型解析,你之前写的单类JsonProperty匹配逻辑可以直接复用,只需要补全嵌套类型、泛型类型的解析步骤即可。
实现思路
整体逻辑和你当前匹配MyClass字段的逻辑一致,只需要额外加两步处理:
- 匹配到字段后先判断字段类型,如果是带泛型的集合类型(比如
List<SecondClass>),通过Java反射的泛型API解析出集合元素的实际类型 - 拿到嵌套类/集合元素类的Class对象后,复用相同的JsonProperty匹配逻辑,就能定位到对应类的字段、getter或setter方法
具体实现步骤
- 先封装一个通用工具方法,输入目标Class和要匹配的JsonProperty值,返回匹配到的Field对象:
private Field getFieldByJsonProperty(Class<?> clazz, String jsonPropValue) { for (Field field : clazz.getDeclaredFields()) { JsonProperty annotation = field.getAnnotation(JsonProperty.class); if (annotation != null && annotation.value().equals(jsonPropValue)) { field.setAccessible(true); return field; } } throw new IllegalArgumentException("未找到对应JsonProperty的字段:" + jsonPropValue); }
- 针对你举的「先匹配
my_list调用getMyList(),再匹配my_name调用setName()」的需求,实现代码如下:
public void accessNestedSetter(MyClass myClass, String newNameVal) throws Exception { // 1. 匹配MyClass中JsonProperty为my_list的字段 Field myListField = getFieldByJsonProperty(MyClass.class, "my_list"); // 2. 调用对应getter拿到List实例(等价于myClass.getMyList()) String listGetterName = "get" + myListField.getName().substring(0,1).toUpperCase() + myListField.getName().substring(1); Method listGetter = MyClass.class.getMethod(listGetterName); List<SecondClass> myList = (List<SecondClass>) listGetter.invoke(myClass); // 按需处理空值:如果list为null就初始化后通过setter赋值回去 if (myList == null) { myList = new ArrayList<>(); String listSetterName = "set" + myListField.getName().substring(0,1).toUpperCase() + myListField.getName().substring(1); Method listSetter = MyClass.class.getMethod(listSetterName, List.class); listSetter.invoke(myClass, myList); } // 3. 解析List的泛型参数,拿到元素实际类型SecondClass ParameterizedType listGenericType = (ParameterizedType) myListField.getGenericType(); Class<?> elementClass = (Class<?>) listGenericType.getActualTypeArguments()[0]; // 4. 在SecondClass中匹配JsonProperty为my_name的字段 Field nameField = getFieldByJsonProperty(elementClass, "my_name"); // 5. 调用对应setter给每个元素赋值(等价于secondClass.setName(newNameVal)) String nameSetterName = "set" + nameField.getName().substring(0,1).toUpperCase() + nameField.getName().substring(1); Method nameSetter = elementClass.getMethod(nameSetterName, String.class); for (SecondClass element : myList) { nameSetter.invoke(element, newNameVal); } }
注意事项
- 如果不需要严格遵循JavaBean规范调用getter/setter,可以直接通过
Field.get()/Field.set()操作字段值,代码会更简洁,效果和调用getter/setter一致 - 如果字段不是集合类型,是普通的嵌套对象(比如直接定义
private SecondClass secondObj),不需要解析泛型,直接调用field.getType()就能拿到嵌套类的Class对象 - 如果需要处理多层嵌套(比如SecondClass里还持有带@JsonProperty的第三层类对象),把上述匹配字段、解析类型的逻辑封装成递归方法即可
- 调用setter或者直接给字段赋值时要注意类型匹配,比如
my_name是String类型就传入字符串,其他类型需要提前做类型转换
内容的提问来源于stack exchange,提问作者mang4521
相关产品推荐
相关产品推荐

