public static Mixin mixin()

in dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Mixin.java [83:209]


    public static Mixin mixin(Class<?>[] ics, Class<?>[] dcs, ClassLoader cl) {
        assertInterfaceArray(ics);

        long id = MIXIN_CLASS_COUNTER.getAndIncrement();
        String pkg = null;
        ClassGenerator ccp = null, ccm = null;
        try {
            ccp = ClassGenerator.newInstance(cl);

            // impl constructor
            StringBuilder code = new StringBuilder();
            for (int i = 0; i < dcs.length; i++) {
                if (!Modifier.isPublic(dcs[i].getModifiers())) {
                    String npkg = dcs[i].getPackage().getName();
                    if (pkg == null) {
                        pkg = npkg;
                    } else {
                        if (!pkg.equals(npkg)) {
                            throw new IllegalArgumentException("non-public interfaces class from different packages");
                        }
                    }
                }

                ccp.addField("private " + dcs[i].getName() + " d" + i + ";");

                code.append('d')
                        .append(i)
                        .append(" = (")
                        .append(dcs[i].getName())
                        .append(")$1[")
                        .append(i)
                        .append("];\n");
                if (MixinAware.class.isAssignableFrom(dcs[i])) {
                    code.append('d').append(i).append(".setMixinInstance(this);\n");
                }
            }
            ccp.addConstructor(Modifier.PUBLIC, new Class<?>[] {Object[].class}, code.toString());

            Class<?> neighbor = null;
            // impl methods.
            Set<String> worked = new HashSet<>();
            for (int i = 0; i < ics.length; i++) {
                if (!Modifier.isPublic(ics[i].getModifiers())) {
                    String npkg = ics[i].getPackage().getName();
                    if (pkg == null) {
                        pkg = npkg;
                        neighbor = ics[i];
                    } else {
                        if (!pkg.equals(npkg)) {
                            throw new IllegalArgumentException("non-public delegate class from different packages");
                        }
                    }
                }

                ccp.addInterface(ics[i]);

                for (Method method : ics[i].getMethods()) {
                    if ("java.lang.Object".equals(method.getDeclaringClass().getName())) {
                        continue;
                    }

                    String desc = ReflectUtils.getDesc(method);
                    if (worked.contains(desc)) {
                        continue;
                    }
                    worked.add(desc);

                    int ix = findMethod(dcs, desc);
                    if (ix < 0) {
                        throw new RuntimeException("Missing method [" + desc + "] implement.");
                    }

                    Class<?> rt = method.getReturnType();
                    String mn = method.getName();
                    if (Void.TYPE.equals(rt)) {
                        ccp.addMethod(
                                mn,
                                method.getModifiers(),
                                rt,
                                method.getParameterTypes(),
                                method.getExceptionTypes(),
                                "d" + ix + "." + mn + "($$);");
                    } else {
                        ccp.addMethod(
                                mn,
                                method.getModifiers(),
                                rt,
                                method.getParameterTypes(),
                                method.getExceptionTypes(),
                                "return ($r)d" + ix + "." + mn + "($$);");
                    }
                }
            }

            if (pkg == null) {
                pkg = PACKAGE_NAME;
                neighbor = Mixin.class;
            }

            // create MixinInstance class.
            String micn = pkg + ".mixin" + id;
            ccp.setClassName(micn);
            ccp.toClass(neighbor);

            // create Mixin class.
            String fcn = Mixin.class.getName() + id;
            ccm = ClassGenerator.newInstance(cl);
            ccm.setClassName(fcn);
            ccm.addDefaultConstructor();
            ccm.setSuperClass(Mixin.class.getName());
            ccm.addMethod("public Object newInstance(Object[] delegates){ return new " + micn + "($1); }");
            Class<?> mixin = ccm.toClass(Mixin.class);
            return (Mixin) mixin.getDeclaredConstructor().newInstance();
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            // release ClassGenerator
            if (ccp != null) {
                ccp.release();
            }
            if (ccm != null) {
                ccm.release();
            }
        }
    }