Why won't astyanax (java) recognize my @Id annotated values in my scala case class parameter list? -
so here's dilemma: have domain model bunch of case classes in scala such user
, organization
. within data access layer (dao, repository, etc) using astyanax(a java library netflix) , it's entity persister save object cassandra column family.
here sample code cassandra/astyanax-backed daos (yes know need more scala-ish, i'm still learning =))
after reading through long-winded description, i'm looking see why annotated vals in param list won't work when java getdeclaredannotations()
on field
hate have go , refactor can use persister makes simple save entity (i.e. manager.put(entity)
). if want keep using case classes can work more immutable style scala , lens
scalaz, i'll have update dao , persisting manually can kill time.
so, if knows i'm not seeing, please let me know! in advance taking time read through this.
scenario 1 - case class
astyanax fails pick annotation @id on val
@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)
scenario 2 - class companion object or class without companion object
astyanax fails pick @id annotation on val
@entity 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) object organization { def apply(id: option[uuid] = none, createdon: option[date] = none, modifiedon: option[date] = none, name: option[string] = none, ispaidaccount: boolean = false) = new organization(id, createdon, modifiedon, name, ispaidaccount) }
scenario 3 - case class or class val defined inside block
this works fine because picks theid
being annotated @id
, don't want do because idbaseentity
defines , id val
, defeats whole purpose of inheritance , being able pass id
superclass
@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) { @id @column(name = "id") val theid: option[uuid] = id }
the data access portion
way down in manager see call build()
. astyanax examines class passed in withentitytype()
, in case classof[organization]
every 1 of scenarios fails except #3 when have val declared inside class block instead of parameter list case class or regular class/regular class companion object. astyanax says there know member of class annotated @id
throws exception. before dig further, figured ask community nuances of annotation scala class , sending java library reflection. source nothing special. in fact here relevant lines things fail: https://github.com/netflix/astyanax/blob/master/astyanax-entity-mapper/src/main/java/com/netflix/astyanax/entitystore/entitymapper.java#l89-120
class cassandraorganizationdao extends basecassandradao[organization, uuid](astyanax.context) organizationdao { val columnfamilyorganizations: columnfamily[uuid, string] = new columnfamily[uuid, string]( "organizations", timeuuidserializer.get(), stringserializer.get(), bytebufferserializer.get()) val columnfamilyorganizationmembers: columnfamily[uuid, uuid] = new columnfamily[uuid, uuid]( "organization_members", timeuuidserializer.get(), timeuuidserializer.get(), dateserializer.get()) val manager: entitymanager[organization, uuid] = new defaultentitymanager.builder[organization, uuid]() .withentitytype(classof[organization]) .withkeyspace(getkeyspace()) .withcolumnfamily(columnfamilyorganizations) .build() // rest of class omitted }
i came across similar issue, annotation never taken in account in constructor's fields. indeed, used springdata , impossible directly map annotation (like @indexed
) on field.
to enable annotations in case class's constructor, should first create kind of class:
object fixedscalaannotations { type id = com.packagecontainingid.id @field //replace right package type column = com.packagecontainingcolumn.column @field }
and import in case class , use instead of original:
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)
be sure original packages aren't used.
here related article dealing jpa: http://blog.fakod.eu/2010/07/14/constructor-arguments-with-jpa-annotations/
Comments
Post a Comment