最近在处理用动态修改Retrofit代理Server类的注释过程,想通过反射动态修改@GET/@POST注释后路径地址,
发现在java 8中可以修改,由于项目使用17,提示不可用。
参考文章:https://blog.csdn.net/wu_weijie/article/details/129251045
报错:java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.Map
Exception in thread “main” java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.Map sun.reflect.annotation.AnnotationInvocationHandler.memberValues accessible: module java.base does not “opens sun.reflect.annotation” to unnamed module @6325a3ee
解决方法:
在运行VM options值
–add-opens java.base/sun.reflect.annotation=ALL-UNNAMED
关于–add-opens介绍文章:https://blog.51cto.com/u_16175510/6686606
代码样例:
TestController类
public class TestController {
public static void main(String[] args) throws Exception {
TestController retrofitTestController = new TestController();
retrofitTestController.changeBaseUrl();
}
@SneakyThrows
public static <T extends Annotation> void setValueToAnnotate(T annotation, String valueName, Object value) {
InvocationHandler invocationHandler = null;
if (Objects.nonNull(annotation)) {
invocationHandler = Proxy.getInvocationHandler(annotation);
}
if (Objects.isNull(invocationHandler)) {
return;
}
/**
*class AnnotationInvocationHandler implements InvocationHandler, Serializable {
* @java.io.Serial
* private static final long serialVersionUID = 6182022883658399397L;
* private final Class<? extends Annotation> type;
* @SuppressWarnings("serial") // Not statically typed as Serializable
* private final Map<String, Object> memberValues;
*/
Field nameField = invocationHandler.getClass().getDeclaredField("memberValues");
nameField.setAccessible(true);
Map<String, Object> memberValues = (Map<String, Object>) nameField.get(invocationHandler);
memberValues.put(valueName, value);
}
public void changeBaseUrl() throws Exception {
//获取对方指定方法
Method sMethod = GitHubService.class.getDeclaredMethod("listRepos", String.class);
System.out.println("方法名:"+sMethod.getName());
if (sMethod.isAnnotationPresent(GET.class)) {
GET annotation = sMethod.getAnnotation(GET.class);
System.out.println("注释内容:"+annotation.value());
TestController.setValueToAnnotate(annotation, "value", "users/v2/{user}/repos");
System.out.println("修改后注释内容:"+annotation.value());
}else{
System.out.println("不存在GET注释。。");
}
}
}
GitHubService.java
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Object>> listRepos(@FieldMap @Path("user") String user);
}