No value passed for parameter - spring-boot

I use kotli. I define everything as per requirement, why I am getting
thing type of Issue
UserRegistrationService.kt: (25, 36): No value passed for parameter 'userRegistration'
I got this type of issue at my UserRegistration class No value passed
for parameter department, and userRegistration
I Creat ResponseTemplateVO POJO Class
ResponseVO.kt
package com.userservice.userregistration.VO
import com.userservice.userregistration.entity.UserRegistration
data class ResponseTemplateVO(
var userRegistration: UserRegistration,
var department: Department
)
Department.kt
package com.userservice.userregistration.VO
data class Department(
val departmentId:Long=-1,
val departmentName:String="",
val departmentAddress:String="",
val departmentCode:String=""
)
UserRegistration.kt
package com.userservice.userregistration.entity
data class UserRegistration(
val userId:Long=-1,
val firstName:String="",
val lastName:String="",
val email:String="",
val departmentId:Long=-1,
)
UserRegistrationService.kt
package com.userservice.userregistration.service
import com.userservice.userregistration.VO.Department
import com.userservice.userregistration.VO.ResponseTemplateVO
import com.userservice.userregistration.entity.UserRegistration
import com.userservice.userregistration.repository.UserRegistrationRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate
#Service
class UserRegistrationService {
#Autowired
private lateinit var userRegistrationRepository: UserRegistrationRepository
#Autowired
private lateinit var restTemplate: RestTemplate
fun saveUserDetails(userRegistration: UserRegistration): UserRegistration {
return userRegistrationRepository.save(userRegistration)
}
fun getUserWithDepartment(userId: Long): ResponseTemplateVO {
val vo= ResponseTemplateVO()
val userRegistration:UserRegistration=userRegistrationRepository.findUserById(userId)
val department: Department? =
restTemplate.getForObject("http://localhost:9001/departments/"+userRegistration.departmentId,
Department::class.java)
vo.userRegistration=userRegistration
if (department != null) {
vo.department=department
}
return vo
}
}
I am getting error at this below method at the line 2
val vo= ResponseTemplateVO()
No value passed for parameter department and userRegistration .This is
the error
fun getUserWithDepartment(userId: Long): ResponseTemplateVO {
val vo= ResponseTemplateVO()
val userRegistration:UserRegistration=userRegistrationRepository.findUserById(userId)
val department: Department? =
restTemplate.getForObject("http://localhost:9001/departments/"+userRegistration.departmentId,
Department::class.java)
vo.userRegistration=userRegistration
if (department != null) {
vo.department=department
}
return vo
}

This declaration:
data class ResponseTemplateVO(
var userRegistration: UserRegistration,
var department: Department
)
packs multiple things:
it declares 2 properties userRegistration and department
it defines the primary constructor of the class with 2 arguments: userRegistration and department
When you write:
val vo = ResponseTemplateVO()
You're calling the constructor of that class, but you don't specify the 2 required arguments. You should instead call it by passing the arguments:
fun getUserWithDepartment(userId: Long): ResponseTemplateVO {
val userRegistration:UserRegistration=userRegistrationRepository.findUserById(userId)
val department: Department? = restTemplate.getForObject("http://localhost:9001/departments/"+userRegistration.departmentId,
Department::class.java)
if (department == null) {
// here you should decide if it should have a default value
// or throw an exception
}
return ResponseTemplateVO(userRegistration, department)
}
Note that you declared the department property as non-null, so you need a non-null department in order to create an instance of your class.
So if department is null you have 3 options:
throw an exception
use a default value instead
change the type of department in ResponseTemplateVO so it accepts nulls (Department? with ?)
Also, if you instantiate your class with all required value like that, and you don't need to modify its properties later, the properties can be declared val. This is usually more idiomatic Kotlin. With immutability, it's easier to reason about the values.

The issue is in the data class.
data class ResponseTemplateVO(
var userRegistration: UserRegistration,
var department: Department
)
Here you have added the following params into the constructor of the data class. Hence you will need to pass the values to the constructor of the class before you can initialise it.
Hence your ResponseTemplateVO data class will become like this
data class ResponseTemplateVO(
var userRegistration: UserRegistration?=null,
var department: Department?=null)
Now since we have already assigned null as the default value. Now you can initialise the data class and it creates the data class with the values set to null and you do not need to pass any value for params to the constructor. Now you can access each of the variables and set the respective data into them.

Related

How do I set and read properties in a SpringBoot application using Kotlin?

I'm a Java developer new to Kotlin and I'm trying to access values that I set in an application.yml file.
application.yml
q:
client:
apiUrl: https://app.abc.com/api/integr/v1.0
apiToken: abc
apiSecret: abc
authEmail: abc#example.com
sourceName: abc
This is my configuration class, which follows a similar pattern to Java.
#Component
#FeignClient(name = "q", url = "\${q.client.api-url}")
interface QClient {
#PostMapping("/user/get")
fun findUser(#RequestBody request: QRequest?):
QResponse<List<QUser?>?>
#PostMapping("/user/delete")
fun deleteUser(#RequestBody request: QRequest?): QResponse<DeleteResponse?>?
#Configuration
class QConfig {
#Value("\${q.client.apiToken}")
private val apiToken: String? = null
#Value("\${q.client.apiSecret}")
private val apiSecret: String? = null
#Value("\${q.client.authEmail}")
private val authEmail: String? = null
#Value("\${q.client.sourceName}")
private val sourceName: String? = null
fun createAuthRequest(): QAuth {
return QAuth(apiToken, apiSecret, authEmail, sourceName)
}
}
I don't want to assign null as default values for the instance variables, but Kotlin wants me to declare them like this to avoid null references.
I need to create an auth request and I'm calling the config class from the main class.
private fun generateRequest(email: String): QRequest {
val config = QClient.QConfig()
val auth = config.createAuthRequest()
return QRequest(auth, email)
}
But when debugging it just returns null values.
So after googling, I changed my approach and set all the key values into parameters of QConfig class like this:
#Configuration
class QConfig(
#Value("\${q.client.apiToken}") private val apiToken: String,
#Value("\${q.client.apiSecret}") private val apiSecret: String,
#Value("\${q.client.authEmail}") private val authEmail: String,
#Value("\${q.client.sourceName}") private val sourceName: String
) {
fun createAuthRequest(): QAuth {
return QAuth(apiToken, apiSecret, authEmail, sourceName)
}
}
The problem I faced here was it acts as a constructor and expects me to pass arguments while creating an instance for the QConfig class on the main class, which I wont have in the main class.
How can I get the values from the application.yml and access them as from instance variables?
You can use #ConfigurationProperties (ref)
#ConfigurationProperties("q.client")
#ConstructorBinding
data class ClientConfig(
val apiUrl: String, // variable name should be same as the one defined in application.yaml
val apiToken: String,
...other properties
)
#SpringBootApplication
#ConfigurationPropertiesScan
class SpringStackoverflowApplication {
#Autowired
private lateinit var clientConfig: ClientConfig
#EventListener(ApplicationReadyEvent::class)
fun doSomething() {
println("FOOBAR: $clientConfig")
}
}
fun main(args: Array<String>) {
runApplication<SpringStackoverflowApplication>(*args)
}
I solved this with Joffrey's reply, I used this format of config file
#Component
#Configuration
class QConfig {
#Value("\${q.client.apiToken}")
private val apiToken: String? = null
#Value("\${q.client.apiSecret}")
private val apiSecret: String? = null
#Value("\${q.client.authEmail}")
private val authEmail: String? = null
#Value("\${q.client.sourceName}")
private val sourceName: String? = null
fun createAuthRequest(): QAuth {
return QAuth(apiToken, apiSecret, authEmail, sourceName)
}
}
Then created the instance of QConfig like this on main class
#Autowired
val config = QConfig()
My bad, tried creating reference of class manually instead of using AutoWire. When started it pulled all the env variables passed on .yml file into the local variables.

How to handle this Type MisMatch found List required Entity spring Boot JPA

I create a some operations in my controller class ,I want to store
the results what i get from the operation but when I store these list
of things it show me an error like Below
Type mismatch.
Required:
DepositMaterial!
Found:
List<Result>
Here is my controller class
#PatchMapping("/pendingValue")
fun pend(#ModelAttribute request:ReqFindPending):ResponseEntity<*>{
val existingWithdraw = depositRepository.findPendingByWithDrawId(request.withDrawId)
if (existingWithdraw != null){
val upPending = depositRepository.getPending(withDrawId = request.withDrawId)
depositRepository.save(upPending)
return ResponseEntity(ResMessage("Pending update successfull"),HttpStatus.OK)
}else{
return ResponseEntity(ResMessage(" id getting null value"),HttpStatus.NOT_ACCEPTABLE)
}
}
My repository
package com.nilmani.workload.repository
import com.nilmani.workload.entity.DepositMaterial
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Modifying
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.bind.annotation.RequestParam
interface DepositRepository : JpaRepository<DepositMaterial, Long> {
#Query("SELECT wm.quantity ,dd.totalDeposit,wm.quantity -dd.totalDeposit AS pending FROM WithdrawMaterial wm INNER JOIN DepositMaterial dd ON wm.id = dd.withDrawId ")
fun getPending(#Param("withDrawId")withDrawId: Long?):List<Result>
}
Here is my result Model
data class Result(
val pending: Long,
val quantity: Long,
val totalDeposit: Long
)
DepositMaterial Entity Class
package com.nilmani.workload.entity
import com.nilmani.workload.enum.Material
import java.time.LocalDateTime
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
#Entity
data class DepositMaterial (
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
val id:Long=-1,
val withDrawId:Long=-1,
val totalDeposit:Long=-1,
val material:Int= Material.NONE.type,
val depositTime:LocalDateTime = LocalDateTime.now(),
val pending:Long = -1,
val isDeposited:Boolean=false,
)
What is the reason for this issue,I want to only return these three
things, and store the result subtraction result of totalDeposit and
quantity in pending column to update the table but , It give me error
to store the depositMaterial
You are returning a list of Results from getPending, not an individual DepositMaterial. But the save method requires a single object to save. Try only requesting one object from getPending by changing the return signature.
depositRepository.getPending
returns a list of Entities.
depositRepository.save(upPending)
takes a single Entity to save in the database.
Solution:
Either change your save(upPending) method to saveAll(upPending), or update your getPending repo method to return a unique Entity object.

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

Kotlin - Using data class with type from an interface

I have an overrides interface which I created in order to combine 2 data classes - like so:
interface Overrides
data class SoOverrides(
val soId: String,
val freeInterval: String?
) : Overrides
data class CoOverrides(
val coId: String,
val pubType: String,
) : Overrides
I'm then trying to set the type of an item in my main data class to Overrides like so:
#Document(collection = Campaign.COLLECTION)
data class Campaign(
#Id
val id: String,
val title: String,
val overrides: List<Overrides>? = null
) {
companion object {
const val COLLECTION: String = "campaigns"
}
}
However whenever I go to run this, I get the error:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [co.....models.Overrides]: Specified class is an interface
Could someone please explain what I need to do to use that type Overrides. I'm extending the interface that way so I can have multiple classes, under one name, but not sure why it doesnt work?
I guess I could just use val overrides: List<*>? = null
Any help appreciated.
Thanks.

What is the most convenient way to deal with nested objects in Room?

I want to save the server’s response in database (class Parent). The json has nested object, which also should be saved in database in new table (class Nested). The problem is what I don’t know how to write class Parent and ParentDao to make it use NestedDao
#Entity
data class Parent(
#PrimaryKey(autoGenerate = true)
var id: Long? = null,
#SerializedName(«nested»)
val homeTeam: Nested,
//other fields
)
#Entity
data class Nested(
#PrimaryKey(autoGenerate = true)
var nestedId: Long? = null,
#SerializedName("name")
val name: String,
//other fields
)
#Dao
interface ParentDao {
#Query("SELECT * FROM parent»)
fun getData(): Single<List<Parent>>
#Insert
fun insert(matches: List<Parent>)
}
This gives me an error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
So, what should I do to save and query Parent with Nested at once?
I don't know if you've succeed or not, but here is my answer I hope it'll help you.
That's what I used for my project and what is recommended for Room in Android docs
#Entity
data class Parent(
#PrimaryKey(autoGenerate = true)
var id: Long? = null,
#Embedded #ColumnInfo(name= "nested")
val homeTeam: Nested,
//other fields
)
data class Nested(
#PrimaryKey(autoGenerate = true)
var nestedId: Long? = null,
#ColumnInfo(name= "name")
val name: String,
//other fields
)
#Dao
interface ParentDao {
#Query("SELECT * FROM parent»)
fun getData(): Single<List<Parent>>
#Insert
fun insert(matches: List<Parent>)
}

Resources