Can I add hooks to database operations in SORM? - sorm

In many cases, functions need to be applied before and after database operations. An example is encryption. Data needs to be encrypted before INSERTs and UPDATEs. It needs to be decrypted after SELECTs. Would it be possible to add such hooks with SORM?

Well, theoretically you can hook into SORM by simply overriding it's methods, like so:
case class Thing( normalField : String, encryptedField : String )
object Db extends Instance (...) {
override def save
[ T <: AnyRef : TypeTag ]
( value : T )
: T with Persisted
= value match {
case value : Thing =>
super.save(value.copy(encryptedField = encrypt(value.encryptedField)))
case _ => super.save(value)
}
}
But SORM 0.3.* was not designed for customizations like that, and hooking into querying functionality will require quite much more effort and boilerplate. I'm quite unsure whether problems like that are at all of SORM's concern, because you have a rather confusing case.
Anyway, you have other ways to solve your issue on the application side. Here's a couple straight outta head:
1. The classical DAO approach:
object Dao {
def saveA( a : Thing ) =
Db.save(a.copy(encryptedField = encrypt(a.encryptedField)))
def fetchAByNormalField( a : String ) =
Db.query[Thing].whereEqual("normalField", a).fetch()
.map(a => a.copy(encryptedField = decrypt(a.encryptedField)))
}
The con here is that SORM's API is so simple that creating a DAO over it primarily introduces only a redundant abstraction and boilerplate.
2. The converters approach:
case class Thing( normalField : String, decryptedField : String ){
def encrypted = EncryptedThing( normalField, encrypt(decryptedField) )
}
case class EncryptedThing( normalField : String, encryptedField : String ){
def decrypted = Thing( normalField, decrypt(encryptedField) )
}
Note that you should register the EncyptedThing, not the Thing, with SORM:
object Db extends Instance( entities = Set(Entity[EncyptedThing]() ) )
You can use it like so:
val thing = Thing(...)
Db.save(thing.encrypted)
val thing = Db.query[EncryptedThing].fetch().map(_.decrypted)
SORM will bark at you if you accidentally forget to trigger the conversion, for trying to save a value of a type not registered with it. It should be noted though that the barking will be at runtime.

Related

Kotlin field Assignment via Scope Function (Apply )

What is the difference between two such field assignments? Actually, the first way seems very readable but I come across second way in many code samples.
Is there a special reason?
class Login {
var grantToken = GrantTokenRequest()
fun schema(schema: String) {
this.grantToken.schema = schema
}
}
class Login {
var grantToken = GrantTokenRequest()
fun schema(schema: String) = apply { this.grantToken.schema = schema }
}
The difference is the return type of the function schema.
The first way returns Unit.
The second way returns the type of what this is in the current scope.
In your case the second way will return the Login type, so the instance of this class.
The second approach is just more idiomatic in cases when you are "configuring an object". From Kotlin docs about apply
The common case for apply is the object configuration. Such calls can be read as “apply the following assignments to the object [and return the object itself].”
One reason why the second approach is useful, is because it makes call chaining possible. The general term for this kind of "return this" method chaining is "fluent interface".
val login = Login()
.schema("...")
.anotherFunctionOnLoginClass(...)
.moreCallChaining(...)
An additional note: The this used inside the apply lambda is not needed, because apply already sets this as the Receiver. The code could be simplified to
fun schema(schema: String) = apply { grantToken.schema = schema }

Using a Jackson attribute to accumulate state as a byproduct of serialization

Here's my scenario:
I have a deep compositional tree of POJOs from various classes. I need to write a utility that can dynamically process this tree without having a baked in understanding of the class/composition structure
Some properties in my POJOs are annotated with a custom annotation #PIIData("phone-number") that declares that the property may contain PII, and optionally what kind of PII (e.g. phone number)
As a byproduct of serializing the root object, I'd like to accumulate a registry of PII locations based on their JSON path
Desired data structure:
path
type
household.primaryEmail
email-address
household.members[0].cellNumber
phone-number
household.members[0].firstName
first-name
household.members[1].cellNumber
phone-number
I don't care about the specific pathing/location language used (JSON Pointer, Json Path).
I could achieve this with some reflection and maintenance of my own path, but it feels like something I should be able to do with Jackson since it's already doing the traversal. I'm pretty sure that using Jackson's attributes feature is the right way to attach my object that will accumulate the data structure. However, I can't figure out a way to get at the path at runtime. Here's my current Scala attempt (hackily?) built on top of a filter that is applied to all objects through a mixin:
object Test {
#JsonFilter("pii")
class PiiMixin {
}
class PiiAccumulator {
val state = mutable.ArrayBuffer[String]()
def accumulate(test: String): Unit = state += test
}
def main(args: Array[String]): Unit = {
val filter = new SimpleBeanPropertyFilter() {
override def serializeAsField(pojo: Any, jgen: JsonGenerator, provider: SerializerProvider, writer: PropertyWriter): Unit = {
if (writer.getAnnotation(classOf[PiiData]) != null) {
provider.getAttribute("pii-accumulator").asInstanceOf[PiiAccumulator].accumulate(writer.getFullName.toString)
}
super.serializeAsField(pojo, jgen, provider, writer)
}
override def include(writer: BeanPropertyWriter): Boolean = true
override def include(writer: PropertyWriter): Boolean = true
}
val provider = new SimpleFilterProvider().addFilter("pii", filter)
val mapper = new ObjectMapper()
mapper.addMixIn(classOf[Object], classOf[PiiMixin])
val accum = new PiiAccumulator()
mapper.writer(provider)
.withAttributes("pii-accumulator", accum)
.writeValueAsString(null) // Pass in any arbitrary object here
}
}
This code has enabled me to dynamically buffer up a list of property names that contain PII, but I can't figure out how to get their locations within the resulting JSON doc. Perhaps the Jackson architecture somehow precludes knowing that at runtime. Is there some other place I can hook in to do something like this, perhaps while converting to a JsonNode?
Thanks!
Okay, found it. You can access the recursive path/location during serialization via JsonGenerator.getOutputContext.pathAsPointer(). So by changing my code above to the following:
if (writer.getAnnotation(classOf[PIIData]) != null) {
provider.getAttribute("pii").asInstanceOf[PiiAccumulator]
.accumulate(jgen.getOutputContext.pathAsPointer().toString + "/" + writer.getName)
}
I'm able to dynamically buffer a list of special locations in the resulting JSON document for further dynamic processing.

Kotlin multiple class for data storage

I am developing a simple Android app, that will display an icon of a vehicle and the user can click on the icon to display the vehicle information. I want to load the data dynamically when I build the app i.e. the data will come from an external source including the picture for the icon.
I am new to Kotlin and not sure what to search for to understand a suitable solution. What is the correct way to define the data, is it best to create an class as below then create an array of the class (not sure if this is possible)
public class VehicleSpec()
{
var OEM: String? = null
var ModelName: String? = null
var EngineSize: String? = null
}
Or would be better to create a multiple dimension array and then link the data to the cells?
var VehicleSpec = arrayOf(20,20)
VehicleSpec[0][0] = Null //OEM
VehicleSpec[0][1] = Null //ModelName
VehicleSpec[0][2] = Null //EngineSize
What is the best way to set up the data storage, is there any good references to understand how this should be setup?
What is the correct way to define the data, is it best to create an class as below then create an array of the class
Using an array for the properties of an object is not making the full use of the type safety you have in Kotlin (and even Java for that matter).
If what you want to express is multiple properties of an object, then you should use a class to define those properties. This is especially true if the properties have different types.
There is no performance difference between an array and a class, because you'll get a reference to the heap in both cases. You could save on performance only if you convert your multi-dimensional array approach to a single-dimension array with smart indexing. Most of the time, you should not consider this option unless you are handling a lot of data and if you know that performance is an issue at this specific level.
(not sure if this is possible)
Defining lists/arrays of classes is definitely possible.
Usually, for classes that are only used as data containers, you should prefer data classes, because they give you useful methods for free, and these methods totally make sense for simple "data bags" like in your case (equals, hashcode, component access, etc.).
data class Vehicle(
val OEM: String,
val ModelName: String,
val EngineSize: String
)
Also, I suggest using val instead of var as much as possible. Immutability is more idiomatic in Kotlin.
Last but not least, prefer non-null values to null values if you know a value must always be present. If there are valid cases where the value is absent, you should use null instead of a placeholder value like empty string or -1.
First at all, using the "class aprocah" makes it easy for you to understand and give you the full benefits of the language itself... so dont dry to save data in an array .. let the compiler handle those stuff.
Secondly i suggest you have maybe two types (and use data classes ;-) )
data class VehicleListEntry(
val id: Long,
val name: String
)
and
data class VehicleSpec(
val id: Long,
val oem: String = "",
val modelName: String = "",
val engineSize: String = ""
)
from my perspective try to avoid null values whenever possible.
So if you have strings - which you are display only - use empty strings instead of null.
and now have a Model to store your data
class VehicleModel() {
private val specs: MutableMap<Long, VehicleSpec> = mutableMapOf()
private var entries: List<VehicleListEntry> = listOf()
fun getSpec(id: Long) = specs[id]
fun addSpec(spec: VehicleSpec) = specs[spec.id] = spec
fun getEntries(): List<VehicleListEntry> = entries
fun setEntries(data: List<VehicleListEntry>) {
entries = data.toMutableList()
}
}
You could also use a data class for your model which looks like
data class VehicleModel(
val specs: MutableMap<Long, VehicleSpec> = mutableMapOf(),
var entries: List<VehicleListEntry> = listOf()
)
And last but not least a controller for getting stuff together
class VehicleController() {
private val model = VehicleModel()
init{
// TODO get the entries list together
}
fun getEntries() = model.entries
fun getSpec(id: Long) : VehicleSpec? {
// TODO load the data from external source (or check the model first)
// TODO store the data into the model
// TODO return result
}
}

Validation Data Class Parameters Kotlin

If I am modeling my value objects using Kotlin data classes what is the best way to handle validation. Seems like the init block is the only logical place since it executes after the primary constructor.
data class EmailAddress(val address: String) {
init {
if (address.isEmpty() || !address.matches(Regex("^[a-zA-Z0-9]+#[a-zA-Z0-9]+(.[a-zA-Z]{2,})$"))) {
throw IllegalArgumentException("${address} is not a valid email address")
}
}
}
Using JSR-303 Example
The downside to this is it requires load time weaving
#Configurable
data class EmailAddress(#Email val address: String) {
#Autowired
lateinit var validator: Validator
init {
validator.validate(this)
}
}
It seems unreasonable to me to have object creation validation anywhere else but in the class constructor. This is the place responsible for the creation, so that is the place where the rules which define what is and isn't a valid instance should be. From a maintenance perspective it also makes sense to me as it would be the place where I would look for such rules if I had to guess.
I did make a comment, but I thought I would share my approach to validation instead.
First, I think it is a mistake to perform validation on instantiation. This will make the boundary between deserialization and handing over to your controllers messy. Also, to me, if you are sticking to a clean architecture, validation is part of your core logic, and you should ensure with tests on your core logic that it is happening.
So, to let me tackle this how I wish, I first define my own core validation api. Pure kotlin. No frameworks or libraries. Keep it clean.
interface Validatable {
/**
* #throws [ValidationErrorException]
*/
fun validate()
}
class ValidationErrorException(
val errors: List<ValidationError>
) : Exception() {
/***
* Convenience method for getting a data object from the Exception.
*/
fun toValidationErrors() = ValidationErrors(errors)
}
/**
* Data object to represent the data of an Exception. Convenient for serialization.
*/
data class ValidationErrors(
val errors : List<ValidationError>
)
data class ValidationError(
val path: String,
val message: String
)
Then I have a framework specific implementations. For example a javax.validation.Validation implementation:
open class ValidatableJavax : Validatable {
companion object {
val validator = Validation.buildDefaultValidatorFactory().validator!!
}
override fun validate() {
val violations = validator.validate(this)
val errors = violations.map {
ValidationError(it.propertyPath.toString(), it.message)
}.toMutableList()
if (errors.isNotEmpty()) {
throw ValidationErrorException(errors = errors)
}
}
}
The only problem with this, is that the javax annotations don't play so well with kotlin data objects - but here is an example of a class with validation:
import javax.validation.constraints.Positive
class MyObject(
myNumber: BigDecimal
) : ValidatableJavax() {
#get:Positive(message = "Must be positive")
val myNumber: BigDecimal = myNumber
}
Actually, it looks like that validation is not a responsibility of data classes. data tells for itself — it's used for data storage.
So if you would like to validate data class, it will make perfect sense to set #get: validation on arguments of the constructor and validate outside of data class in class, responsible for construction.
Your second option is not to use data class, just use simple class and implement whole logic in the constructor passing validator there
Also, if you use Spring Framework — you can make this class Bean with prototype scope, but chances are it will be absolutely uncomfortable to work with such kind of spaghetti-code :)
I disagree with your following statement :
Seems like the init block is the only logical place since it executes after the primary constructor.
Validation should not be done at construction time, because sometimes, you need to have intermediate steps before getting a valid object, and it does not work well with Spring MVC for example.
Maybe use a specific interface (like suggested in previous answer) with a method dedicated to executing validation.
For the validation framework, I personnaly use valiktor, as I found it a lot less cumbersome that JSR-303

Scala class inheritance

Tagged as homework.
I'm having trouble in the object oriented world while trying to implement a class.
I'm implenting various functions to take action on lists, that I'm using to mock a set.
I'm not too worried about my logic on how to find union, for example, but really just the structure.
For eg:
abstract class parentSet[T] protected () {
def union(other:parentSet[T]):parentSet[T]
}
Now I want a new class extending parentSet:
class childSet[T] private (l: List[T]) extends parentSet[T] {
def this() = this(List())
private val elems = l
val toList = List[T] => new List(l)
def union(other:parentSet[T]):childSet[T] = {
for (i <- this.toList) {
if (other contains i) {}
else {l :: i}
}
return l
}
}
Upon compiling, I receive errors such that type childSet isn't found in def union, nor is type T to keep it parametric. Also, I assume my toList isn't correct as it complains that it isn't a member of the object; to name a few.
Where in my syntax am I wrong?
EDIT
Now I've got that figured out:
def U(other:parentSet[T]):childSet[T] = {
var w = other.toList
for (i <- this.toList) {
if (!(other contains i)) {w = i::w}
}
return new childSet(w)
}
Now, I'm trying to do the same operations with map, and this is what I'm working on/with:
def U(other:parentSet[T]):MapSet[T] = {
var a = Map[T,Unit]
for (i <- this.toList) {
if (!(other contains i)) {a = a + (i->())}
}
return new MapSet(elems + (a->()))
}
I still want to use toList to make it easily traversable, but I'm still getting type errors while messing with maps..
This code has a few problems:
It seems that you are not realizing that List[T] is an immutable type, meaning you cannot change its value once created. So if you have a List[T] and you call the :: method to prepend a value, the function returns a new list and leaves your existing one unchanged. Scala has mutable collections such as ListBuffer which may behave more like you expect. So when you return l, you're actually returning the original list.
Also, you have the order wrong in using ::. It should go i :: l, since :: is a right-binding function (because it ends with a :).
Lastly, in your union method you are doing (other contains i). Maybe it's just the Scala syntax that's confusing you, but this is the same as doing (other.contains(i)) and clearly contains is not a defined method of parentSet. It is a method on the List[T] type, but you're not calling contains on a list.
You tagged this as homework so I'm not going to fix your code, but I think you should
Look at some examples of correct Scala code involving lists, try here for starters
Play around in the Scala REPL and try creating and working with some lists, so you get a feel for how immutable collections work.
To answer your direct question, even though childSet is inheriting parentSet the original method specify parentSet as the return type and not childSet. You can either only use parentSet as the type OR you could specify the return type to be anything that inherits parentSet.