Spring data mongodb and scala lazy val: do not serialise bitmap$0 field - spring

I use spring boot data mongodb in my scala project. When saving a case class that contains a lazy val, an additional bitmap$0 field appears in the mongo document (even if lazy val field is annotated with org.springframework.data.annotation.Transient). For example:
case class User(val firstName: String, val lastName: String) {
#Transient lazy val fullName: String = firstName +' ' + lastName
}
trait UserMongoRepository extends MongoRepository[User, String]
#Service
class userService(userMongoRepository: UserMongoRepository){
def saveUser = {
val u = User("Bob", "Marley")
userMongoRepository.save(u)
}
}
This results in a document:
{"firstName": "Bob", "lastName": "Marley", "bitmap$0": false}
How do I save a class with lazy val without the bitmap$0 field?

Related

How to use #value annotation in kotlin data class

I have an application.properties file like:
person-one-name=John
This is my data class, I have used #Value annotation outside dataclass.
#Value("\${person-one-name}")
lateinit var personOne: String
data class Person(val name: String, val age: Int) {
constructor(age: Int) : this(personOne, age)
}
I want to use the var personOne in my data class.
It gives an error lateinit property personOne has not been initialized
Following on from my comment under the Question:
data class Person(val name: String, val age: Int)
#Service
class PersonFactory(
#Value("\${person-one-name}")
private val personOne: String,
) {
fun createPerson(name: String? = null, age: Int) =
if (name != null) Person(name, age)
else Person(personOne, age)
}
Another gotcha, is that the PersonFactory service needs to be in a package at the same level or within the class that starts the App.
More info: https://springhow.com/a-guide-to-value-in-spring-boot/

Spring Data Mongo with Koltin coroutines and #DocumentReference

I am using Spring Data MongoDB with Kotlin Coroutines to create a non-blocking server.
I have a document Deck:
#Document
data class Deck(
#Id val id: ObjectId = ObjectId.get(),
#DocumentReference(lazy = true) val author: User,
val title: String,
val desc: String,
#DocumentReference(lazy = true) val cards : Set<Card> = emptySet(),
#CreatedDate val createdAt: Instant = Instant.now(),
#LastModifiedDate val lastModifiedAt: Instant = Instant.now()
)
Deck has a reference to a User type in the author field:
#Document
data class User(
#Id val id: ObjectId = ObjectId.get(),
val name: String,
#Indexed(unique = true, name = "username_index") val username: String,
val password: String,
#CreatedDate val createdAt: Instant = Instant.now(),
#LastModifiedDate val lastModifiedAt: Instant = Instant.now(),
#DocumentReference(lazy = true) val decks: Set<Deck> = emptySet()
)
Here's my DeckRepository interface:
interface DeckRepository: CoroutineSortingRepository<Deck, String> {
}
The Deck documents are getting saved properly in the database with the author's ObjectId.
But when I try to fetch the deck with id, the repository method gives an error. It's not able to populate the author's reference.
override suspend fun getDeck(deckId: String): DeckResponseDTO {
log.info("Getting deck with id $deckId")
return deckRepository.findById(deckId)?.toDto() ?: throw Exception("Could not find deck with id $deckId")
}
Stacktrace snippets:
Failed to instantiate io.gitub.startswithzed.dex.model.Deck using constructor fun <init>(org.bson.types.ObjectId, io.gitub.startswithzed.dex.model.User, kotlin.String, kotlin.String, kotlin.collections.Set<io.gitub.startswithzed.dex.model.Card>, java.time.Instant, java.time.Instant): io.gitub.startswithzed.dex.model.Deck with arguments 63173407712ec0263535829a,null,Test title,Test Desc,null,2022-09-06T11:50:31.370Z,2022-09-06T11:50:31.370Z,16,null
at org.springframework.data.mapping.model.KotlinClassGeneratingEntityInstantiator$DefaultingKotlinClassInstantiatorAdapter.createInstance(KotlinClassGeneratingEntityInstantiator.java:215) ~[spring-data-commons-2.7.2.jar:2.7.2]
Caused by: java.lang.NullPointerException: Parameter specified as non-null is null: method io.gitub.startswithzed.dex.model.Deck.<init>, parameter author
at io.gitub.startswithzed.dex.model.Deck.<init>(Deck.kt) ~[main/:na]
at io.gitub.startswithzed.dex.model.Deck.<init>(Deck.kt:14) ~[main/:na]
I even verified the data by querying using lookup in the console. Somehow Spring Data is not able to query properly.
Thanks for the help!

Return different Dto using same repository method with Spring Boot repositories

I have two DTOs
One for a get method like "/pessoas/{id}"
And another one for "/pessoas/{id}/detalhes" where I am going to see more attributes of Pessoa.
My codes are in Kotlin.
My simple DTO:
interface PessoaDTO {
val idInstitucional: UUID?
val nome: String?
}
data class PessoaDTOImpl(override val idInstitucional: UUID?, override val nome: String?): PessoaDTO
My DTO with details:
interface PessoaDetalhesDTO {
val idInstitucional: UUID?
val nome: String?
val email: String?
val telefone: String?
val cpf: Long?
}
data class PessoaDetalhesDTOImpl(override val idInstitucional: UUID?, override val nome: String?, override val email: String?, override val telefone: String?, override val cpf: Long?): PessoaDetalhesDTO
I have a repository that will be accessed by my PessoaController. I was thinking about having two methods in my Repository, each one for a different DTO.
That's my Repository:
internal interface PessoaRepository : CrudRepository<Pessoa, Long>, JpaSpecificationExecutorWithProjection<Pessoa> {
fun findByIdInstitucional(idInstitucional: UUID): PessoaDTO?
fun findByIdInstitucional(idInstitucional: UUID): PessoaDetalhesDTO?
}
However, I can't have two functions with the same name in the Repository for different returned data types.
How can I deal with that without having to create another Repository for the detailed information of Pessoa?

How to use Type converters for complex data type in ROOM library?

I'm new to ROOM library. I've some complex json data structure which i would like to store in ROOM database, i don't know how to use Type convertes for multiple list of objectes. Following are my Entities,
// Trying to put all my custom models in a single table
#Entity(tableName = "myTable")
data class RaceModelDatabase(
#PrimaryKey
val ID: String,
#Embedded val info: CustomModel,
#Embedded(prefix = "parti")
val parti: Map<String,UserModelDatabase> ,
#Embedded val totalTime: Map<String,TimeDataModel>
)
// Custom Models which also has Map objects
data class CustomModel (val name :String, val crdate : String )
data class UserModelDatabase(#Embedded val info : CustomModel,
#Embedded(prefix = "Result_") val result :Map<String,CustomModel>
)
data class TimeDataModel (
val Start : Long,
val End : Long
)
Here is an example of how to use TypeAdapter for one of your Map objects. You could follow the same for the rest.
class RaceTypeConverter {
#JvmStatic
#TypeConverter
fun fromString(value: String): Map<String, TimeDataModel > {
val mapType = object : TypeToken<Map<String, TimeDataModel >>() {}.type
return Gson().fromJson(value, mapType)
}
#TypeConverter
#JvmStatic
fun fromStringMap(map: Map<String, TimeDataModel>): String {
val gson = Gson()
return gson.toJson(map)
}
}

Spring Boot Mongo findById returns null

I have a collection, with documents having a field named _id of type String, not generated manually.
I have been trying to get a document using its id.
val criteria = Criteria.where("_id").`is`("a2z3e44R")
val document = mongoTemplate.findOne(Query.query(criteria), MyDocument::class.java) // returns null
val criteria = Criteria.where("_id").`is`(ObjectId("a2z3e44R"))
val document = mongoTemplate.findOne(Query.query(criteria), MyDocument::class.java) // returns null
val document = mongoTemplate.findById("a2z3e44R", MyDocument::class.java) // returns null
mongoTemplate.findAll(MyDocument::class.java).first { myDocument ->
myDocument._id == "a2z3e44R"
} // OK...
MyDocument is
data class MyDocument(val _id: String, val name: String)
Trying to find a document by another field works.
An idea of what I could be missing or a workaround?
You should indicate the type of the id like this
public class Article {
#MongoId(value = FieldType.OBJECT_ID)
private String id;
private String title;
private String desc;
}
Try mark _id with annotation #Id. The #Id annotation is used to specify the identifier for Spring.
data class MyDocument(#Id val _id: String, val name: String)
Ypu could define in your repository:
public interface MyDocumentRepository extends MongoRepository<MyDocument, String> {
Pets findBy_id(ObjectId _id);
}
and use it :
myDocumentRepository.findBy_id("a2z3e44R");
for more info see
or
ObjectId objID = new ObjectId("a2z3e44R");
query.addCriteria(Criteria.where("_id").lt(objID));
like this other answer link

Resources