Making JSON string to Kotlin object not working - json

I am trying to send a multipart/formdata object to the backend that contains a Freelancer object and two image files that have to be stored on the server. The saving on disc part works, but saving the JSON string as a freelancer object is not working. I tried converting the string with Jackson objectmapper but I think I am doing something wrong. When I debug the application it crashes at mapper.readValue and goes straight to the catch().
I also tried to work with kotlinx.serializer, but the import just would not work so I switched to Jackson.
The Kotlin controller that takes in the request:
private val imageDirectory = System.getProperty("user.dir") + "/images/"
#PostMapping(consumes = ["multipart/form-data"])
fun saveUser(
#RequestParam("profileImage") profileImage: MultipartFile,
#RequestParam("fileIdImage") fileIdImage: MultipartFile,
#RequestParam("freelancer") freelancer: String,
): ResponseEntity<*> {
return try {
val mapper = ObjectMapper();
val freelancerJson: Freelancer = mapper.readValue(freelancer, Freelancer::class.java)
println(freelancerJson.aboutYou)
makeDirectoryIfNotExist(imageDirectory)
val profileImagePath: Path = Paths.get(imageDirectory, profileImage.originalFilename)
val idImagePath: Path = Paths.get(imageDirectory, fileIdImage.originalFilename)
Files.write(profileImagePath, profileImage.bytes);
Files.write(idImagePath, fileIdImage.bytes);
JsonResponse(HttpStatus.OK, "Saved freelancer} ").createResponseEntity()
} catch (e: Exception) {
JsonResponse(HttpStatus.INTERNAL_SERVER_ERROR, e.message.toString()).createResponseEntity()
}
}
The request from the front end using vue:
The console output of the formdata:
Freelancer model:
#Entity
data class Freelancer(
#Id
val id: Int,
//maps ID to freelancer primary key
#MapsId
#OneToOne(targetEntity = User::class)
#JoinColumn(name = "freelancer_id")
//ignores the freelancer id because it is already mapped to val id
#JsonIgnore
val freelancerId: User,
val firstName: String? = null,
val lastName: String? = null,
val dateOfBirth: Date? = null,
val kvk: String? = null,
val btw: String? = null,
val phone: String? = null,
val street: String? = null,
val zipcode: String? = null,
val city: String? = null,
val housenumber: Int? = 0,
val addition: String? = null,
val nameCardHolder: String? = null,
val iban: String? = null,
val referral: String? = null,
val specialism: String? = null,
val aboutYou: String? = null,
val motivation: String? = null,
val workExperience: Int? = null,
val driverLicense: Boolean? = null,
val ownTransport: Boolean? = null,
val identificationImage: String? = null,
val smallBusinessScheme: Boolean? = false,
val profileImage: String? = null,
val previousWorkedPlatform: String? = null,
val servicesAmount: Int? = null,
val previousWorkedRating: Int? = null,
val foundBy: String? = null,
val privacyStatement: Boolean? = null,
)

I solved it by adding ID to the Json object I was sending to the backend, because my model has a one-to-one relation with another model I had to include it when mapping the Json to the model.

Related

Server side pagination in Graphql Scala

I need to do server side pagination in graphql in scala. I have seven reports and have used one graphql query with different operations to get the data. Now I need to add server side pagination to it and I am not able to do that. Any help would be appreciated. Below are my code:
Schema:
val PanelNominationStatusReportDataType = ObjectType(
"PanelNominationStatus",
"Dashboard Reports",
fields[Unit, PanelRewardSatusDetail](
Field("awardName", OptionType(StringType), resolve = _.value.awardName),
Field("nominatorEmail", OptionType(StringType), resolve = _.value.nominatorEmail),
Field("nomineeEmail", OptionType(StringType), resolve = _.value.nomineeEmail),
Field("nomineeLocation", OptionType(StringType), resolve = _.value.nomineeLocation),
Field("approverEmail", OptionType(StringType), resolve = _.value.approverEmail),
Field("citation", OptionType(StringType), resolve = _.value.citation),
Field("businessJustification", OptionType(StringType), resolve = _.value.businessJustification),
Field("rating", OptionType(IntType), resolve = _.value.rating),
Field("votingStatus", OptionType(StringType), resolve = _.value.votingStatus),
Field("nominatedDate", OptionType(StringType), resolve = _.value.nominatedDate),
Field("approvedDate", OptionType(StringType), resolve = _.value.approvedDate)
)
)
Graphql Query:
Field(
"PanelNominationStatus",
ListType(PanelNominationStatusReportDataType),
description = Some("Returns the Employee Reward Report Data"),
arguments = companyIdType :: rewardNamesType :: startDateType :: endDateType :: Nil,
resolve = { c =>
c.ctx.getPanelStatusReport(c.arg(companyIdType), c.arg(startDateType), c.arg(endDateType), c.arg(rewardNamesType))
})
DataRepo:
def getPanelStatusReport(companyId: Int, startDate: Long, endDate: Long, rewardNames: Seq[String]): List[PanelRewardSatusDetail] = {
val redemptionReport = Await.result(reportsModel.findPanelRewardStatusDetailsReport(companyId, rewardNames, startDate, endDate), 20.seconds).toList
redemptionReport
}
And at last the model:
def findPanelRewardStatusDetailsReport(companyId: Int, rewardNames: Seq[String], startDate: Long, endDate: Long): Future[Seq[PanelRewardSatusDetail]] = {
val df = new SimpleDateFormat("dd-MM-yyyy")
val start = stringToDateTime(df.format(startDate * 1000L), None).toDateTime()
val end = stringToDateTime(df.format(endDate * 1000L), None).toDateTime()
val rewardFilter = if(rewardNames.nonEmpty) "AND vrrc.reward_name IN (" + rewardNames.map(a => "'" + a + "'").mkString(",") + ")" else ""
implicit val getOrdersResult = GetResult(r => PanelRewardSatusDetail(r.<<, r.<<, r.<<, r.<<, r.<<, r.<<, r.<<, r.<<, r.<<, r.<<, r.<<))
val q = sql"""select vrrc.reward_name, (select login from users where id=vrur.sender_id), (select login from users where id=vrur.receiver_ids), (select city_name from cities where id=(select city_id from users where id=vrur.receiver_ids)), (select login from users where id=approver_user_id), vrur.comment, vrur.business_justification, vrpa.rating, CASE WHEN vrpa.is_approved = 1 THEN 'VOTED' ELSE 'NOT VOTED' END, date(vrpa.created_at), date(vrpa.approved_at) from vr_panel_approval vrpa inner join vr_user_reward vrur on vrur.id=vrpa.user_reward_id inner join vr_reward_config vrrc on vrrc.id=vrur.reward_config_id where vrrc.company_id = $companyId and date(vrpa.created_at) between date($start) and date($end) #$rewardFilter"""
db.run(q.as[PanelRewardSatusDetail])
}
My request query:
{
"query": "query PanelNominationStatus($startDate: Long!, $endDate: Long!, $companyId: Int!, $rewardNames: [String!]!) { PanelNominationStatus( startDate: $startDate, endDate: $endDate, companyId: $companyId, rewardNames: $rewardNames ) { awardName nominatorEmail nomineeEmail nomineeLocation approverEmail citation businessJustification rating votingStatus nominatedDate approvedDate }}",
"operationName": "PanelNominationStatus",
"variables": {
"startDate": 1285891200,
"endDate": 1576108800,
"companyId": 355,
"rewardNames": ["PANEL AWARD FEBRUARY", "PANEL AWARD MARCH"]
}
}
I can make it possible using limit in the query and accepting it in the query but I need to send the total count of rows in the response as well. But I am not able to figure out where to make change in schema.
You just need to define another GraphQL type for your result which also contains the count,
val PanelNominationStatusResultType = ObjectType(
"PanelNominationStatusResult",
"Dashboard Reports",
fields[Unit, List[PanelRewardSatusDetail]](
Field(
"count",
IntType,
description = Some("count of nomination-status-reports in this response"),
resolve = _.value.length
),
Field(
"panelNominationStatusList",
ListType(PanelNominationStatusReportDataType),
description = Some("list of nomination-status-reports"),
resolve = _.value
)
)
)
Now, as for your query,
Field(
"panelNominationStatusResult",
PanelNominationStatusResultType,
description = Some("Returns the details of ............"),
arguments = companyIdType :: rewardNamesType :: startDateType :: endDateType :: Nil,
resolve = { c =>
c.ctx.getPanelStatusReport(c.arg(companyIdType), c.arg(startDateType), c.arg(endDateType), c.arg(rewardNamesType))
}
)
If you want the totalCount, then first of all you need to change your getPanelStatusReport method to also return the totalCount
def findPanelRewardStatusDetailsReport(
companyId: Int,
rewardNames: Seq[String],
startDate: Long,
endDate: Long
): Future[(Int, Seq[PanelRewardSatusDetail])] = ???
// updated result type
val PanelNominationStatusResultType = ObjectType(
"PanelNominationStatusResult",
"Dashboard Reports",
fields[Unit, (Int, List[PanelRewardSatusDetail])](
Field(
"totalCount",
IntType,
description = Some("total count of nomination-status-reports"),
resolve = _.value._1
),
Field(
"count",
IntType,
description = Some("count of nomination-status-reports in this response"),
resolve = _.value._2.length
),
Field(
"panelNominationStatusList",
ListType(PanelNominationStatusReportDataType),
description = Some("list of nomination-status-reports"),
resolve = _.value._2
)
)
)

how can i parse json weather response

this is my response from weather map api
{
"message": "accurate",
"cod": "200",
"count": 3,
"list": [
{
"id": 2641549,
"name": "Newtonhill",
"coord": {
"lat": 57.0333,
"lon": -2.15
},
"main": {
"temp": 275.15,
"pressure": 1010,
"humidity": 93,
"temp_min": 275.15,
"temp_max": 275.15
},
"dt": 1521204600,
"wind": {
"speed": 9.3,
"deg": 120,
"gust": 18
},
"sys": {
"country": ""
},
"rain": null,
"snow": null,
"clouds": {
"all": 75
},
"weather": [
{
"id": 311,
"main": "Drizzle",
"description": "rain and drizzle",
"icon": "09d"
}
]
}
how can i get the description i did get the temperature using a retrofit by seriazable object but i could'nt get the weather description
i did that to get temperature and the country
class WeatherResponse {
#SerializedName("sys")
var sys: Sys? = null
#SerializedName("main")
var main: Main? = null
#SerializedName("weather")
var weather: Weather? = null
}
class Main {
#SerializedName("temp")
var temp: Float = 0.0f
}
and i my main class im using a callback
fun getCurrentData() {
val retrofit = Retrofit.Builder()
.baseUrl(BaseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
val service = retrofit.create(WeatherService::class.java)
val call = service.getCurrentWeatherData(lat, lon, AppId)
call.enqueue(object : Callback<WeatherResponse> {
override fun onResponse(call: Call<WeatherResponse>, response: Response<WeatherResponse>) {
if (response.code() == 200) {
val weatherResponse = response.body()!!
var temp = (weatherResponse.main!!.temp - 273).toString().substring(0,3) + " ÂșC"
tmp.text=temp
}
}
override fun onFailure(call: Call<WeatherResponse>, t: Throwable) {
}
})
}
Here is POJO class for your JSON. It now can be parsed easily.
WeatherResponse.kt
data class WeatherResponse(
#SerializedName("cod")
val cod: String? = null,
#SerializedName("count")
val count: Int? = null,
#SerializedName("list")
val list: List<X?>? = null,
#SerializedName("message")
val message: String? = null
) {
data class X(
#SerializedName("clouds")
val clouds: Clouds? = null,
#SerializedName("coord")
val coord: Coord? = null,
#SerializedName("dt")
val dt: Int? = null,
#SerializedName("id")
val id: Int? = null,
#SerializedName("main")
val main: Main? = null,
#SerializedName("name")
val name: String? = null,
#SerializedName("rain")
val rain: Any? = null,
#SerializedName("snow")
val snow: Any? = null,
#SerializedName("sys")
val sys: Sys? = null,
#SerializedName("weather")
val weather: List<Weather?>? = null,
#SerializedName("wind")
val wind: Wind? = null
)
data class Clouds(
#SerializedName("all")
val all: Int?
)
data class Coord(
#SerializedName("lat")
val lat: Double? = null,
#SerializedName("lon")
val lon: Double? = null
)
data class Main(
#SerializedName("humidity")
val humidity: Int? = null,
#SerializedName("pressure")
val pressure: Int? = null,
#SerializedName("temp")
val temp: Double? = null,
#SerializedName("temp_max")
val tempMax: Double? = null,
#SerializedName("temp_min")
val tempMin: Double? = null
)
data class Sys(
#SerializedName("country")
val country: String?
)
data class Weather(
#SerializedName("description")
val description: String? = null,
#SerializedName("icon")
val icon: String? = null,
#SerializedName("id")
val id: Int? = null,
#SerializedName("main")
val main: String? = null
)
data class Wind(
#SerializedName("deg")
val deg: Int? = null,
#SerializedName("gust")
val gust: Int? = null,
#SerializedName("speed")
val speed: Double? = null
)
}
You can get Weather description by using
var description = weatherResponse.list?.get(0)?.weather?.get(0)?.description

json serialization of an object

I am pretty new in swift and trying to make a http post request using an api with some properties.
I have defined following class
class Order {
var address1 : String?
var address2 : String?
var cellPhone : String?
var city : String?
var countryName : String?
var orderDate : String?
var orderStatus : Int?
var orderedProductList : Array<OrderedProduct>?
var paymentTransactionId : String?
var state : String?
var zip : String?
var countryId : Int?
var orderId : Int?
var orderTotal : Int?
var paymentMethodId : Int?
var userId : Int?
init(address1:String?, address2:String?, cellPhone:String?, city:String?, countryName:String?, orderDate:String?,orderStatus:Int?,orderedProductList:Array<OrderedProduct>?, paymentTransactionId:String?, state:String?, zip:String?, countryId:Int?, orderId:Int?, orderTotal:Int?, paymentMethodId:Int?, userId:Int?)
{
self.address1 = address1
self.address2 = address2
self.cellPhone = cellPhone
self.city = city
self.countryName = countryName
self.countryId = countryId
self.orderDate = orderDate
self.orderStatus = orderStatus
self.paymentTransactionId = paymentTransactionId
self.state = state
self.zip = zip
self.orderId = orderId
self.orderTotal = orderTotal
self.paymentMethodId = paymentMethodId
self.userId = userId
self.orderedProductList = orderedProductList
}
}
Order Instance is:
var totalOrderInfo = Order(address1: address, address2: apartment, cellPhone: phone, city: city, countryName: cName, orderDate: "\(year)-\(month)-\(day)T\(hour):\(minutes):\(seconds)", orderStatus: 1, orderedProductList: orderedProductList, paymentTransactionId: transctionID, state: state, zip: zip, countryId: cId, orderId: 0, orderTotal: returnValue1, paymentMethodId: 1, userId: userID)
The JSON representation of totalOrderInfo would be the following:
{"address1":"Mirpur","address2":"D6, f8","cellPhone":"01852540565","city":"fghff","countryName":"Bangladesh","orderDate":"2017-02-25T11:28:24","orderStatus":1,"orderedProductList":[{"discount":0.0,"orderDetailId":0,"price":30000.0,"quantity":1,"shippingCharge":50.0,"supplierId":0,"tax":0.0,"type":{"isBook":false,"typeId":0},"productId":5,"productViews":0},{"discount":0.0,"orderDetailId":0,"price":50000.0,"quantity":1,"shippingCharge":50.0,"supplierId":0,"tax":0.0,"type":{"isBook":false,"typeId":0},"productId":8,"productViews":0},{"discount":0.0,"orderDetailId":0,"price":2000.0,"quantity":1,"shippingCharge":50.0,"supplierId":0,"tax":0.0,"type":{"isBook":false,"typeId":0},"productId":9,"productViews":0}],"paymentTransactionId":"1215455638874521","state":"fyy","zip":"4525","countryId":23,"orderId":0,"orderTotal":82000.0,"paymentMethodId":1,"userId":0}
How can I serialize the totalOrderInfo instance and get the above JSON??
Thanks
You could use a library, such as: Object Mapper
In your case your class Order would be like this:
class Order: Mappable {
var address1 : String?
var address2 : String?
var cellPhone : String?
var city : String?
var countryName : String?
var orderDate : String?
var orderStatus : Int?
var orderedProductList : Array<OrderedProduct>?
var paymentTransactionId : String?
var state : String?
var zip : String?
var countryId : Int?
var orderId : Int?
var orderTotal : Int?
var paymentMethodId : Int?
var userId : Int?
init?(map: Map){
}
init(address1:String?, address2:String?, cellPhone:String?, city:String?, countryName:String?, orderDate:String?,orderStatus:Int?,orderedProductList:Array<OrderedProduct>?, paymentTransactionId:String?, state:String?, zip:String?, countryId:Int?, orderId:Int?, orderTotal:Int?, paymentMethodId:Int?, userId:Int?)
{
self.address1 = address1
self.address2 = address2
self.cellPhone = cellPhone
self.city = city
self.countryName = countryName
self.countryId = countryId
self.orderDate = orderDate
self.orderStatus = orderStatus
self.paymentTransactionId = paymentTransactionId
self.state = state
self.zip = zip
self.orderId = orderId
self.orderTotal = orderTotal
self.paymentMethodId = paymentMethodId
self.userId = userId
self.orderedProductList = orderedProductList
}
mutating func mapping(map: Map){
address1 <- map["address1"]
address2 <- map["address2"]
cellPhone <- map["cellPhone"]
city <- map["city"]
countryName <- map["countryName"]
countryId <- map["countryId"]
orderDate <- map["orderDate"]
orderStatus <- map["orderStatus"]
paymentTransactionId <- map["paymentTransactionId"]
state <- map["state"]
zip <- map["zip"]
orderId <- map["orderId"]
orderTotal <- map["orderTotal"]
paymentMethodId <- map["paymentMethodId"]
userId <- map["userId"]
orderedProductList <- map["orderedProductList"]
}
}
As you also have an Array<OrderedProduct> in your code, you will have to do the same to the OrderedProduct class.
After that, you can convert the model object to a JSON string using:
let order = Order(address1, address2.......)
let jsonString = order.toJSONString(prettyPrint: true)
If you want to know more about the library and how to install it, you can check the official documentation at their Github Project page
By the serialization of JSON data you will get dictionary, so add new initialization method from dictionary in your Order class as follows:
class Order {
.
.
.
.
init(dictionary: [String: AnyObject]) {
super.init()
address1 = dictionary["address1"] as? String
address2 = dictionary["address2"] as? String
// and so on
}
Then where you load your JSON data you init your object from JSON dictionary:
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary
let order = Order(dictionary: json)
} catch let error as NSError {
print(error)
}
(where data is the received data from API)

Mongo DB DAO and Spray JSON :

My Mongo DB abstract Dao is defined as follows
abstract class DbMongoDAO1[K, T <: Keyable[K]] (implicit val manifestT: Manifest[T], val manifestK: Manifest[K])
extends DbDAO[K, T]
with DbDAOExtensions[K, T]
with MongoConnection2
with JsonDbImplicits
{
val thisClass = manifestT.runtimeClass
val simpleName = thisClass.getSimpleName
lazy val collection = db.getCollection(s"${DbMongoDAO1.tablePrefix}$simpleName")
override def insertNew(r:T): Result[String,T] = {
val json: String = r.toJson.compactPrint
collection.insertOne(Document(json))
KO("Not Implemented")
}
}
I'm getting an error in the following line of code when converting a case class to JSON.
Error:(31, 26) value toJson is not a member of type parameter T
val json: String = r.toJson.compactPrint
val json: String = r.toJson.compactPrint
The trait JsonDbImplicits is as follows
trait JsonDbImplicits extends DefaultJsonProtocol
with SprayJsonSupport with JodaImplicits {
implicit val json_UserEmail:RootJsonFormat[UserEmail] = jsonFormat5(UserEmail)
implicit val json_UserProfile:RootJsonFormat[UserProfile] = jsonFormat13(UserProfile)
implicit val json_UserSession:RootJsonFormat[UserSession] = jsonFormat5(UserSession)
}
The case classes UserEmail and UserProfile are defined as follows
case class UserEmail
(
// it is the full email address
#Key("_id") id: String
, account_id: String
, active: Boolean = false
, ts_created: DateTime = now
, ts_updated: DateTime = now
) extends Keyable[String]
trait DbUserEmail extends DbMongoDAO1[String,UserEmail]
and
case class UserProfile
(
// id is the same as AccountId
#Key("_id") id: String = UUID.randomUUID().toString
, gender: Option[String] = None
, first_name: Option[String] = Some("")
, last_name: Option[String] = Some("")
, yob: Option[Int] = None
, kids: Option[Int] = None
, income: Option[Int] = None
, postcode: Option[String] = None
, location: Option[Boolean] = Some(true)
, opt_in: Option[Boolean] = Some(true)
, third_party: Option[Boolean] = Some(true)
, ts_created: DateTime = now
, ts_updated: DateTime = now
) extends Keyable[String]
trait DbUserProfile extends DbMongoDAO1[String,UserProfile]
What am I missing?

Play 2.1 Json serialization of traits

The experimental "Inception" feature in Play 2.1 (Json.format[...]) only works for case classes (see here). How can I write my custom format implicit for a trait. I have the following construct:
sealed trait Plan {
def id: String
def name: String
def apps: Int
def users: Int
def testruns: Int
def price: Int
def prio: Int
}
And the following case classes which are extending the trait Plan.
case class Start(
id: String = "start",
name: String = "Start",
apps: Int = 1,
users: Int = 1,
testruns: Int = 10,
price: Int = 99,
prio: Int = 30) extends Plan
case class Pro(
id: String = "pro",
name: String = "Pro",
apps: Int = 2,
users: Int = 5,
testruns: Int = 25,
price: Int = 299,
prio: Int = 20) extends Plan
case class Premium(
id: String = "premium",
name: String = "Premium",
apps: Int = -1,
users: Int = -1,
testruns: Int = -1,
price: Int = 799,
prio: Int = 10) extends Plan
Now I need to write my custom implicit format val in the Plan companion object. I tried:
object Plan {
implicit val planFormats = (
(__ \ "id").format[String] and
(__ \ "name").format[String] and
(__ \ "apps").format[Int] and
(__ \ "users").format[Int] and
(__ \ "testruns").format[Int] and
(__ \ "price").format[Int] and
(__ \ "prio").format[Int]
)(Plan.apply, unlift(Plan.unapply))
}
However, a trait hasn't an apply or unapply method. What is the correct way to provide an implicit val for the json serialization in Play 2.1?
You simply have to provide your own function that creates a new instance from the given values.
Essentially a companion object to the trait that acts as a factory.
object Plan {
def apply(id: String, name: String, ...) = id match {
case "pro" => new Pro(id, name, ...)
...
}
def unapply(p: Person): Option[(String, String, ...)] = ...
}
Why are you using Traits and implementing case class ?
Why not using instances of classes, such as:
case class Plan (
id: String,
name: String,
apps: Int,
users: Int,
testruns: Int,
price: Int,
prio: Int
)
val start = new Plan("start", "Start", 1, 1, 10, 99, 30)
val pro = new Plan("pro", "Pro", 2, 5, 25, 299, 20)
val premium = new Plan("premium", "Premium", -1, -1, -1, 799, 10)
and then, you can keep your Json formatter:
object Plan {
implicit val planFormats = (
(__ \ "id").format[String] and
(__ \ "name").format[String] and
(__ \ "apps").format[Int] and
(__ \ "users").format[Int] and
(__ \ "testruns").format[Int] and
(__ \ "price").format[Int] and
(__ \ "prio").format[Int]
)(Plan.apply, unlift(Plan.unapply))
}