#generics #scala #morphia #traits
#общие сведения #scala #morphia #Трейты
Вопрос:
Я обнаружил эту проблему при использовании Morphia
в scala. Он проверяет поля класса путем отражения и получает необходимую информацию о типе для сопоставления.
Но если я использую traits
и определю некоторые поля коллекции, информация об общем типе будет потеряна, что приведет к тому, что Morphia не сможет получить достаточно информации и выдаст исключения.
Смотрите мой код:
trait HasTags {
@Reference
var tags: java.util.List[Tag] = new java.util.ArrayList[Tag]() // the generic type is Tag
}
class Question extends Entity with HasTags {
}
Я скомпилировал файл scala и получил несколько файлов классов java. Затем я использую java decompiler, чтобы просмотреть содержимое байтовых кодов java:
public class Question extends Entity implements HasTags {
@Reference
private java.util.List tags;
}
Вы можете видеть, что здесь ее нет Tag
, поэтому Morphia завершится неудачей.
Я использовал scala 2.8.1
. Есть ли какой-нибудь способ это исправить?
Обновить
@extempore сказал, что, возможно, javap
не отображает эту Tag
информацию.
Но я использовал программу под названием Java Decompiler, а не javap
.
Я попробовал этот код:
class Question extends Entity with HasTags {
@Reference
var tags2: java.util.List[Tag] = new java.util.ArrayList()
}
И посмотрите на байтовый код в Java Decompiler
, он отображает:
public class Question extends Entity implements HasTags {
@Reference
private java.util.List tags;
@Reference
private java.util.List<models.Tag> tags2;
}
Мы можем видеть, что tags2
содержит Tag
, но tags
этого не делает.
И интерфейс HasTags
является:
public abstract interface HasTags extends ScalaObject
{
public abstract List<Tag> tags();
@TraitSetter
public abstract void tags_$eq(List<Tag> paramList);
}
Мы можем видеть, что возвращаемое значение метода tags()
равно List<Tag>
, а поле tags
— нет.
Поскольку morphia получает информацию по полям, она не может работать корректно.
Ответ №1:
Вот как javap отображает вещи. Это не означает, что подпись отсутствует.
scala> classOf[HasTags].getMethod("tags").getGenericReturnType
res0: java.lang.reflect.Type = java.util.List<Tag>
Вот откуда вы знаете, что это такое. Вы также можете увидеть это в пуле констант.
const #3 = Asciz tags;
const #4 = Asciz ()Ljava/util/List;;
const #5 = Asciz ()Ljava/util/List<LTag;>;;
Ответ №2:
Я не знаю, что еще показать: в этом выводе не может быть указано «Tag», если подпись не присутствует. Поле и метод.
% cat a.scala
class Tag
class Ref {
var tags: java.util.List[Tag] = new java.util.ArrayList()
}
% scalac281 a.scala
% scala281
Welcome to Scala version 2.8.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_22).
Type in expressions to have them evaluated.
Type :help for more information.
scala> classOf[Ref].getDeclaredField("tags").getGenericType
res0: java.lang.reflect.Type = java.util.List<Tag>
scala> classOf[Ref].getMethod("tags").getGenericReturnType
res1: java.lang.reflect.Type = java.util.List<Tag>