1

同じプロジェクトでplayOrmjunitテストを実行すると、nosql.Persistenceクラス(したがって、マップされたエンティティ)が正常に実行されます。ただし、DAOとfindメソッドを使用して、エンティティをjarファイルにパッケージ化する必要があります。他のプロジェクトからこのdaoを使用すると、次の例外が発生します。

手がかりはありません。どこから探し始めるかについて何か考えはありますか?

java.lang.RuntimeException: Failure scanning class(see chained exception)=class com.alvazan.orm.api.z8spi.meta.DboTableMeta
    at com.alvazan.orm.layer0.base.MyClassAnnotationDiscoveryListener.scanClass(MyClassAnnotationDiscoveryListener.java:44)
    at com.alvazan.orm.layer0.base.MyClassAnnotationDiscoveryListener.discovered(MyClassAnnotationDiscoveryListener.java:34)
    at com.impetus.annovention.Discoverer.discoverAndIntimateForClassAnnotations(Discoverer.java:197)
    at com.impetus.annovention.Discoverer.discover(Discoverer.java:155)
    at com.alvazan.orm.layer0.base.BaseEntityManagerFactoryImpl.rescan(BaseEntityManagerFactoryImpl.java:80)
    at com.alvazan.orm.layer0.base.BaseEntityManagerFactoryImpl.setup(BaseEntityManagerFactoryImpl.java:131)
    at com.alvazan.orm.impl.bindings.BootstrapImpl.createInstance(BootstrapImpl.java:51)
    at com.alvazan.orm.api.base.Bootstrap.create(Bootstrap.java:53)
    at com.alvazan.orm.api.base.Bootstrap.create(Bootstrap.java:48)
    at com.alvazan.orm.api.base.Bootstrap.create(Bootstrap.java:45)
    at com.alvazan.orm.api.base.Bootstrap.create(Bootstrap.java:41)
    at com.s1mbi0se.dmp.da.dao.PlayOrmConfiguration.init(PlayOrmConfiguration.java:40)
    at com.s1mbi0se.dmp.da.dao.PlayOrmConfiguration.getEntityManager(PlayOrmConfiguration.java:46)
    at com.s1mbi0se.dmp.da.dao.AbstractDao.getEm(AbstractDao.java:10)
    at com.s1mbi0se.dmp.da.dao.UserDao.insertOrUpdateUser(UserDao.java:15)
    at com.s1mbi0se.dmp.module.UserModule.persistData(UserModule.java:101)
    at com.s1mbi0se.dmp.processor.mapred.SelectorReducer.reduce(SelectorReducer.java:55)
    at com.s1mbi0se.dmp.processor.mapred.SelectorReducer.reduce(SelectorReducer.java:1)
    at org.apache.hadoop.mapreduce.Reducer.run(Reducer.java:176)
    at org.apache.hadoop.mapred.Task$NewCombinerRunner.combine(Task.java:1502)
    at org.apache.hadoop.mapred.MapTask$MapOutputBuffer.sortAndSpill(MapTask.java:1436)
    at org.apache.hadoop.mapred.MapTask$MapOutputBuffer.flush(MapTask.java:1298)
    at org.apache.hadoop.mapred.MapTask$NewOutputCollector.close(MapTask.java:699)
    at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:766)
    at org.apache.hadoop.mapred.MapTask.run(MapTask.java:370)
    at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:212)
Caused by: com.google.inject.ProvisionException: Guice provision errors:

1) Error injecting constructor, java.lang.ExceptionInInitializerError
  at com.alvazan.orm.impl.meta.data.MetaClassSingle.<init>(MetaClassSingle.java:22)
  while locating com.alvazan.orm.impl.meta.data.MetaClassSingle

1 error
    at com.google.inject.internal.InjectorImpl$4.get(InjectorImpl.java:987)
    at com.alvazan.orm.impl.meta.data.MetaInfo.findOrCreate(MetaInfo.java:60)
    at com.alvazan.orm.impl.meta.scan.ScannerForClass.addClass(ScannerForClass.java:57)
    at com.alvazan.orm.layer0.base.MyClassAnnotationDiscoveryListener.scanClass(MyClassAnnotationDiscoveryListener.java:42)
    ... 25 more
Caused by: java.lang.ExceptionInInitializerError
    at com.alvazan.orm.impl.meta.data.MetaAbstractClass.<init>(MetaAbstractClass.java:17)
    at com.alvazan.orm.impl.meta.data.MetaClassSingle.<init>(MetaClassSingle.java:22)
    at com.alvazan.orm.impl.meta.data.MetaClassSingle$$FastClassByGuice$$29abb300.newInstance(<generated>)
    at com.google.inject.internal.cglib.reflect.$FastConstructor.newInstance(FastConstructor.java:40)
    at com.google.inject.internal.DefaultConstructionProxyFactory$1.newInstance(DefaultConstructionProxyFactory.java:60)
    at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:85)
    at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:254)
    at com.google.inject.internal.InjectorImpl$4$1.call(InjectorImpl.java:978)
    at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1024)
    at com.google.inject.internal.InjectorImpl$4.get(InjectorImpl.java:974)
    ... 28 more
Caused by: java.lang.ClassCastException: com.alvazan.orm.api.z8spi.meta.TypedRow_$$_javassist_0 cannot be cast to javassist.util.proxy.Proxy
    at com.alvazan.orm.api.z8spi.meta.DboTableMeta.testInstanceCreation(DboTableMeta.java:93)
    at com.alvazan.orm.api.z8spi.meta.DboTableMeta.<clinit>(DboTableMeta.java:84)
    ... 38 more
4

1 に答える 1

2

ある種のクラスローディングの問題が発生しました。NoSqlEntityManagerFactoryを作成するときに、クラスローダーを渡す必要がある場合があります。ここでこのコードを扱っています

static {
    ProxyFactory f = new ProxyFactory();
    f.setSuperclass(TypedRow.class);
    f.setInterfaces(new Class[] {NoSqlTypedRowProxy.class});
    f.setFilter(new MethodFilter() {
        public boolean isHandled(Method m) {
            // ignore finalize()
            if(m.getName().equals("finalize"))
                return false;
            else if(m.getName().equals("equals"))
                return false;
            else if(m.getName().equals("hashCode"))
                return false;
            return true;
        }
    });
    Class clazz = f.createClass();
    testInstanceCreation(clazz);

    typedRowProxyClass = clazz;

    NAME_PATTERN = Pattern.compile("[a-zA-Z_][a-zA-Z_0-9]*");
}

private static Proxy testInstanceCreation(Class<?> clazz) {
    try {
        Proxy inst = (Proxy) clazz.newInstance();
        return inst;
    } catch (InstantiationException e) {
        throw new RuntimeException("Could not create proxy for type="+clazz, e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException("Could not create proxy for type="+clazz, e);
    }
}

静的初期化ブロック内にあるため、一度実行されることに注意してください。このコードは、通常の場合は常に機能します。たとえば、あるClassLoaderで作成されたCarクラスがあり、同じCarクラスが別のクラスローダーで作成されている場合、実際にはそのように(Car)carをキャストして、1つのCarであるcarのためにclassCastExceptionを取得できます。クラスローダーは他のクラスローダーの車ではありません。

さて、ステップ1は、NoSqlEntityManagerFactoryを作成するときに独自のクラスローダーを渡してみることです。これにより、どのクラスローダーが使用されているかがわかります。上記のコードを見ると、どのクラスローダーがプロキシを作成しているかはまだわかりません。そのため、同じクラスローダーであることを確認する必要があります。

大きな問題の1つは、hadoopがすでに別のクラスローダーにロードされたjavassistを使用しているかどうか、またはmapreduceジョブの一部としてjavassistを送信したかどうかです。

編集:さて、また、javassistのスレッドコンテキストローダーも設定する必要があります....これはPlayOrmで修正するので、次のリリースでは必要ありません....今のところこれを行う

  1. Thread.currentThread.setContextClassLoader(yourClassloader)を呼び出します
  2. Bootstrap.createを呼び出して、同じクラスローダーも渡します。
  3. javassistが同じクラスローダーからロードされていることを確認します

これは、クラスローダーjavassistが参照用に使用している情報を見つけたコードです。

   protected ClassLoader getClassLoader0() {
591         ClassLoader loader = null;
592         if (superClass != null && !superClass.getName().equals("java.lang.Object"))
593             loader = superClass.getClassLoader();
594         else if (interfaces != null && interfaces.length > 0)
595             loader = interfaces[0].getClassLoader();
596  
597         if (loader == null) {
598             loader = getClass().getClassLoader();
599             // In case javassist is in the endorsed dir
600             if (loader == null) {
601                 loader = Thread.currentThread().getContextClassLoader();
602                 if (loader == null)
603                     loader = ClassLoader.getSystemClassLoader();
604             }
605         }
606 
607         return loader;
608     }

ディーン

于 2012-10-18T15:31:00.320 に答える