【问题标题】:Scala Generics - Overloaded methodScala 泛型 - 重载方法
【发布时间】:2014-12-23 22:31:19
【问题描述】:

考虑到给定的代码:

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

并且我的存储库有一个可序列化的字符串。

我正在尝试执行以下操作:

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))
  }

}

已编辑

即使在我的 getObject 中将类型返回设置为 Address,然后将保存方法设置为如下 save(getObject(t) : Address) 也会给我同样的重载错误。

已编辑

我刚刚发现这是一个限制,可能的解决方法是创建一个工厂或类似的东西。 然后我用 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$

【问题讨论】:

    标签: spring scala generics spring-data aspectj


    【解决方案1】:

    我可以在这里看到:

    • getObject[T](t : T) 返回存在类型 _1 并实际上杀死所有类型检查,因为您在运行时选择类
    • ElasticsearchRepository[_, String].save 需要将存在类型 _2 传递给 save 方法,所以 _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
    

    【讨论】:

      猜你喜欢
      • 2011-06-26
      • 1970-01-01
      • 2011-11-13
      • 1970-01-01
      • 2013-03-09
      • 1970-01-01
      • 1970-01-01
      • 2013-06-16
      • 1970-01-01
      相关资源
      最近更新 更多