Referencing value and calling methods in generic class types - spring

I'm new to Kotlin coming from C#. Currently I am trying to setup a class that takes in a couple of interchangeable generic types, the internal code of this class is a spring service end-point.
I have started with something like below, however I seem to have trouble with the syntax to reference the parameters of the request body as well as calling a method, which are of the types passed in through the class constructor. Syntax of generics and reflection does not seem that straight forward and most of the Kotlin examples I have been digging up has not seem to covered precisely what I am trying to do (if even possible). The object instance of type1 will be passed in through the body parameter and the object instance of type2 should be passed in through the constructor (syntax is probably not right).
Planning to use this as a template to setup several end-points based on the same base code but with different requests and services classes.
Any help is greatly appreciated.
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import javax.validation.Valid
open class Base <T1,T2>(t1: Class<T1>, t2: Class<T2>) {
#Autowired
var type1 = t1
#Autowired
var type2 = t2
#ApiOperation(value = "API 1", response = myResponse::class)
#ApiResponses(value = *arrayOf(
ApiResponse(code = 200, message = "successful", response = CcdaResponse::class),
ApiResponse(code = 405, message = "Invalid", response = Void::class)))
#RequestMapping(
value = "/myEndPoint",
produces = arrayOf("application/json"),
consumes = arrayOf("application/json"),
method = arrayOf(RequestMethod.POST)
)
fun endpoint(
#ApiParam(value = "Options", required = true)
#Valid
#RequestBody
body: Class<T1>
): ResponseEntity<myResponse> {
val r = myResponse()
val response: ResponseEntity<myResponse>
response = ResponseEntity(r, HttpStatus.OK)
try {
//payload
val parameters = Parameters().apply {
Id1 = type1::body.Id1.get()
Id2 = type1::body.Id2.get()
Id3 = type1::body.Id3.get()
Id4 = type1::body.Id4.get()
v = type1::body.v.get()
}
//Do stuff like calling method in class of type2 passed in
val d = type2.getViewModel(parameters)
r.status = "ok"
} catch (e: Exception) {
r.message = e.toString()
r.status = "error"
} finally {
}
return response
}
}

The types of the parameters are passed in through the type arguments when creating an instance (the same as Java). So you do need to pass in the types themselves, adding a Class parameter just isn't the correct syntax.
I believe this is what you are looking for (omitted some code for brevity).
open class Base<T1, T2> (#Autowired var t2: T2) {
#Autowired var type1: T1? = null
fun endpoint(
#ApiParam(value = "Options", required = true) #Valid #RequestBody
body: T1
): ResponseEntity<MyResponse> {
type1 = body
}
}
Then, for instance, you can create an instance of this class with the types Int and String (for T1 and T2 respectively) in the following manner.
val t2 = "t2"
val base = Base<Int, String>(t2)
Or you can subclass the Base class with any (or none) of the types specified.
class SubBase(t2: String): Base<Int, String>(t2)

Related

Gradle Spring mvc validation data class recursive Kotlin

I need to create a recursive validation to be able to validate PizzaCreate Object and base attribute in recursive mode using Kotlin. The test should return 400 but it returns 200 ok (Base name size must be greater than 2):
data class Base(#field:Length(min = 2, max = 100) val name:String)
data class PizzaCreate(
val id: Long,
#field:Length(min = 2, max = 100) val name: String,
val description: String,
val price: Int,
#Valid val base: Base
)
#RestController
#RequestMapping("/pizza")
class PizzaController(val pizzaService: PizzaService) {
#PostMapping
fun post(#RequestBody #Valid pizza: PizzaCreate) = pizzaService.addPizza(pizza)
}
#Test
fun `should add pizza `() {
val pizza = easyRandom.nextObject(PizzaCreate::class.java).copy(id = 1, name="aaa", base = Base(""))
val pizzaOut = PizzaOut(id=1,name=pizza.name,description = pizza.description,price = pizza.price)
`when`(pizzaService.addPizza(pizza)).thenReturn(pizzaOut.toMono())
webTestClient.post()
.uri("/pizza")
.bodyValue(pizza)
.exchange()
.expectStatus().isBadRequest
.returnResult<PizzaOut>().responseBody
}
Validation on Base should be #field:Valid val base: Base instead of #Valid val base: Base
field: specifies the annotation is applied on the field not construc
ref:
https://stackoverflow.com/a/35853200
https://stackoverflow.com/a/36521309

Spring - Springboot controller GET requests with default parameters

I have a Springboot controller with two GET endpoints:
#RestController
#RequestMapping("/foo")
class MyController {
fun getFoo(
#RequestParam("x", required = false) x: Int = 0
) = ...
fun getFoo(
#RequestParam("x", required = true) x: Int,
#RequestParam("y", required = true) y: Int
) = ...
The behaviour I want is that when called:
/foo calls the first endpoint with an optional x param.
/foo?x=123 calls the first endpoint with a supplied x param.
/foo?x=123&y=456' calls the second endpoint with the supplied xandy` params.
Currently I get an error:
{
"timestamp": "2020-07-20T13:11:24.732+0000",
"status": 400,
"error": "Bad Request",
"message": "Parameter conditions \"x\" OR \"x, y\" not met for actual request parameters: ",
"path": "/foo"
}
Any ideas how to determine a default endpoint when zero params are specified?
Set a params in #RequestMapping or its variants(#GetMapping, #PostMapping etc).
eg.
#GetMapping(params=arrayOf("!x", "!y"))
fun getFoo()
#GetMapping(params=arrayOf("x", "!y"))
fun getFoo(
#RequestParam("x", required = true) x: Int = 0
#GetMapping(params=arrayOf("x", "y"))
fun getFoo(
#RequestParam("x", required = true) x: Int,
#RequestParam("y", required = true) y: Int
Different params can be applied and identified on the same URI.
You can specify a defaultValue as a String in #RequestParam:
fun getFoo(
#RequestParam(name = "x", required = false, defaultValue = "0") x: Int,
#RequestParam(name = "y", required = false, defaultValue = "1") y: Int
) =
Spring will convert the String to whatever type you really want (Int in your case) using the same method as if you specified x as a parameter (same coercion, errors, etc).
If you want more then one mapping to the same url (lot of times it is a codesmell, but sometime it is necessary, you can do i twith filter params in #GetMapping or #RequestMapping annotations' params element.
#RestController
#RequestMapping("/foo")
class MyController {
#GetMapping(params = ["!y"])
fun getFoo(
#RequestParam("x", required = false) x: Int?
) = ...
#GetMapping(params = ["x", "y"])
fun getFoo(
#RequestParam("x", required = true) x: Int,
#RequestParam("y", required = true) y: Int
) = ...
}

Custom Result handling by calling store procedure in Spring Data JPA

I have requirement to call store procedures which takes input parameters. This store procedure returns custom result set, that result set i need to read and process further before return to UI. How we can achieve this?
EG:
#Query("CALL SP_EMPLOYEE_REPORT(:year)",nativeQuery = true)
List<EmpolypeeCustomReportBean> getEmployeeReport(#param("year") Integer year);
Given the following stored procedure.
CREATE PROCEDURE NAME_OF_THE_PROCEDURE(IN param VARCHAR(255), OUT retval INT)
You can call it from interface query:
#Procedure(value = "NAME_OF_THE_PROCEDURE")
int getFromStoredProcedure(String param);
Also by #Query annotation:
#Query(value = "CALL NAME_OF_THE_PROCEDURE(:input_value);", nativeQuery = true)
Integer findSomeThing(#Param("input_value") Integer name);
Or you can use named stored procedure query too.
#Entity
#NamedStoredProcedureQuery(name = "MyObj.getSomethingFromProc",
procedureName = "NAME_OF_THE_PROCEDURE", parameters = {
#StoredProcedureParameter(mode = ParameterMode.IN, name = "param", type = String.class),
#StoredProcedureParameter(mode = ParameterMode.OUT, name = "retval", type = Integer.class)})
public class MyObj{
// class definition
}
Then call it.
#Procedure(name = "MyObj.getSomethingFromProc")
Integer getSomethingFromStoredProc(#Param("param") String model);
Also you can use resultClasses and resultSetMapping properties in #NamedStoredProcedureQuery for complex return types.
Complex example provided by Eclipselink:
#NamedStoredProcedureQuery(
name="ReadUsingMultipleResultSetMappings",
procedureName="Read_Multiple_Result_Sets",
resultSetMappings={"EmployeeResultSetMapping", "AddressResultSetMapping", "ProjectResultSetMapping", "EmployeeConstructorResultSetMapping"}
)
#SqlResultSetMappings({
#SqlResultSetMapping(
name = "EmployeeResultSetMapping",
entities = {
#EntityResult(entityClass = Employee.class)
}
),
#SqlResultSetMapping(
name = "EmployeeConstructorResultSetMapping",
classes = {
#ConstructorResult(
targetClass = EmployeeDetails.class,
columns = {
#ColumnResult(name="EMP_ID", type=Integer.class),
#ColumnResult(name="F_NAME", type=String.class),
#ColumnResult(name="L_NAME", type=String.class),
#ColumnResult(name="R_COUNT", type=Integer.class)
}
)
}
)
})
public Employee(){
....
}

Pass multiple Filters to Android Room Dao SQL Query from ViewModel with Repository

I am using the below to fetch Database rows to my Adapter, however I want to return rows from multi-filtered single query using either "LIKE" and/or "WHERE" and basically all sql query filter types, I can do one filter via MutableLiveData<String>();
end result would be like ...
#Query("SELECT * FROM mytable WHERE suburb LIKE '%' || :suburb || '%' postcode LIKE '%' || :postcode || '%' BETWEEN firstDate AND lastDate")
fun getFilteredRows(
suburb: String?,
postcode: String?,
firstDate: String?,
lastDate: String?): LiveData<List<MyTable>>
As per below, currently way only can pass one filter var.
ViewModel Class
class MyViewModel internal constructor(repository: MyRepository) : ViewModel()
//filter by suburb
var suburb = MutableLiveData<String>().apply {
//do I set as HashMap??
value = SUBURB
}
//LiveData Observer access
val filteredRows: LiveData<List<MyTable>> = suburb.switchMap {
//pass multiple filters to repository here
//but currently only can pass one string to repository
repository.getFilteredRows(it)
}
//MyViewModel function to set the suburb value
fun setSuburb(_suburb: String) {
suburb.value = _suburb
}
//companion object
companion object {
var SUBURB: String? = null
}
Repository Class
class Repository private constructor(private val dao: Dao)
//basic repo to dao communtication
fun getFilteredRows(suburb: String?) = dao.getFilteredRows(suburb)
Dao Interface
#Dao
interface Dao
//here I want to receive multiple Strings to do filtering within the query
#Query("SELECT * FROM mytable WHERE suburb LIKE '%' || :suburb || '%'")
fun getFilteredRows(suburb: String?): LiveData<List<MyTable>>
I have tried with passing basic var Strings with no luck, seems only MutableLiveData is the way to pass variable to the Dao via ViewModel & Repository
** See Edit Below **
Not ideal to say the least, actually would not recommend, however, current work around is to "loop" through multiple MutableLiveData variables
ViewModel Class
var suburb = MutableLiveData<String>().apply { value = SUBURB }
var postcode = MutableLiveData<String>().apply { value = POSTCODE }
var limit = MutableLiveData<Int>().apply { value = LIMIT }
val filteredRows: LiveData<List<MyTable>> =
suburb.switchMap {
//set suburb MutableLiveData
var suburb = it
postcode.switchMap {
//set postcode MutableLiveData
var postcode = it
}
limit.switchMap {
//set limit MutableLiveData
var limit = it
}
repository.getFilteredRows(suburb, postcode, limit)
}
/// EDIT ANSWER ///
Using HashMap to pass multiple filters (Strings) to Dao SQl Query.
Tested a returned what was expected, so confirming this works.
Foreseeable issue is when needing to pass Strings & Int etc, may have to refer back to passing as Strings only & then do parse.ToInt() etc on Int String Values
build HashMap in my Fragment to pass to MyViewModel
lateinit var myModel: LiveData<MyTable>
var filters = HashMap<String, String>()
filters.put("suburb", myModel.value!!.suburb)
filters.put("postcode", myModel.value!!.postcode)
with(viewModel) {
//pass my HashMap to my ViewModel for update/change/set on filters MutableLiveData HashMap variable
setFilters(filters)
}
MyViewModel Class
//initilise filters MutableLiveData HashMap variable
var filters = MutableLiveData<HashMap<String, String>>().apply { value = FILTERS }
//function to update/change/set filters MutableLiveData HashMap variable
//see setFilters(filters) used in above Fragment
fun setFilters(_filters: HashMap<String, String>) {
filters.value = _filters
}
//foreach on passed HashMap via switchMap{}
val filtered: LiveData<List<MyTable>> = filters.switchMap {
//initilise variables
var suburb = ""
var postcode = ""
//foreach loop on HashCookie :)
for (filter in it) {
if(filter.key.equals("suburb")){
suburb = filter.value
}else if(filter.key.equals("postcode")) {
postcode = filter.value
}
}
//pass strings to Dao
repository.getFiltered(suburb, postcode)
}
//companion object
companion object {
var FILTERS: HashMap<String, String>? = null
}
Repository Class
//send variables to the Dao Interface
fun getFiltered(suburb: String?, postcode: String?) = dao.getFiltered(suburb, postcode)
Dao Interface
#Query("SELECT * FROM mytable WHERE suburb LIKE '%' || :suburb || '%' AND postcode LIKE '%' || :postcode || '%' ")
fun getFiltered(suburb: String?, postcode: String?): LiveData<List<MyTable>>

How do fetch the state with custome query? Corda application using Spring boot webserver- error while fetching the result

I have created the IOU in corda applicatiion, the IOU has ID,xml payload in body, partyName. NOW, i want to fetch the state with custome query that is basis on ID. NOTE- i am not using linearID.
Below is my API call- which gives me syntax error on. Can someone please correct me, what is the wrong thing that i am doing.
#GetMapping(value = ["getIous"],produces = [ MediaType.APPLICATION_JSON_VALUE])
private fun getTransactionOne(#RequestParam(value = "payloadId") payloadId: String): ResponseEntity<List<IOUState>> {
val generalCriteria = QueryCriteria.VaultQueryCriteria(Vault.StateStatus.ALL)
val results = builder { IOUState::iouId.equal(payloadId)
val customCriteria = QueryCriteria.VaultCustomQueryCriteria(results)}
val criteria = customCriteria.and(customCriteria)
val res = proxy.vaultQueryBy<IOUState>(criteria)
return ResponseEntity.ok(res)
}
I think the issue is because VaultCustomQueryCriteria is applicable only to StatePersistable objects. So you should use PersistentIOU instead of IOUState. Also, I could see incorrect use of brackets. Here is how your code should look like:
#GetMapping(value = ["getIous"],produces = [ MediaType.APPLICATION_JSON_VALUE])
private fun getTransactionOne(#RequestParam(value = "payloadId") payloadId: String): ResponseEntity<List<IOUState>> {
val generalCriteria = QueryCriteria.VaultQueryCriteria(Vault.StateStatus.ALL)
val results = builder {
val idx = IOUSchemaV1.PersistentIOU::iouId.equal(payloadId);
val customCriteria = QueryCriteria.VaultCustomQueryCriteria(idx)
val criteria = generalCriteria.and(customCriteria)
proxy.vaultQueryBy<IOUState>(criteria);
}
return ResponseEntity.ok(results)
}

Resources