Я работаю в проекте, который использует mapperdao library .
Иногда он генерирует исключение, которое предполагает, что библиотека не является поточно-ориентированной. Я не мог понять, почему, хотя.
Проблема возникает в этот код :
type CacheKey = (Class[_], LazyLoad)
private val classCache = new scala.collection.mutable.HashMap[CacheKey, (Class[_], Map[String, ColumnInfoRelationshipBase[_, Any, Any, Any]])]
def proxyFor[ID, T](constructed: T with Persisted, entity: EntityBase[ID, T], lazyLoad: LazyLoad, vm: ValuesMap): T with Persisted = {
(...)
val key = (clz, lazyLoad)
// get cached proxy class or generate it
val (proxyClz, methodToCI) = classCache.synchronized {
classCache.get(key).getOrElse {
val methods = lazyRelationships.map(ci =>
ci.getterMethod.getOrElse(
throw new IllegalStateException("please define getter method on entity %s . %s".format(entity.getClass.getName, ci.column))
).getterMethod
).toSet
if (methods.isEmpty)
throw new IllegalStateException("can't lazy load class that doesn't declare any getters for relationships. Entity: %s".format(clz))
val proxyClz = createProxyClz(constructedClz, clz, methods)
val methodToCI = lazyRelationships.map {
ci =>
(ci.getterMethod.get.getterMethod.getName, ci.asInstanceOf[ColumnInfoRelationshipBase[T, Any, Any, Any]])
}.toMap
val r = (proxyClz, methodToCI)
classCache.put(key, r)
r
}
}
val instantiator = objenesis.getInstantiatorOf(proxyClz)
val instance = instantiator.newInstance.asInstanceOf[DeclaredIds[ID] with T with MethodImplementation[T with Persisted]]
(...)
}
instantiator.newInstance
создает java.lang.NoClassDefFoundError
для класса, который должен быть динамически скомпилирован, а его имя помещено на карту.
Этот код мне кажется поточно-ориентированным, так как любая операция на карте выполняется в синхронизированном блоке. Не могу понять сценарий, когда карта возвращает имя класса, которое еще не сгенерировано и не скомпилировано. Я что-то упустил?
Еще одно объяснение состоит в том, что класс скомпилирован, но он не виден текущему загрузчику классов. Хотя я не знаю, как это может случиться и почему это происходит иногда.
UPDATE:
Трасса выглядит следующим образом:
java.lang.NoClassDefFoundError: Could not initialize class com.mypackage.MyClass_$2
at sun.reflect.GeneratedSerializationConstructorAccessor57.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:56)
at com.googlecode.mapperdao.lazyload.LazyLoadManager.proxyFor(LazyLoadManager.scala:63)
at com.googlecode.mapperdao.jdbc.impl.MapperDaoImpl.lazyLoadEntity(MapperDaoImpl.scala:338)
at com.googlecode.mapperdao.jdbc.impl.MapperDaoImpl.$anonfun$toEntities$5(MapperDaoImpl.scala:301)
at com.googlecode.mapperdao.internal.EntityMap.$anonfun$get$1(EntityMap.scala:46)
ОБНОВЛЕНИЕ 2: я наконец нашел основную причину своей проблемы. Это действительно проблема параллелизма, но не в коде, который я вставил. Это в MImpl класс .
Здесь происходит то, что динамически генерируемый класс компилируется правильно, но иногда его инициализация завершается ошибкой из-за проблемы параллелизма в MImpl class . В следующий раз, когда код пытается создать экземпляр класса, в итоге возникает исключение NoClassDefFoundException, выдаваемое JVM.