2014-12-23 131 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

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