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

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

Related

Initialize non existing keys to empty array list

I have a class :
class Con {
private List<Ind> inds;
}
I am using Gson in the usual way to convert a JSON string to this class object. so in case, the JSON doesn't have the key inds present this variable inds is assigned a null value. Is there a way to assign inds an empty ArrayList instead?
My Thoughts:
One straightforward way could be once the Gson object is built. Go over all the null objects and assign them to the new ArrayList<>(). Is there a better approach?
public List<Ind> getInds() {
return inds;
}
Currently I am using the above getter in a code like : con.getInds().stream() which is causing NullPointerException.
I am not sure what would be a good way to resolve this. Instead of List Should I return an Optional or Should I modify this getter like
public List<Ind> getInds() {
inds==null?new ArrayList<>():inds;
}
The above will also resolve the NullPointerException. Not sure if there are pros and cons to using this approach. Although now there is no way to identify if the Json has a key with name inds or not. For the current code that I am writing this may not be required. But there is a meaning loss here certainly.
One solution to this would be to assign default values to the fields, for example:
class Con {
private List<Ind> inds = new ArrayList<>();
}
Gson will keep this default value; only if the field is present in the JSON data it will reassign the field value.
There are however a few things to keep in mind:
Your class needs a no-args constructor (implicit or explicit); otherwise Gson might create instances without invoking the initializer blocks of the class, and therefore the field will be null
If the field is present in JSON but has a JSON null value, then Gson will still set that as value
You cannot tell afterwards whether the field was present in JSON but had an empty JSON array as value, or whether it was missing

Spring Kotlin - Changed object to class and got error saying "classifier does not have a companion object and thus must be initialized"

I changed my code from this
object SomeHelper{}
to this
#Component
class SomeHelper{}
In my test class I wrote something like this:
class SomeHelperTester{
val cut = SomeHelper
//...
}
which used to work fine when SomeHelper was an object, but now the line val cut = SomeHelper is underlined with an error saying Classifier SomeHelper does not have a companion object, and thus must be initialized. How can I make this line of code work?
just add () behind it, like
val cut = SomeHelper()
This is down to the difference between an object (a singleton, with exactly one instance), and a class (of which you can create as many instances as you like).
When you declare a variable with an initialiser (as you do with cut), the initialiser needs to evaluate to an object. When SomeHelper was declared as an object, then it evaluates to the one and only instance, which works fine as an initialiser. But when it's declared as a class, then the class name alone doesn't mean anything.
What you need to do is to create an instance of the class, by calling its constructor. In this case, since you haven't specified a constructor, you get the default one which takes no parameters. So you can simply call it by appending an empty pair of brackets, and use that as the initialiser:
val cut = SomeHelper()

Exclude 0 from JSON response in Jackson Spring boot

I have a POJO like this.
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class Test {
private int a;
private String b;
}
I want to exclude the property 'a' if it has 0 value. String b is excluded with
#JsonInclude(JsonInclude.Include.NON_NULL)
Only way I could thing of is convert the int data type to Integer Object and set the value to NULL in the setter explicitly if it is 0.
Any other suggestions or correct solution will be appreciated
Option 1:
Do what you said: Change int to Integer and use #JsonInclude(Include.NON_NULL). Because primitive types have default values and their values cannot be compared to null you have to wrap the int to Integer. See Primitive Data Types. imho this is the cleaner way.
Option 2:
Use the way described in this answer and use #JsonInclude(Include.NON_DEFAULT) instead (see Jackson-annotations API), so that default values (and so also null values for objects) will be ignored.
Note:
If you only want to exclude the specific field (in your case the int/Integer - a - field) when it has a null-/default value and the other fields (in your case the String - b - field) should be included when they have null-/default values, put the annotation on field level.

How to keep non-nullable properties in late initialization

Following issue: In a client/server environment with Spring-Boot and Kotlin the client wants to create objects of type A and therefore posts the data through a RESTful endpoint to the server.
Entity A is realized as a data class in Kotlin like this:
data class A(val mandatoryProperty: String)
Business-wise that property (which is a primary key, too) must never be null. However, it is not known by the client, as it gets generated quite expensively by a Spring #Service Bean on the server.
Now, at the endpoint Spring tries to deserialize the client's payload into an object of type A, however, the mandatoryProperty is unknown at that point in time, which would result in a mapping exception.
Several ways to circumvent that problem, none of which really amazes me.
Don't expect an object of type A at the endpoint, but get a bunch of parameters describing A that are passed on until the entity has actually been created and mandatoryProperty is present . Quite cumbersome actually, since there are a lot more properties than just that single one.
Quite similar to 1, but create a DTO. One of my favorites, however, since data classes can't be extended it would mean to duplicate the properties of type A into the DTO (except for the mandatory property) and copy them over. Furthemore, when A grows, the DTO has to grow, too.
Make mandatoryProperty nullable and work with !! operator throughout the code. Probably the worst solution as it foils the sense of nullable and non-nullable variables.
The client would set a dummy value for the mandatoryProperty which is replaced as soon as the property has been generated. However, A is validated by the endpoint and therefore the dummy value must obey its #Pattern constraint. So each dummy value would be a valid primary key, which gives me a bad feeling.
Any other ways I might have overseen that are more feasible?
I don't think there is a general-purpose answer to this... So I will just give you my 2 cents regarding your variants...
Your first variant has a benefit which no other really has, i.e. that you will not use the given objects for anything else then they were designed to be (i.e. endpoint or backend purposes only), which however probably will lead to cumbersome development.
The second variant is nice, but could lead to some other development errors, e.g. when you thought you used the actual A but you were rather operating on the DTO instead.
Variant 3 and 4 are in that regard similar to 2... You may use it as A even though it has all the properties of a DTO only.
So... if you want to go the safe route, i.e. no one should ever use this object for anything else then its specific purpose you should probably use the first variant. 4 sounds rather like a hack. 2 & 3 are probably ok. 3 because you actually have no mandatoryProperty when you use it as DTO...
Still, as you have your favorite (2) and I have one too, I will concentrate on 2 & 3, starting with 2 using a subclass approach with a sealed class as supertype:
sealed class AbstractA {
// just some properties for demo purposes
lateinit var sharedResettable: String
abstract val sharedReadonly: String
}
data class A(
val mandatoryProperty: Long = 0,
override val sharedReadonly: String
// we deliberately do not override the sharedResettable here... also for demo purposes only
) : AbstractA()
data class ADTO(
// this has no mandatoryProperty
override val sharedReadonly: String
) : AbstractA()
Some demo code, demonstrating the usage:
// just some random setup:
val a = A(123, "from backend").apply { sharedResettable = "i am from backend" }
val dto = ADTO("from dto").apply { sharedResettable = "i am dto" }
listOf(a, dto).forEach { anA ->
// somewhere receiving an A... we do not know what it is exactly... it's just an AbstractA
val param: AbstractA = anA
println("Starting with: $param sharedResettable=${param.sharedResettable}")
// set something on it... we do not mind yet, what it is exactly...
param.sharedResettable = UUID.randomUUID().toString()
// now we want to store it... but wait... did we have an A here? or a newly created DTO?
// lets check: (demo purpose again)
when (param) {
is ADTO -> store(param) // which now returns an A
is A -> update(param) // maybe updated also our A so a current A is returned
}.also { certainlyA ->
println("After saving/updating: $certainlyA sharedResettable=${certainlyA.sharedResettable /* this was deliberately not part of the data class toString() */}")
}
}
// assume the following signature for store & update:
fun <T> update(param : T) : T
fun store(a : AbstractA) : A
Sample output:
Starting with: A(mandatoryProperty=123, sharedReadonly=from backend) sharedResettable=i am from backend
After saving/updating: A(mandatoryProperty=123, sharedReadonly=from backend) sharedResettable=ef7a3dc0-a4ac-47f0-8a73-0ca0ef5069fa
Starting with: ADTO(sharedReadonly=from dto) sharedResettable=i am dto
After saving/updating: A(mandatoryProperty=127, sharedReadonly=from dto) sharedResettable=57b8b3a7-fe03-4b16-9ec7-742f292b5786
I did not yet show you the ugly part, but you already mentioned it yourself... How do you transform your ADTO to A and viceversa? I will leave that up to you. There are several approaches here (manually, using reflection or mapping utilities, etc.).
This variant cleanly seperates all the DTO specific from the non-DTO-specific properties. However it will also lead to redundant code (all the override, etc.). But at least you know on which object type you operate and can setup signatures accordingly.
Something like 3 is probably easier to setup and to maintain (regarding the data class itself ;-)) and if you set the boundaries correctly it may even be clear, when there is a null in there and when not... So showing that example too. Starting with a rather annoying variant first (annoying in the sense that it throws an exception when you try accessing the variable if it wasn't set yet), but at least you spare the !! or null-checks here:
data class B(
val sharedOnly : String,
var sharedResettable : String
) {
// why nullable? Let it hurt ;-)
lateinit var mandatoryProperty: ID // ok... Long is not usable with lateinit... that's why there is this ID instead
}
data class ID(val id : Long)
Demo:
val b = B("backend", "resettable")
// println(newB.mandatoryProperty) // uh oh... this hurts now... UninitializedPropertyAccessException on the way
val newB = store(b)
println(newB.mandatoryProperty) // that's now fine...
But: even though accessing mandatoryProperty will throw an Exception it is not visible in the toString nor does it look nice if you need to check whether it already has been initialized (i.e. by using ::mandatoryProperty::isInitialized).
So I show you another variant (meanwhile my favorite, but... uses null):
data class C(val mandatoryProperty: Long?,
val sharedOnly : String,
var sharedResettable : String) {
// this is our DTO constructor:
constructor(sharedOnly: String, sharedResettable: String) : this(null, sharedOnly, sharedResettable)
fun hasID() = mandatoryProperty != null // or isDTO, etc. what you like/need
}
// note: you could extract the val and the method also in its own interface... then you would use an override on the mandatoryProperty above instead
// here is what such an interface may look like:
interface HasID {
val mandatoryProperty: Long?
fun hasID() = mandatoryProperty != null // or isDTO, etc. what you like/need
}
Usage:
val c = C("dto", "resettable") // C(mandatoryProperty=null, sharedOnly=dto, sharedResettable=resettable)
when {
c.hasID() -> update(c)
else -> store(c)
}.also {newC ->
// from now on you should know that you are actually dealing with an object that has everything in place...
println("$newC") // prints: C(mandatoryProperty=123, sharedOnly=dto, sharedResettable=resettable)
}
The last one has the benefit, that you can use the copy-method again, e.g.:
val myNewObj = c.copy(mandatoryProperty = 123) // well, you probably don't do that yourself...
// but the following might rather be a valid case:
val myNewDTO = c.copy(mandatoryProperty = null)
The last one is my favorite as it needs the fewest code and uses a val instead (so also no accidental override is possible or you operate on a copy instead). You could also just add an accessor for the mandatoryProperty if you do not like using ? or !!, e.g.
fun getMandatoryProperty() = mandatoryProperty ?: throw Exception("You didn't set it!")
Finally if you have some helper methods like hasID(isDTO or whatever) in place it might also be clear from the context what you are exactly doing. The most important is probably to setup a convention that everyone understands, so they know when to apply what or when to expect something specific.

Gson, How to write a JsonDeserializer for Generic Typed Classes?

Situation
I have a class that holds a generic type, and it also has a non-zero arg constructor. I don't want to expose a zero arg constructor because it can lead to erroneous data.
public class Geometries<T extends AbstractGeometry>{
private final GeometryType geometryType;
private Collection<T> geometries;
public Geometries(Class<T> classOfT) {
this.geometryType = lookup(classOfT);//strict typing.
}
}
There are several (known and final) classes that may extend AbstractGeometry.
public final Point extends AbstractGeometry{ ....}
public final Polygon extends AbstractGeometry{ ....}
Example json:
{
"geometryType" : "point",
"geometries" : [
{ ...contents differ... hence AbstractGeometry},
{ ...contents differ... hence AbstractGeometry},
{ ...contents differ... hence AbstractGeometry}
]
}
Question
How can I write a JsonDeserializer that will deserialize a Generic Typed class (such as Geometires)?
CHEERS :)
p.s. I don't believe I need a JsonSerializer, this should work out of the box :)
Note: This answer was based on the first version of the question. The edits and subsequent question(s) change things.
p.s. I don't believe I need a JsonSerializer, this should work out of the box :)
That's not the case at all. The JSON example you posted does not match the Java class structure you apparently want to bind to and generate.
If you want JSON like that from Java like that, you'll definitely need custom serialization processing.
The JSON structure is
an object with two elements
element 1 is a string named "geometryType"
element 2 is an object named "geometries", with differing elements based on type
The Java structure is
an object with two fields
field 1, named "geometryType", is a complex type GeometryType
field 2, named "geometries" is a Collection of AbstractGeometry objects
Major Differences:
JSON string does not match Java type GeometryType
JSON object does not match Java type Collection
Given this Java structure, a matching JSON structure would be
an object with two elements
element 1, named "geometryType", is a complex object, with elements matching the fields in GeometryType
element 2, named "geometries", is a collection of objects, where the elements of the different objects in the collection differ based on specific AbstractGeometry types
Are you sure that what you posted is really what you intended? I'm guessing that either or both of the structures should be changed.
Regarding any question on polymorphic deserialization, please note that the issue was discussed a few times on StackOverflow.com already. I posted a link to four different such questions and answers (some with code examples) at Can I instantiate a superclass and have a particular subclass be instantiated based on the parameters supplied.

Resources