2016-10-16 15 views
0

ASM Frameworkを使用して動的にサブクラスを作成しようとしています。 クラスを作成してインスタンス化できました。私はASM動的サブクラスの作成 - NoClassDefFoundError BeanInfo

org.apache.commons.beanutils.BeanUtils.copyProperties(processedEntity, entity); 

をしようとするとき、それは、この例外がスローされます。

java.lang.NoClassDefFoundError: com/wheelsup/app/benefits/service/XpOWErhNBiBeanInfo (wrong name: com/wheelsup/app/benefits/service/XpOWErhNBi) 

ここで私は、サブクラスを作成するために使用していたコードがあります:

Class<? extends T> get() throws Exception { 
    String superClassInternalName = getInternalName(superClass); 

    String subClassSimpleName = RandomStringUtils.random(10, true, false); 
    String subClassInternalName = getClass().getPackage().getName().replaceAll("\\.", "/").concat("/").concat(subClassSimpleName); 
    String subClassName = getClass().getPackage().getName().concat(".").concat(subClassSimpleName); 

    ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 
    classWriter.visit(Opcodes.V1_6, 
      ACC_PUBLIC, 
      subClassInternalName, 
      null, 
      superClassInternalName, 
      null); 

    visitDefaultConstructor(classWriter, superClassInternalName); 

    classWriter.visitEnd(); 

    return SubClassLoader.<T>init().load(classWriter.toByteArray(), subClassName); 
} 

private void visitDefaultConstructor(ClassWriter classWriter, String superClassInternalName) { 
    MethodVisitor methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 
    methodVisitor.visitCode(); 
    methodVisitor.visitVarInsn(ALOAD, 0); 
    methodVisitor.visitMethodInsn(INVOKESPECIAL, superClassInternalName, "<init>", "()V"); 
    methodVisitor.visitInsn(RETURN); 
    methodVisitor.visitMaxs(0, 0); 
    methodVisitor.visitEnd(); 
} 

private static class SubClassLoader<T> { 
    private final ClassLoader contextClassLoader; 

    private SubClassLoader(ClassLoader contextClassLoader) { 
     this.contextClassLoader = contextClassLoader; 
    } 

    static <U> SubClassLoader<U> init() { 
     return new SubClassLoader<>(Thread.currentThread().getContextClassLoader()); 
    } 

    @SuppressWarnings("unchecked") 
    Class<? extends T> load(byte[] classBytes, String className) throws Exception { 
     return (Class<? extends T>) new SubClassLoader.DynamicClassLoader(contextClassLoader, classBytes).loadClass(className); 
    } 

    private static class DynamicClassLoader extends ClassLoader { 
     private byte[] rawClassBytes; 

     private DynamicClassLoader(ClassLoader contextClassLoader, byte[] classBytes) { 
      super(contextClassLoader); 
      this.rawClassBytes = classBytes; 
     } 

     @Override 
     public Class findClass(String name) { 
      return defineClass(name, this.rawClassBytes, 0, this.rawClassBytes.length); 
     } 
    } 
} 

私は理解していませんBeanInfo事;それは何ですか?どうすれば問題を解決できますか?

ありがとうございました。

答えて

0

にありました。いくつかの状況では、クラスの読み込みに失敗すると、操作を行うのが適切です。

BeanUtilsクラスが検査クラスの実装のBeanInfoオプションの明示的なことができますIntrospectorに依存しているFooBeanInfoを求められるので、もし、それが最初のクラスFooBeanInfoをロードしようとすると、これが失敗した場合、それが構築されますFooの汎用ビーン情報

しかし、あなたのfindClass実装が(再)間違った名前XpOWErhNBiBeanInfoの代わりXpOWErhNBiBeanInfoの不在を報告する下XpOWErhNBiクラスを構築しようとするので、物事がうまくいきません。

SubClassLoaderを変更して、生成されるクラスの予想される名前を受け取る必要があります。その後、あなたはシンプルな、しかしハック、解決策は、ファーストクラスの建設後rawClassBytesnullになり

@Override 
public Class findClass(String name) throws ClassNotFoundException { 
    if(!name.equals(expectedName)) 
     throw new ClassNotFoundException(name); 
    return defineClass(name, this.rawClassBytes, 0, this.rawClassBytes.length); 
} 

からfindClass実装を変更し、継承された標準loadClassとして後続の各クラスのロード要求のClassNotFoundExceptionを投げることができます実装はまだロードされていないクラスに対してのみfindClassを呼び出すことを保証します。したがって、生成されたクラスをすぐにロードするプログラムロジックが変更されない限り、すべての後続の要求はサポートされていない異なるクラスです。

しかし、重要な点はプログラムのロジックを変更してはならないということなので、私はハッキーで脆弱な解決法を推奨しません。生成されたクラスの名前をカスタムローダに渡して検証しますが、最初はもう少しコードですが、はるかにクリーンです。

+0

ありがとうHolger! ByteBuddy Frameworkで使用されていたClassLoaderインプラントを見てから、解決策を見つけました。 – arammal

0

ので、問題は、問題があなたのfindClass実装にかかわらず、呼び出し側が要求するためにどのクラスの、1つの生成されたクラスを返すようにしようということであるクラスローダ

private static class SubClassLoader<T> { 
    private final ClassLoader contextClassLoader; 

    private SubClassLoader(ClassLoader contextClassLoader) { 
     this.contextClassLoader = contextClassLoader; 
    } 

    static <U> SubClassLoader<U> init() { 
     return new SubClassLoader<>(Thread.currentThread().getContextClassLoader()); 
    } 

    @SuppressWarnings("unchecked") 
    Class<? extends T> load(byte[] classBytes, String className) throws Exception { 
     return (Class<? extends T>) new DynamicClassLoader(contextClassLoader, classBytes, className).loadClass(className); 
    } 

    private static class DynamicClassLoader extends ClassLoader { 
     private byte[] classBytes; 
     private final String className; 

     private DynamicClassLoader(ClassLoader contextClassLoader, byte[] classBytes, String className) { 
      super(contextClassLoader); 
      this.classBytes = classBytes; 
      this.className = className; 
     } 

     @Override 
     public Class findClass(String className) throws ClassNotFoundException { 
      if (StringUtils.equals(this.className, className)) { 
       return defineClass(className, this.classBytes, 0, this.classBytes.length); 
      } 

      throw new ClassNotFoundException(className); 
     } 
    } 
} 
関連する問題