【问题标题】:Why won't astyanax (java) recognize my @Id annotated values in my scala case class parameter list?为什么 astyanax (java) 不能在我的 scala 案例类参数列表中识别我的 @Id 注释值?
【发布时间】:2013-04-27 06:03:35
【问题描述】:

所以这是我的两难境地:我有一个域模型,在 scala 中有一堆案例类,例如 UserOrganization。在我的数据访问层(dao、存储库等)中,我使用 astyanax(来自 netflix 的 java 库),它是实体持久化器,用于将对象保存到 cassandra 列族。

这是我的 cassandra/astyanax 支持的 DAO 的一些示例代码(是的,我知道我需要做一些更 scala-ish 的事情,但我仍在学习 =))

在阅读了这个冗长的描述之后,我基本上是想看看为什么当 java 在getDeclaredAnnotations()getDeclaredAnnotations()Field 时,参数列表中的带注释的 val 不起作用我不想不得不回去重构一切,以便我可以使用持久化器,这使得保存实体变得非常简单(即manager.put(entity))。如果我想继续使用案例类,以便可以使用更多不可变样式的 scala 和来自 scalaz 的 Lens,那么我将不得不更新 DAO 并手动执行所有持久化操作,这真的可以消磨时间。

所以,如果有人知道我没有看到的东西,请告诉我!提前感谢您抽出宝贵时间阅读本文。

场景 1 - 案例类

Astyanax 无法获取 val 上的注释 @Id

@实体 case class Organization(@Id @Column(name = "id") override val id: Option[UUID] = None, @Column(name = "created_on") 覆盖 val createdOn: Option[Date] = None, @Column(name = "modified_on") 覆盖 val modifiedOn: Option[Date] = None, @Column(name = "name") 名称:选项 [字符串] = 无, @Column(name = "is_paid_account") isPaidAccount: Boolean = false) 扩展 IdBaseEntity[UUID](id, createdOn, modifiedOn)

场景 2 - 有伴随对象的类或没有伴随对象的类

Astyanax 无法获取val 上的@Id 注释

@实体 类组织(@Id @Column(name = "id") 覆盖有效 id: Option[UUID] = None, @Column(name = "created_on") 覆盖 val createdOn: Option[Date] = None, @Column(name = "modified_on") 覆盖 val modifiedOn: Option[Date] = None, @Column(name = "name") 名称:选项 [字符串] = 无, @Column(name = "is_paid_account") isPaidAccount: Boolean = false) 扩展 IdBaseEntity[UUID](id, createdOn, modifiedOn) 对象组织{ def apply(id: Option[UUID] = None, createdOn: 选项 [日期] = 无, 修改时间:选项 [日期] = 无, 名称:选项 [字符串] = 无, isPaidAccount: Boolean = false) = new Organization(id, createdOn, modifiedOn, name, isPaidAccount) }

场景 3 - 在块内定义 val 的案例类或类

这很好用,因为它会将theId 拾取为使用@Id 进行注释,但我不想这样做,因为IdBaseEntity 已经定义和id val 并破坏了继承和能够实现的整个目的将id 传递给超类

@实体 case class Organization(@Id @Column(name = "id") override val id: Option[UUID] = None, @Column(name = "created_on") 覆盖 val createdOn: Option[Date] = None, @Column(name = "modified_on") 覆盖 val modifiedOn: Option[Date] = None, @Column(name = "name") 名称:选项 [字符串] = 无, @Column(name = "is_paid_account") isPaidAccount: Boolean = false) 扩展 IdBaseEntity[UUID](id, createdOn, modifiedOn) { @Id @Column(name = "id") val theId: Option[UUID] = id }

数据访问部分

在经理中,您将看到对build() 的调用。 Astyanax 检查传递给withEntityType() 的类,在本例中为classOf[Organization]

当我在类块内声明了一个 val 而不是案例类或带有伴随对象的常规类/常规类的参数列表时,我的每个场景都失败了,除了 #3。 Astyanax 说该类的已知成员用@Id 注释,因此它会引发异常。在进一步挖掘之前,我想我会向社区询问注释 scala 类并将其发送到进行反射的 java 库的细微差别。来源没什么特别的。事实上,这是失败的相关行:https://github.com/Netflix/astyanax/blob/master/astyanax-entity-mapper/src/main/java/com/netflix/astyanax/entitystore/EntityMapper.java#L89-120

类 CassandraOrganizationDAO 扩展 BaseCassandraDAO[Organization, UUID](Astyanax.context) 与 OrganizationDAO { val ColumnFamilyOrganizations: ColumnFamily[UUID, String] = new ColumnFamily[UUID, String]( “组织”, TimeUUIDSerializer.get(), StringSerializer.get(), ByteBufferSerializer.get()) val ColumnFamilyOrganizationMembers: ColumnFamily[UUID, UUID] = new ColumnFamily[UUID, UUID]( “组织成员”, TimeUUIDSerializer.get(), TimeUUIDSerializer.get(), DateSerializer.get()) val manager: EntityManager[Organization, UUID] = new DefaultEntityManager.Builder[Organization, UUID]() .withEntityType(classOf[组织]) .withKeyspace(getKeyspace()) .withColumnFamily(ColumnFamilyOrganizations) 。建造() // 类的其余部分被省略 }

【问题讨论】:

    标签: java scala reflection annotations astyanax


    【解决方案1】:

    @Mik378 在处理 JPA 注释方面提供了很大帮助,这似乎适用于使用 Hibernate 之类的东西的人。但是,就我而言,我使用的是 Astyanax,它可能只是它的细微差别之一,所以鉴于我从上面的 @Mike378 中学到的知识,我将发布对我有用的解决方案。

    重要提示:当IdBaseEntity 是一个抽象类或类时,我什么都做不了

    解决方案:我不得不让 IdBaseEntity 成为一个特征,一切都很好

    这是层次结构

    BaseEntity.scala

    import java.util.Date
    
    trait BaseEntity {
      val createdOn: Option[Date] = None
      val modifiedOn: Option[Date] = None
    }
    

    IdBaseEntity.scala

    trait IdBaseEntity[T <: java.io.Serializable] extends BaseEntity {
      val id: Option[T] = None
    }
    

    FixedScalaAnnotations.scala

    import scala.annotation.meta.field
    
    object FixedScalaAnnotations {
      type Id = javax.persistence.Id @field
      type Column = javax.persistence.Column @field
    }
    

    Organization.scala

    import java.util.{Date, UUID}
    import FixedScalaAnnotations._
    import javax.persistence.Entity
    
    @Entity
    case class Organization(@Id @Column(name = "id") override val id: Option[UUID] = None,
                            @Column(name = "created_on") override val createdOn: Option[Date] = None,
                            @Column(name = "modified_on") override val modifiedOn: Option[Date] = None,
                            @Column(name = "name") name: Option[String] = None,
                            @Column(name = "is_paid_account") isPaidAccount: Boolean = false) extends IdBaseEntity[UUID]
    

    【讨论】:

    • 查看您的代码,您正在处理val 和继承。也许,我只是说也许,你会接触到这个微妙的 scala 规则:github.com/paulp/scala-faq/wiki/Initialization-Order。如果我是你,我会尝试两种方式:将你的父母重新声明为abstract并尝试处理varlazy valid字段只是为了看看这个规则是否与你的工作无关。其他方式:只需将@Idannotation 声明到抽象类的val id 字段,而不是在Organization 类中声明。
    • 所以我尝试了一些方法。由于 astyanax 限制,父级中的 @Id 不起作用,但是有一个拉取请求可以解决此问题。我确实发现我是个白痴。当我说抽象类不起作用时,那是因为我从案例类组织传递了 extends IdBaseEntity[UUID](id)。如果我只是离开它扩展 IdBaseEntity[UUID] 那么一切都像一个魅力。所以我可以使用更简洁的默认参数列表语法而不是特征来保留抽象类定义。我在这个问题上学到了很多东西。谢谢!
    【解决方案2】:

    我遇到了类似的问题,我的注释从未在构造函数的字段中考虑在内。确实,我使用了 SpringData,无法直接在字段上映射注解(如 @Indexed)。

    要在案例类的构造函数中启用注释,您应该首先创建这种类:

    object FixedScalaAnnotations {
      type Id = com.packagecontainingid.Id @field //replace by the right package
      type Column = com.packagecontainingcolumn.Column @field
    }
    

    然后将其导入您的案例类并使用它来代替原来的:

    import FixedScalaAnnotations._
    
    @Entity
    case class Organization(@Id @Column(name = "id") override val id: Option[UUID] = None,
                            @Column(name = "created_on") override val createdOn: Option[Date] = None,
                            @Column(name = "modified_on") override val modifiedOn: Option[Date] = None,
                            @Column(name = "name") name: Option[String] = None,
                            @Column(name = "is_paid_account") isPaidAccount: Boolean = false) extends IdBaseEntity[UUID](id, createdOn, modifiedOn)
    

    确保不使用原始包。

    这里有一篇关于 JPA 的相关文章:http://blog.fakod.eu/2010/07/14/constructor-arguments-with-jpa-annotations/

    【讨论】:

    • 所以我尝试了好几个小时你的建议的许多排列,但它不起作用。当组织不扩展任何其他类时,它工作得很好。一旦我使用抽象类或常规类引入继承,它就会拒绝找到 @Id 注释。所以我继续把 IdBaseEntity 变成了一个特征,一切都很好。我想这很好吗?无论如何,不​​要走错路,但我他妈的爱你!感谢您对此的教育。如果您碰巧知道为什么继承类不起作用,我很想知道。再次感谢!
    • 我会在给定 Astyanax 的情况下添加对我有用的东西,以防其他人遇到同样的问题,但我会接受你的回答,因为它似乎从我在链接中读到的内容有效你发给我
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-14
    • 2019-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-14
    相关资源
    最近更新 更多