I found this problem when I use Morphia
in scala. It checks the fields of a class by reflection, and get necessary type information for mapping.
But if I use traits
, and define some collection fields, the generic type information will be lost, which cause Morphia can't get enough information, and throw exceptions.
See my code:
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 {
}
I compiled the scala file, and get some java class files. Then I use java decompiler to see the content of the java byte codes:
public class Question extends Entity implements HasTags {
@Reference
private java.util.List tags;
}
You can see there is no Tag
here, so Morphia will fail.
I used scala 2.8.1
. Is there any way to fix it?
UPDATE
@extempore said, maybe javap
doesn't display that Tag
information.
But I used a program called Java Decompiler, not javap
.
I tried this code:
class Question extends Entity with HasTags {
@Reference
var tags2: java.util.List[Tag] = new java.util.ArrayList()
}
And see the byte code in Java Decompiler
, it displays:
public class Question extends Entity implements HasTags {
@Reference
private j开发者_Go百科ava.util.List tags;
@Reference
private java.util.List<models.Tag> tags2;
}
We can see the tags2
contains Tag
, but tags
doesn't.
And the interface HasTags
is:
public abstract interface HasTags extends ScalaObject
{
public abstract List<Tag> tags();
@TraitSetter
public abstract void tags_$eq(List<Tag> paramList);
}
We can see, the return value of method tags()
is List<Tag>
, but the field tags
is not.
Since morphia get the information by fields, it can't work correctly.
That's how javap displays things. It doesn't mean the signature isn't present.
scala> classOf[HasTags].getMethod("tags").getGenericReturnType
res0: java.lang.reflect.Type = java.util.List<Tag>
That's how you know it is. You can also see it in the constant pool.
const #3 = Asciz tags;
const #4 = Asciz ()Ljava/util/List;;
const #5 = Asciz ()Ljava/util/List<LTag;>;;
I don't know what else to show: it can't say "Tag" in this output unless the signature is present. Field and method.
% 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>
精彩评论