Javassist创建POJO类,需要关注两个地方,第一个是Getter和Setter方法的构建:
javassist.CtNewMethod#setter
,示例:
CtClass typeClass = classes.get(fieldType.getType());
CtField ctField = new CtField(typeClass, fieldName, ctClass);
ctField.setModifiers(Modifier.PRIVATE);
String camelFieldName = fieldName.toUpperCase().charAt(0) + fieldName.substring(1);
CtMethod setter = CtNewMethod.setter("set" + camelFieldName, ctField);
CtMethod getter = CtNewMethod.getter("get" + camelFieldName, ctField);
ctClass.addField(ctField);
ctClass.addMethod(setter);
ctClass.addMethod(getter);
第二个地方就是,如果是容器类(例如:List、Map)时,它的genericSignature的获取。
如果不设置GenericSignature,将反射将无法获取genericType,会影响反序列化(例如:json、mybatis、jdbctemplate等等)。
设置GenericSignature使用:javassist.CtField#setGenericSignature
示例:
String sig = "Ljava/util/List<Ljava/lang/String;>;";
CtClass ctClass = classPool.makeClass("flow.A");
CtClass fileType = classPool.get("java.util.List");
CtField ctField = new CtField(fileType, "name", ctClass);
ctField.setGenericSignature(sig);
ctField.setModifiers(Modifier.PRIVATE);
ctClass.addField(ctField);
可以看到GenericSignatureLjava/util/List<Ljava/lang/String;>;
是一个有特殊规则的字符串,接下来就需要构建GenericSignature。
构建GenericSignature,主要使用:javassist.bytecode.SignatureAttribute.ObjectType#encode
示例:
class Sample {
private final Set<String> basicTypes;
private final Set<String> collectionTypes;
public BeanDefines() {
basicTypes = Set.of("String", "Boolean", "Integer", "Double");
collectionTypes = Set.of("List", "Map");
}
public void addField(CtClass ctClass, FieldType fieldType) {
final ClassPool classPool = ClassPool.getDefault();
try {
CtClass typeClass = classPool.makeClass(fieldType.getType(), baseBean);
CtField ctField = new CtField(typeClass, fieldName, ctClass);
ClassType genericSignature = computeClassType(fieldType);
ctField.setGenericSignature(genericSignature.encode());
ctField.setModifiers(Modifier.PRIVATE);
String camelFieldName = fieldName.toUpperCase().charAt(0) + fieldName.substring(1);
CtMethod setter = CtNewMethod.setter("set" + camelFieldName, ctField);
CtMethod getter = CtNewMethod.getter("get" + camelFieldName, ctField);
ctClass.addField(ctField);
ctClass.addMethod(setter);
ctClass.addMethod(getter);
} catch (CannotCompileException e) {
throw new IllegalArgumentException("Failed to create field(%s) of bean(%s)".formatted(fieldName, beanName), e);
}
}
private ClassType computeClassType(FieldType fieldType) {
String type = fieldType.getType();
if (this.basicTypes.contains(type)) {
return new ClassType("java.lang." + type);
}
if (this.collectionTypes.contains(type)) {
List<FieldType> parameters = fieldType.getParameters();
List<TypeArgument> types = new ArrayList<>();
for (FieldType parameter : parameters) {
types.add(new TypeArgument(computeClassType(parameter)));
}
return new ClassType("java.util." + type, types.toArray(new TypeArgument[0]));
}
return new ClassType(baseClass.getPackageName() + "." + type);
}
private static class FieldType {
private String type;
private List<FieldType> parameters;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<FieldType> getParameters() {
return parameters;
}
public void setParameters(List<FieldType> parameters) {
this.parameters = parameters;
}
@Override
public String toString() {
return "FieldType{" +
"type='" + type + '\'' +
", parameters=" + parameters +
'}';
}
}
}
网友评论