考虑给定代码:
val repository =
context.getBean(
Introspector.decapitalize(t.getClass.getSimpleName).replace("C", "E").concat("Repository"))
并且我的存储库有一个String as Serializable。
我正在尝试执行以下操作:
repository.asInstanceOf[ElasticsearchRepository[_, String]].save(getObject(t))
这个很好用:
repository.asInstanceOf[ElasticsearchRepository[_, String]].findAll()
但我不知道如何将上述内容付诸实践。
假设方法getObject(t)正在重新调整要保留的正确对象,并且因为它是一个Spring Data Repository,所以有2个save方法。一个接受单个实体,另一个接受实体列表,它表示重载方法值保存。
到目前为止我尝试过:
我在另一个线程中看到强制使用类型的方法,如下所示:
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 to Address中设置一个类型返回,然后设置save方法如下save(getObject(t):Address)给我同样的重载错误。
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$
答案 0 :(得分: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