2014-12-23 93 views
2

考虑给定的代码:斯卡拉泛型 - 重载方法

val repository = 
     context.getBean(
     Introspector.decapitalize(t.getClass.getSimpleName).replace("C", "E").concat("Repository")) 

,我的仓库有一个字符串为Serializable。

我试图做到以下几点:

repository.asInstanceOf[ElasticsearchRepository[_, String]].save(getObject(t)) 

这一个正常工作:

repository.asInstanceOf[ElasticsearchRepository[_, String]].findAll() 

但我不知道如何把上面的工作。

假设getObject(t)方法正在重新调用要保留的正确对象,并且由于它是Spring Data Repository,因此有2个保存方法。一个接受单个实体,另一个接受实体列表,它说重载的方法值保存。

我迄今为止尝试:

我在另一个线程看到了强制方法与类型,像这样:

repository.asInstanceOf[ElasticsearchRepository[_, String]].save(getObject(t) : TYPE) 

这是确定的,如果我知道的类型,也是我的方法getObject应该返回相同的类型。

这里是我的getObject方法,我返回对象本身没有任何具体的类型:

@throws[IOException] 
    def getObject[T](t : T) = { 
    objectMapper.readValue(objectMapper.writeValueAsString(t), getClazz(t)) 
    } 

所以我试图让这样的类型:

val m = Manifest.classType(getClazz(t)) 
    type TYPE = m.type 

看起来不错,如果我强迫我的对象使用getObject(t) : TYPE这种类型,但我不知道如何在我的getObject方法中使用这个相同的类型来返回。

无论如何,我甚至不知道这是否是最好的方法来调用通用存储库并保存通用对象。为了理解我想要做的事情,我使用了一个方面来拦截一个Cassandra实体来保存,然后获取它并转换成一个ElasticSearch实体来保存一个json(这就是为什么getObject(t ))并复制到ElasticSearch中。

这里是全方面类:

@Component 
@Aspect 
class ElasticAop { 

    @Autowired val context : ApplicationContext = null 

    val objectMapper : ObjectMapper = new ObjectMapper() 

    @Pointcut("execution(* com.test.service.cassandra.*.post(..)) && args(t)") 
    def getPointcutPost[T](t : T) : Unit = {} 

    @throws[Throwable] 
    @Before("getPointcutPost(t)") 
    def elasticSaveAspect[T](joinPoint: JoinPoint, t: T) = { 
    val m = Manifest.classType(getClazz(t)) 
    type TYPE = m.type 

    val repository = 
     context.getBean(
     Introspector.decapitalize(t.getClass.getSimpleName).replace("C", "E").concat("Repository")) 

    repository.asInstanceOf[ElasticsearchRepository[_, String]].findAll() 
    repository.asInstanceOf[ElasticsearchRepository[_, String]].save(getObject(t)) 
    } 

    @throws[ClassNotFoundException] 
    def getClazz[T](t : T) = { 
    val className = t.getClass.getName.replace("cassandra", "elastic").replace("C", "E") 
    Class.forName(className) 
    } 

    @throws[IOException] 
    def getObject[T](t : T) = { 
    objectMapper.readValue(objectMapper.writeValueAsString(t), getClazz(t)) 
    } 

} 

EDITED

即使建立在我的getObject类型返回地址,然后设置保存方法如下保存(的getObject(T) :地址)给我相同的重载错误。

EDITED

我只是想出了这是一个限制和可能的解决办法是建立一个工厂或类似这样的东西。 然后,我创建了一个带有saveOrUpdate方法的服务:

trait ElasticGenericService[T <: ElasticGenericKey, R <: ElasticsearchRepository[T, String]] { 

    var r : R = _ 

    def saveOrUpdate(t: T) = r.save(t) 

} 

,现在我得到一个转换异常:

java.lang.ClassCastException: Address cannot be cast to scala.runtime.Nothing$ 

回答

1

什么,我可以在这里看到:

  • getObject[T](t : T)回报存在键入_1,实际上会杀死所有类型的检查,因为您在运行时选择类别
  • ElasticsearchRepository[_, String].save需要存在类型_2要传递到保存方法,所以_1不适合

可能的解决方案:

repository.asInstanceOf[ElasticsearchRepository[Any, String]].save(getObject(t).asInstanceOf[Any]) //getClass will work with runtime class instead of Any, so should be fine 

另一种解决方案(节省存在型):

def getObject[T](t : T) = { 
    objectMapper.readValue(objectMapper.writeValueAsString(t), getClazz(t)).asInstanceOf[T] 
} //assuming T is an existential - it will return same existential as you passed 
+1

很棒,它像一个魅力:) –