泛型编译报错排查记录

记录一次应用升级过程中遇到的编译报错问题,升级完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 gen(Class eventType) throws Exception {}

该方法如果返回类型为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();
    }
}
posted @ 2021-11-07 14:10  wykCN  阅读(124)  评论(0编辑  收藏  举报