2

デフォルトのコンストラクターを持たないクラスに対して、cglib を使用してサブクラスを生成する必要があります。デフォルトのコンストラクターを持つクラスで正常に機能する次のコードがあります。

    Enhancer enhancer = new Enhancer();
    enhancer.setCallbackType(NoOp.class);
    enhancer.setUseCache(false);

    enhancer.setSuperclass(clazz);
    return enhancer.createClass();

新しいクラスには、スーパークラスからデフォルト以外のコンストラクターを呼び出す必要があるデフォルトのコンストラクターが必要です。

検索したところ、cglib ではそのようなことができないため、asm を使用する必要があることがわかりました。ただし、デフォルトのコンストラクターをクラスに追加する例は見つかりませんでした。

誰かがそれを実装する方法の例を持っていれば、それは素晴らしいことです.

4

1 に答える 1

4

私はこの問題を解決しました。以前の想像とは少し違って見えました。Cglibはすべてのコンストラクターを継承し、以前考えていたデフォルトのコンストラクターだけではありません。

ただし、既存のcglibコンストラクター構築コードに影響を与えずにコンストラクターを置き換えることはできないようです。これは小さな意味なので、コンストラクターインジェクションからメソッドインジェクションに移行しました。コンストラクターが戻る直前にメソッド呼び出しを追加しています。そしてこれはうまくいきます!!! とても嬉しいです。

これは私が得たものです:

cglibエンハンサーの呼び出し

Enhancer enhancer = new Enhancer();
        enhancer.setNamingPolicy(new IndexedNamingPolicy());
        enhancer.setCallbackType(NoOp.class);
        enhancer.setUseCache(false);
        enhancer.setStrategy(new DefaultGeneratorStrategy() {
            @Override
            protected ClassGenerator transform(ClassGenerator cg) throws Exception {
                return new TransformingClassGenerator(cg, new DefaultConstructorEmitter(key));
            }
        });

        enhancer.setSuperclass(clazz);
        return enhancer.createClass();

そして私のDefaultConstructorEmitter(それはまだコンストラクター処理のために名前が付けられています、気にしないでください)

private class DefaultConstructorEmitter extends ClassEmitterTransformer {
        private final Signature CALL_SIGNATURE = TypeUtils.parseSignature("void someMethod(Object)");

        private String parametersKey;

        public DefaultConstructorEmitter(final String key) {
            parametersKey = key;
        }

        @Override
        public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) {
            final CodeEmitter emitter = super.begin_method(access, sig, exceptions);
            if (sig.getName().equals(Constants.CONSTRUCTOR_NAME)) {
                return new CodeEmitter(emitter) {
                    @Override
                    public void visitInsn(int arg0) {
                        if (arg0 == Opcodes.RETURN) {
                            Type classType = ...   
                            emitter.load_this();
                            emitter.push(parametersKey);
                            emitter.invoke_static(classType, CALL_SIGNATURE);
                        }
                        super.visitInsn(arg0);
                    }
                };
            }

            return emitter;
        }
    }

この例が、誰かが私のように数時間を費やさないようにするのに役立つことを願っています。

于 2013-02-14T00:19:39.053 に答える