记录一次应用升级过程中遇到的编译报错问题,升级完pom文件后一直报错:'incompatible types error'
记录一次代码泛型使用导致的编译错误问题排查,问题发生在一次系统升级pom文件过程中,中间无代码变更
泛型资料:http://zjwave.com/article/32.html
https://dunwu.github.io/javacore/basics/java-generic.html
出问题部分代码:
//代码调用入口
/**
*
* public static UntypedStateMachineBuilder create(Class<? extends UntypedStateMachine> stateMachineClazz) {
return create(stateMachineClazz, new Class[0]);
}
*
*/
builder = StateMachineBuilderFactory.create(generator.gen(eventClass));
//实现部分的接口定义
public interface Generator {
<T extends Enum,C extends UntypedStateMachine> Class<C> gen(Class<T> eventType) throws Exception;
}
//实现类##出错部分代码##
//出错代码段:return cc.toClass();
/**编译报错内容:[ERROR] /Users/ykwoo001/Documents/work/codes/pay-hvp/pay-hvp-common/src/main/java/com/youzan/pay/hvp/common/sm/generator/JavassistGenerator.java:[41,26] 不兼容的类型: java.lang.Class<ca1, 共 ?>无法转换为java.lang.Class<C>
**/
public class JavassistGenerator implements Generator {
@Override
public <T extends Enum,C extends UntypedStateMachine> Class<C> gen(Class<T> eventType) throws Exception {
ClassPool pool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(this.getClass());
pool.insertClassPath(classPath);
CtClass cc = pool.makeClass(eventType.getName() + "$StateMachine");
ClassFile ccFile = cc.getClassFile();
ConstPool constPool = ccFile.getConstPool();
//继承
cc.setSuperclass(pool.get("com.youzan.pay.hvp.common.sm.generator.AbstractStateMachineExt"));
// 添加类注解
AnnotationsAttribute bodyAttr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
Annotation bodyAnnot = new Annotation("org.squirrelframework.foundation.fsm.annotation.StateMachineParameters", constPool);
bodyAnnot.addMemberValue("stateType", new ClassMemberValue("java.lang.String", constPool));
bodyAnnot.addMemberValue("eventType", new ClassMemberValue(eventType.getName(), constPool));
bodyAnnot.addMemberValue("contextType", new ClassMemberValue(BizContextParam.class.getName(), constPool));
bodyAttr.addAnnotation(bodyAnnot);
ccFile.addAttribute(bodyAttr);
return cc.toClass();
}
}
问题产生原因分析
知识点:
1、泛型在java中应用场景有如下几种
- 简单泛型
- 如:类中某个对象定义为泛型对象,支持传入不同类型对象进行使用
- 泛型接口
- 类似简单泛型,指泛型定义的类型在接口上描述,实现类也会支持泛型的能力
- 泛型方法
- 指在方法参数和返回值上描述泛型,针对方法作用范围使用的泛型
- 语法格式:public
T func(T obj) {}
2、以上代码报错分析
根据方法描述:
public <T extends Enum,C extends UntypedStateMachine> Class
该方法如果返回类型为Class那么编译应该是能正常编译的:
这里本地模拟之后有如下发现:
public interface GenTargetObj {
<C extends TargetObject> Class<C> gen();
Class<?> gen1();
}
public class JavassistGeneratorTargetObj implements GenTargetObj{
@Override
public <C extends TargetObject> Class<C> gen() {
Class clazz = null;
return clazz;
// return gen1(); 如果代码使用这段逻辑的话就会编译错误 class<?> 不匹配Class<C extends TargetObject>
}
@Override
public Class<?> gen1() {
Class clazz = null;
return clazz;
}
}
总结:
问题根源在return cc.toClass(); 这段代码,为什么这里没有做代码变更只是变更pom文件就报错的点在于,CtClass.toClass()方法由原来的返回Class(javasist 3.20)变为了返回Class<?>(javasist 3.24)版本变更后变更代码成如下形式就好了:
//调用入口(增加类型强转)
//这里将类型转换放到运行时去执行
builder = StateMachineBuilderFactory.create(
(Class<? extends UntypedStateMachine>) generator.gen(eventClass));
//针对Class<?>的类型定义
public interface Generator {
<T extends Enum> Class<?> gen(Class<T> eventType) throws Exception;
}
//实现部分
public class JavassistGenerator implements Generator {
@Override
public <T extends Enum> Class<?> gen(Class<T> eventType) throws Exception {
ClassPool pool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(this.getClass());
pool.insertClassPath(classPath);
CtClass cc = pool.makeClass(eventType.getName() + "$StateMachine");
ClassFile ccFile = cc.getClassFile();
ConstPool constPool = ccFile.getConstPool();
//继承
cc.setSuperclass(pool.get("com.youzan.pay.hvp.common.sm.generator.AbstractStateMachineExt"));
// 添加类注解
AnnotationsAttribute bodyAttr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
Annotation bodyAnnot = new Annotation("org.squirrelframework.foundation.fsm.annotation.StateMachineParameters", constPool);
bodyAnnot.addMemberValue("stateType", new ClassMemberValue("java.lang.String", constPool));
bodyAnnot.addMemberValue("eventType", new ClassMemberValue(eventType.getName(), constPool));
bodyAnnot.addMemberValue("contextType", new ClassMemberValue(BizContextParam.class.getName(), constPool));
bodyAttr.addAnnotation(bodyAnnot);
ccFile.addAttribute(bodyAttr);
return cc.toClass();
}
}