• 泛型编译报错排查记录


    记录一次应用升级过程中遇到的编译报错问题,升级完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();
        }
    }
    
  • 相关阅读:
    RMAN01009: syntax error: found "dot" 解决方法
    Oracle 11g 新特性 DB_ULTRA_SAFE 参数 说明
    Oracle 11g 新特性 Result Cache(结果高速缓存)说明
    Oracle 11g 新特性 DB_ULTRA_SAFE 参数 说明
    /dev/sdxx is apparently in use by the system; will not make a filesystem here! 解决方法
    CSDN博客之星 投票说明
    Oracle 11g 新特性 – ACFS 说明
    Oracle 与 iptables 和 SELinux 禁用关系 说明
    Vbox 安装 windows Server 2008 R2 报错 Info: An unexpected error has occurred 解决方法
    Oracle 11g 新特性 SecureFiles 说明
  • 原文地址:https://www.cnblogs.com/wykCN/p/15519795.html
Copyright © 2020-2023  润新知