Is it possible to convert case class(in scala) or scala class to json by Yasson? And how? - jsonb

I want to use Yasson to convert scala class to json.
Is it possible?
case class Person(first: String, last: String)
val person = Person("ha","ha")
jsonb.tojson(person)

Related

Convert string to enum in ruby (in controller)

I am creating a webhook route where I will receive a JSON, so I am converting it into an object as follows:
data = JSON.parse(request.body.read, object_class: OpenStruct)
And that generates the object I want. This object however has a property that is similar to an ENUM, which has some 'predictable' values
being: PURCHASE_APPROVED, PURCHASE_CANCELED.
They come as a string, so I tried to do the following to convert them
events = { PURCHASE_CANCELED: 0, PURCHASE_APPROVED: 1 }
So I want to take the value that came as a string and transform it into an enum, the way I managed to convert the data was:
data.event = events[data.event.to_sym]
But the data doesn't become an enum, I can't use some properties like the
data.event.PURCHASE_APPROVED?
Is there any simple way to do this within the controller? Or would I have to create a class and specify each property just to have 1 enum?

Validate at least 1 of a set of args is present in Kotlin class constructor

Scenario
I need to create a Kotlin class that can receive up to 4 arguments for its constructor, but only requires at least 1 out of a set of 3 (the fourth being entirely optional). To illustrate:
class Pie {
// Completely optional, the constructor should use it if present, otherwise it may be null.
var topping: String?
// Of these three [fillingA, fillingB, fillingC] 1 or more must be present.
var fillingA: String?
var fillingB: String?
var fillingC: String?
}
Thoughts
I've attempted to use Kotlin init{} blocks for validation, or telescoping constructors, but it gets ugly fast and I've yet to solve the issue. I have not found anything in the kotlinlang.org docs on primary/secondary constructors that is more elegant, though. My preference would be to find something similar to the #Size or #NotNull annotations, but I have failed to locate anything close.
It is important to note that I am using this class as a model for an API response.
Question
What is the most concise way to validate that a Kotlin class has at least 1 of a set of arguments passed to its constructor?
Are this fillings interchangeable? You could assume that fillingA is always required and the other ones are optional, something like this:
class Pie constructor(
val fillingA: String,
val fillingB: String? = null,
val fillingC: String? = null,
val topping: String? = null
){...}

Kotlin cast from LinkedHashMap<String, String> to String?

I'm parsing a very simple YAML file.
Here is my code:
val yaml = Yaml()
val inputStream: InputStream = FileInputStream("permissions.yml")
val obj = yaml.load<LinkedHashMap<String, String>>(inputStream)
println(obj.get("accepted_groups")) // prints [A, B]
val group = obj.get("accepted_groups") // crashes
The error is java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class java.lang.String
So how does println manage to print the object? How can I retrieve an Array from this LinkedHashMap?
The problem is that the values in your YAML file aren't (all) strings. I.e. it looks something like
accepted_groups:
- A
- B
not
accepted_groups: "[A, B]"
So LinkedHashMap<String, String> is simply the wrong type to use.
What is the right type, can't be said without knowing:
the actual structure of the file;
which library Yaml class comes from (it isn't Kotlin standard library, or Spring Boot which you mention in tags).
LinkedHashMap<String, Any> will probably work, but isn't the best choice.
So how does println manage to print the object?
By calling toString, as it does for any object.
The problem with
val group = obj.get("accepted_groups")
is that by using LinkedHashMap<String, String> the type inferred for group is String but the actual value stored there isn't.

Kotlin - Using Enums to retrieve a Char

Being a little new to OOP concepts, enums in Kotlin are a bit confusing to me. My caveman interpretation is that enums are used to store non changing variables. I'm making a simple Tic-Tac-Toe app and simply want to store the values 'X', 'Y', and '-' all as Chars. Where is my confusion? Is there a better way to retrieve a particular set of Chars from a "library"? Here is my current assumption in code:
enum class markers(char: Char){
X('X'), O('O'), EMPTY('-')
}
//To access the enums, thought it would be something like this
fun printX(){
println(markers.X)
}
You want to have the property char instead of the enum constants‘ name, change to:
fun printX(){
println(markers.X.char)
}
Also make char a val so that it’s accessible as a property: enum class markers(val char: Char)
enum class markers(private val char: Char){
X('X'), O('O'), EMPTY('-');
override fun toString() = char.toString()
}
markers.values().forEach(::print)

Access all fields from parent method

I'm developing an application where data is stored in mongodb. There are several collections and of course all of them have some common fields (like Id, creation date, etc) and methods (for example Insert). In my vision, I need to create base model struct with needed fields and methods, and then embed this struct into my models. Unfortunately, this doesn't work because method defined for base model doesn't see child fields.
I don't know how to explain further. Here is code in playground:
https://play.golang.org/p/_x-B78g4TV
It uses json instead of mgo, but idea is still the same.
I want the output to be:
Saving to 'my_model_collection'
{"_id":42, "foo": "Some value for foo", "bar": "Here we set some value for bar"}
Not:
Saving to 'my_model_collection'
{"_id":42}
Writing that insert method for each my model seems to be against DRY, so what is correct/idiomatic way to achieve this in Go?
This is not possible, for details see my answer: Can embedded struct method have knowledge of parent/child?
You may do 2 things:
1. Abandon method and make it a helper / utility function
The idea is to make Insert() detached from BaseModel and make it a simple function, and you pass the document to it which you want to save.
I personally prefer this option, as it requires less hassle and maintenance. It could look like this:
func Insert(doc interface{}) {
j, _ := json.Marshal(doc)
fmt.Println(string(j))
}
You also had a "typo" in the tags:
type MyModel struct {
*BaseModel
Foo string `json:"foo"`
Bar string `json:"bar"`
}
Using it:
Insert(m)
Output (try it on the Go Playground):
{"_id":42,"foo":"Some value for foo","bar":"Here we set some value for bar"}
2. Pass the (pointer to) the wrapper to the BaseModel
In this approach, you have to pass a pointer to the embedder struct so the BaseModel.Insert() method will have a pointer to it, and may use that to save / marshal. This is basically manually maintaining a "reference" to the struct that embeds us and is being saved/marshalled.
This is how it could look like:
type BaseModel struct {
Id int `json:"_id"`
collectionName string
wrapper interface{}
}
And then in the Insert() method save the wrapper:
func (m *BaseModel) Insert() {
fmt.Printf("Saving to '%v'\n", m.collectionName)
j, _ := json.Marshal(m.wrapper)
fmt.Println(string(j))
}
Creation is slightly more complex:
func NewMyModel() *MyModel {
mm := &MyModel{
Foo: "Some value for foo",
}
mm.BaseModel = NewBaseModel("my_model_collection", mm)
return mm
}
But output is as you wish:
Saving to 'my_model_collection'
{"_id":42,"foo":"Some value for foo","bar":"Here we set some value for bar"}
Try it on the Go Playground.
In Golang, you can't override a parent method, because that's not how polymorphism works. The Insert method will apply on the BaseModel member, and not on MyModel.
Also, you're trying to use mgo in an improper way. If you want to insert documents in collections, then you already have an Insert method for a Collection struct which works on interface{} types (same as json.Marshal).
Of course, you can have a BaseModel that will contain fields shared by all of your models. In fact, GORM uses a similar approach and provides a Model struct to be included in every child model.
Well known problem ;o) Member variables (like collectionName) which name starts with lower letter are not visible from other packages (like json). Therefore change struct to:
type BaseModel struct {
Id int `json:"_id"`
CollectionName string `json:"collectionName"`
}
and world will be better place to live in.

Resources