java运行时添加注解
最近工作的时候发现项目里的entity类需要加JPA的@Table和@Column注解,但是都得手动加。我总结了一下,加的注解name都是把java的upper camel case改成lower underscore case, 然后我就行,这么规律的事情,是人干的吗?于是就像能不能让程序在运行的时候自动加上注解,于是经过我的一番折腾,终于实现了这个功能。用的就是大名鼎鼎的Byte Byddy.
最近工作的时候发现项目里的entity类需要加JPA的@Table和@Column注解,但是都得手动加。我总结了一下,加的注解name都是把java的upper camel case
改成lower underscore case
, 然后我就想,这么规律的事情,是人干的吗?于是就想能不能让程序在运行的时候自动加上注解,于是经过我的一番折腾,终于实现了这个功能。用的就是大名鼎鼎的Byte Buddy.
简介
Byte Buddy 是一个代码生成和操作库,用于在 Java 应用程序运行时创建和修改 Java 类,无需编译器的帮助。除了Java 类库附带的代码生成实用程序,Byte Buddy 允许创建任意类,并且不限于实现用于创建运行时代理的接口。此外,Byte Buddy 提供了一个方便的 API,用于手动、使用 Java 代理或在构建期间更改类。这个工具目前是用过的字节码操作最舒服的工具了。
具体实现
- 先添加依赖
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.10.20</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>1.11.0</version>
</dependency>
- 在jvm上安装代理
ByteBuddy byteBuddy=new ByteBuddy();
ByteBuddyAgent.install();
- 重新定义类
其中class就是需要重新定义的类
DynamicType.Builder builder=byteBuddy.redefine(clazz);
定义注解
AnnotationDescription.Builder tableAnnotationBuilder= AnnotationDescription.Builder.ofType(Table.class);
添加注解
builder = builder.annotateType(tableAnnotationBuilder.define("name",tableName).build());
生成新的类,然后加载
builder.make().load(Thread.currentThread().getContextClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
注意: builder连续添加注解时,必须要写成builder = builder.annotateType(), 因为builder每调用一次方法,builder的值都会发生改变,所以每次都要复制给原来的builder.
超级简单有木有,只能说这种API用着太舒服
以下是完整代码,完全可以复制直接用
@Component
//public class JpaAnnotationProcessor implements ApplicationRunner {
public class JpaAnnotationProcessor{
//@Autowired
//THtCMapper tHtCMapper;
private static final Logger logger= LoggerFactory.getLogger(JpaAnnotationProcessor.class);
private static Converter<String,String> lc2LuConverter=
CaseFormat.LOWER_CAMEL.converterTo(CaseFormat.LOWER_UNDERSCORE);
private static Converter<String,String> uc2LuConverter=
CaseFormat.UPPER_CAMEL.converterTo(CaseFormat.LOWER_UNDERSCORE);
private static void addAnnotation(List<Class> classes, ByteBuddy byteBuddy){
for(Class clazz:classes){
boolean redefine=false;
DynamicType.Builder builder=byteBuddy.redefine(clazz);
if(!containsAnnotation(clazz, Table.class)){
AnnotationDescription.Builder tableAnnotationBuilder= AnnotationDescription.Builder.ofType(Table.class);
String tableName=uc2LuConverter.convert(clazz.getSimpleName());
builder = builder.annotateType(tableAnnotationBuilder.define("name",tableName).build());
logger.info("给类:{}添加table注解",clazz.getName());
redefine=true;
}
Field[] fields = clazz.getDeclaredFields();
for(Field field:fields){
Class annotationType;
if(field.getName().equals("id")){
annotationType= Id.class;
} else {
annotationType= Column.class;
}
if(!containsAnnotation(field,annotationType)){
AnnotationDescription.Builder columnAnnotationBuilder= AnnotationDescription.Builder.ofType(annotationType);
if(!field.getName().equals("id")){
columnAnnotationBuilder= columnAnnotationBuilder.define("name", lc2LuConverter.convert(field.getName()));
}
builder = builder.field((ElementMatcher<FieldDescription>) target -> target.getName().equals(field.getName()))
.annotateField(columnAnnotationBuilder.build());
redefine=true;
logger.info("给类{}的{}添加注解{}",clazz.getName(),field.getName(),annotationType.getName());
}
}
if(redefine){
builder.make().load(Thread.currentThread().getContextClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
}
}
}
private static boolean containsAnnotation(Field field,Class annotationType){
return containsAnnotation(field.getAnnotations(),annotationType);
}
private static boolean containsAnnotation(Class clazz,Class annotationType){
return containsAnnotation(clazz.getAnnotations(),annotationType);
}
private static boolean containsAnnotation(Annotation[] srcAnnotations, Class annotationType){
boolean result=false;
for(Annotation srcAnnotation:srcAnnotations){
if(annotationType.equals(srcAnnotation.annotationType())){
result=true;
break;
}
}
return result;
}
private static void printAnnotations(Class clazz){
List<Field> fields= Arrays.asList(clazz.getDeclaredFields());
fields.forEach(field -> {
System.out.println(field.getName()+" annotations:");
Annotation[] fieldAnnotations = field.getAnnotations();
for (Annotation annotation : fieldAnnotations) {
System.out.println(annotation);
}
});
System.out.println("class annotations:");
System.out.println(Arrays.asList(clazz.getAnnotations()));
}
}
更多推荐
所有评论(0)