美文网首页
Javassist创建POJO类

Javassist创建POJO类

作者: onmeiei | 来源:发表于2022-10-16 17:56 被阅读0次

    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 +
                        '}';
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Javassist创建POJO类

          本文链接:https://www.haomeiwen.com/subject/wvsdzrtx.html