10

I'm new with Kotlin and I try to rework a small Java project to this new language. I use mongodb in my project and I have a class, for example:

class PlayerEntity {

  constructor() {} //for mongodb to create an instance

  constructor(id: ObjectId, name: String) { //used in code
    this.id = id
    this.name = name
  }

  @org.mongodb.morphia.annotations.Id
  var id: ObjectId? = null

  var name: String? = null
}

I have to mark id field as nullable (var id: ObjectId?) because of empty constructor. When I try to access this field from another class I have to use non-null check: thePlayer.id!!. But the logic of my application is that id field is never null (mongo creates an instance of Player and immediately sets id field). And I don't want to make a non-null check everywhere.

I tried to make a non-null getter, but it does not compile:

var id: ObjectId? = null
    get(): ObjectId = id!!

I can also make some stub for id and use it in constructor, but this looks like a dirty hack:

val DUMMY_ID = new ObjectId("000000000000000000000000");

So is there a workaround to solve the issue?

awfun
  • 2,316
  • 4
  • 31
  • 52
  • 2
    put `lateinit` before your variable, it basically means, don't bother how but I ensure it will be initialized – succcubbus Nov 21 '16 at 09:40
  • Does [this similar problem in hibernate and solution](https://stackoverflow.com/questions/32038177/kotlin-with-jpa-default-constructor-hell) help? – miensol Nov 21 '16 at 09:40

1 Answers1

4

I personally use a private var prefixed by _ + public val in similiar situations.

class Example<out T> {
  private var _id: T? = null
  val id: T
    get() = _id!!
}

For your situation, it would look like this:

@org.mongodb.morphia.annotations.Id
private var _id: ObjectId? = null
val id: ObjectId
  get() = _id!!

Alternatively, declare your variable as lateinit like this (but note that this exposes the setter publicly):

@org.mongodb.morphia.annotations.Id
lateinit var id: ObjectId
F. George
  • 4,970
  • 4
  • 20
  • 38
  • 4
    `lateinit` is the correct thing to do in this case; no need to bother with a second property. – yole Nov 21 '16 at 11:52
  • Thanks, `lateinit` is what I need – awfun Nov 21 '16 at 12:21
  • 2
    @yole Everybody his own, I have a personal dislike against `lateinit` for some reason. – F. George Nov 21 '16 at 13:02
  • "I personally use a private var prefixed by _ + public val in similiar situation". What is the difference between this and a public var with a private setter? Is there one? – Rocoty Nov 22 '16 at 18:11
  • 3
    A getter/setter can't override it's parent var/val's type, so anybody consuming the getter would still have to non-null assert (`!!`) the return value. – F. George Nov 22 '16 at 21:06