使用javassist时 classPool.get 时报错 javassist.NotFoundException 解决。

今天在用javassist 这个库的时候遇到了一些问题。
调试发现在此行代码处会 报错 javassist.NotFoundException
但是正常 import 的时候并不会报错。然后我找到了以下三种解决方法。

import com.fasterxml.jackson.databind.node.BaseJsonNode;

ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");

方法一

使用appendClassPath 导入响应jar包或者class文件。

ClassPool classPool = ClassPool.getDefault();
classPool.appendClassPath("/Users/taoyu/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.15.3/jackson-databind-2.15.3.jar");
CtClass ctClass = classPool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");

方法二

ClassPool classPool = ClassPool.getDefault();
classPool.insertClassPath(new ClassClassPath(BaseJsonNode.class));
CtClass ctClass = classPool.get(BaseJsonNode.class.getName());
// 或者下面这个也可以
// CtClass ctClass = classPool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");

方法三

ClassPool classPool = ClassPool.getDefault();
ClassPool.getDefault().appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader()));
CtClass ctClass = classPool.get("com.fasterxml.jackson.databind.node.BaseJsonNode");

报错具体原因不详,感觉应该是版本问题。欢迎大家讨论。

参考文章

https://blog.csdn.net/2201_75528722/article/details/133093643
https://stackoverflow.com/questions/23652765/classpool-get-throwing-notfoundexception-on-class-that-clearly-exists
https://blog.csdn.net/weixin_43900321/article/details/105189867

@GetMapping("/get-import-sdn-meter-template") @Operation(summary = "获得小口径水表批量导入模板") public void importSdnMeterTemplate(HttpServletResponse response) throws IOException, NotFoundException, CannotCompileException { List<EquipmentPropertyDO> equipmentPropertyList = equipmentPropertyService.getEquipmentPropertyList(); // 定义新字段 DynamicClassCreator.FieldDefinition newField = new DynamicClassCreator.FieldDefinition("dynamicField", "java.lang.String", "动态列"); // 创建动态子类 Class<?> dynamicClass = DynamicClassCreator.createDynamicSubclass( SdnMeterImportExcelVO.class, "com.example.DynamicChild_" + System.currentTimeMillis(), new DynamicClassCreator.FieldDefinition[]{newField} ); // 手动创建导出 demo List<SdnMeterImportExcelVO> list = Arrays.asList( SdnMeterImportExcelVO.builder().meterCode("cs000001").electronicModuleCode("mk000001").categoryId(3).meterDnId(1) .manufacturerId(1).standardId(1).quality("铁").withValve(true).meterRange(1).productionDate("2024-12-01") .batteryReplacementDate("2025-12-01").serviceLifetimeYears(1).sealNo("001") .withRemoteTransmission(true).communicationMethod(1).simNo("001").imei("001").imsi("001").iccid("001").serviceProvider("运营商1").build()); // 输出 ExcelUtils.write(response, "小口径水表批量导入模版.xlsx", "小口径水表", SdnMeterImportExcelVO.class, list); } 请修改上边代码,使得导出的excel用动态生成的类替换SdnMeterImportExcelVO类,并保持所有注解属性不变,其中类SdnMeterImportExcelVO的源代码为: package cn.iocoder.yudao.module.tdsw.controller.admin.equipment.vo.equipment; import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; import cn.iocoder.yudao.module.tdsw.convert.EquipmentstandardConvert; import cn.iocoder.yudao.module.tdsw.convert.ManufacturerConvert; import cn.iocoder.yudao.module.tdsw.convert.MeterDnConvert; import cn.iocoder.yudao.module.tdsw.convert.TdswEquipmentCategoryConvert; import cn.iocoder.yudao.module.tdsw.framework.excel.core.EquipmentStandardExcelColumnSelectFunction; import cn.iocoder.yudao.module.tdsw.framework.excel.core.ManufacturerExcelColumnSelectFunction; import cn.iocoder.yudao.module.tdsw.framework.excel.core.MeterDnExcelColumnSelectFunction; import cn.iocoder.yudao.module.tdsw.framework.excel.core.TdswEquipmentCategorySdnExcelColumnSelectFunction; import com.alibaba.excel.annotation.ExcelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import static cn.iocoder.yudao.module.tdsw.enums.DictTypeConstants.*; /** * 用户 Excel 导入 VO */ @Data @Builder @AllArgsConstructor @NoArgsConstructor @Accessors(chain = false) // 设置 chain = false,避免导入有问题 public class SdnMeterImportExcelVO { @ExcelProperty("表编号") private String meterCode; @ExcelProperty("电子模块编号") private String electronicModuleCode; @ExcelProperty(value = "表类型", converter = TdswEquipmentCategoryConvert.class) @ExcelColumnSelect(functionName = TdswEquipmentCategorySdnExcelColumnSelectFunction.NAME) private Integer categoryId; @ExcelProperty(value = "表口径", converter = MeterDnConvert.class) @ExcelColumnSelect(functionName = MeterDnExcelColumnSelectFunction.NAME) private Integer meterDnId; @ExcelProperty(value = "厂商名称", converter = ManufacturerConvert.class) @ExcelColumnSelect(functionName = ManufacturerExcelColumnSelectFunction.NAME) private Integer manufacturerId; @ExcelProperty(value = "规格型号", converter = EquipmentstandardConvert.class) @ExcelColumnSelect(functionName = EquipmentStandardExcelColumnSelectFunction.NAME) private Integer standardId; @ExcelProperty("材质") private String quality; @ExcelProperty(value = "是否有阀门",converter = DictConvert.class) @DictFormat(TDSW_WITH_VALVE) @ExcelColumnSelect(dictType = TDSW_WITH_VALVE) private Boolean withValve; @ExcelProperty(value = "表量程",converter = DictConvert.class) @DictFormat(TDSW_METER_RANGE) @ExcelColumnSelect(dictType = TDSW_METER_RANGE) private Integer meterRange; @ExcelProperty("出厂日期") private String productionDate; @ExcelProperty("更换电池最后期限") private String batteryReplacementDate; @ExcelProperty("服务年限") private Integer serviceLifetimeYears; @ExcelProperty("铅封号") private String sealNo; @ExcelProperty(value = "是否有远程传输",converter = DictConvert.class) @DictFormat(TDSW_WITH_REMOTE_TRANSMISSION) @ExcelColumnSelect(dictType = TDSW_WITH_REMOTE_TRANSMISSION) private Boolean withRemoteTransmission; @ExcelProperty(value = "通讯方式",converter = DictConvert.class) @DictFormat(TDSW_COMMUNICATION_METHOD) @ExcelColumnSelect(dictType = TDSW_COMMUNICATION_METHOD) private Integer communicationMethod; @ExcelProperty("SIM卡号") private String simNo; @ExcelProperty("IMEI") private String imei; @ExcelProperty("IMSI") private String imsi; @ExcelProperty("ICCID") private String iccid; @ExcelProperty("运营商") private String serviceProvider; } 其中DynamicClassCreator的源代码为: package cn.iocoder.yudao.module.tdsw.utils; import javassist.*; import javassist.bytecode.AnnotationsAttribute; import javassist.bytecode.ClassFile; import javassist.bytecode.ConstPool; import javassist.bytecode.annotation.Annotation; import javassist.bytecode.annotation.StringMemberValue; import java.lang.reflect.Field; import java.util.Arrays; import com.alibaba.excel.annotation.ExcelProperty; public class DynamicClassCreator { public static Class<?> createDynamicSubclass(Class<?> superClass, String newClassName, FieldDefinition[] newFields) throws NotFoundException, CannotCompileException { // 1. 初始化ClassPool ClassPool pool = ClassPool.getDefault(); // 2. 创建新类并设置父类 CtClass ctChildClass = pool.makeClass(newClassName); ctChildClass.setSuperclass(pool.get(superClass.getName())); // 3. 复制父类所有字段(包括注解) copyFieldsFromParent(superClass, ctChildClass, pool); // 4. 添加新字段及注解 for (FieldDefinition fieldDef : newFields) { addFieldWithAnnotation(ctChildClass, fieldDef, pool); } // 5. 生成并返回Class对象 return ctChildClass.toClass(); } // 复制父类字段(保留注解) private static void copyFieldsFromParent(Class<?> superClass, CtClass ctChildClass, ClassPool pool) throws NotFoundException, CannotCompileException { // 遍历所有父类字段(包括私有字段) for (Field field : superClass.getDeclaredFields()) { try { CtField ctField = CtField.make( String.format("private %s %s;", field.getType().getName(), field.getName()), ctChildClass ); // 复制字段注解 ConstPool constPool = ctChildClass.getClassFile().getConstPool(); AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag); Arrays.stream(field.getDeclaredAnnotations()) .forEach(ann -> { Annotation javassistAnn = new Annotation(ann.annotationType().getName(), constPool); // 这里可扩展:复制注解参数(简化版仅处理注解类型) attr.addAnnotation(javassistAnn); }); if (attr.numAnnotations() > 0) { ctField.getFieldInfo().addAttribute(attr); } ctChildClass.addField(ctField); } catch (Exception e) { throw new CannotCompileException("Failed to copy field: " + field.getName(), e); } } } // 添加带注解的新字段 private static void addFieldWithAnnotation(CtClass ctChildClass, FieldDefinition fieldDef, ClassPool pool) throws CannotCompileException { try { // 创建字段 CtField ctField = new CtField( pool.get(fieldDef.type), fieldDef.name, ctChildClass ); ctField.setModifiers(Modifier.PRIVATE); // 添加@ExcelProperty注解 ConstPool constPool = ctChildClass.getClassFile().getConstPool(); AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag); Annotation excelProperty = new Annotation(ExcelProperty.class.getName(), constPool); // 设置注解参数(例如value) excelProperty.addMemberValue("value", new StringMemberValue(fieldDef.excelHeader, constPool)); attr.addAnnotation(excelProperty); ctField.getFieldInfo().addAttribute(attr); ctChildClass.addField(ctField); } catch (NotFoundException e) { throw new CannotCompileException("Invalid field type: " + fieldDef.type, e); } } // 新字段定义结构 public static class FieldDefinition { String name; String type; String excelHeader; // @ExcelProperty注解的header值 public FieldDefinition(String name, String type, String excelHeader) { this.name = name; this.type = type; this.excelHeader = excelHeader; } } }
最新发布
06-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值