原博客没续费,文章也看不见了,16年5月的文章了,复活一下。
Thrift是传统的java bean实现,在类型上,尤其是在容器类型上会给scala调用带来一些困扰。各种类型不匹配会然你烦不胜烦,前前后后折磨了我一年了,感觉是时候可以写点什么了。
下面以ActiveDays
的Thrift为例:
struct ActiveDays {
1: string id;
2: i64 firstActiveTime;
3: i64 lastActiveTime;
4: set<string> daysList;
5: list<i32> daysBits;
}
一般方案
1. Scala容器直接赋给thrift class
import com.xiaomi.data.spec.platform.profile.tmp.ActiveDays
val days = new ActiveDays()
days.daysBits = List(1, 2, 3)
// Error:(5, 22) type mismatch;
// found : List[Int]
// required: java.util.List[Integer]
// days.daysBits = List(1, 2, 3)}
// ^
这个如果能做到就NB了,只可惜不是,无尽的烦恼也是从这里才刚刚开始。
2. 利用Guava
类来操作
import com.google.common.collect.Lists
days.daysBits = Lists.newArrayList(1, 2, 3)
不过,这个跟Scala有关系吗?
3. 利用容器的addToXxx
方法
for(i <- List(1, 2, 3)){
days.addToDaysBits(i)
}
4. 利用JavaConverters
import scala.collection.JavaConverters._
days.daysBits = List(1, 2, 3).asJava
// Error:(18, 32) type mismatch;
// found : java.util.List[Int]
// required: java.util.List[Integer]
// days.daysBits = List(1, 2, 3).asJava};}
// ^
很遗憾,这个类并没有为我们做更多的事情,还有些类型要处理——Java的Integer竟然与Scala的Int是不相容的。
5. 利用JavaConverters
+ 类型转换
days.daysBits = List(1, 2, 3).map(i => i: Integer).asJava
i => i: Integer
这个是关键,不去StackOverflow上面逛逛我也不知道还可以这么玩。这一个转换只是保证编译不出错,这里daysBits
字段事实上只是收到了一个wrapper类。
6. 利用JavaConverters
+ 类型转换 + 容器转换
days.daysBits = Lists.newArrayList(List(1, 2, 3).map(i => i:Integer).asJava)
wrapper类会给你制造一些麻烦,scala 2.10中wrapper类是不可序列化的,在写thrift parquet文件或者kryo序列化时都会给你抛出一个wrapper类不可序列化的exception。好像这个方法跟addToXxxx
相比一点优势都没有,确实。
7. asInstance
val list = List(10000, 10001, 10002).asInstanceOf[java.util.List[java.lang.Integer]]
days.setDaysBits(list)
// java.lang.UnsupportedOperationException
8. asJava
+ asInstance
val list = List(10000, 10001, 10002).asJava.asInstanceOf[java.util.List[java.lang.Integer]]
days.setDaysBits(list)
仍然还有更多方案
Scrooge!Scrooge相当于Scala版的thrift,没有类型冲突的问题,不需要解决上述所有问题。只是路走得太远没法回头了。