开发者

The generic type information of fields in traits are missing?

开发者 https://www.devze.com 2023-03-04 03:29 出处:网络
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.

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>
0

精彩评论

暂无评论...
验证码 换一张
取 消