I have the empty interface interface HavingUniqueValues(val v: Int) {} and some enums like enum class EnumName(override val v: Int) : HavingUniqueValues.
I want the elements in each enum have unique v-values but I can mistype the values. So I need a test.
Is it possible to create a test where the interface implementations are saved as a List manually and the test checks if all the implementations in the List meet the requirement?
If yes: is it possible to create a function that returns the List of all implementations in the specified package to use it in the test?
Take a look at the Reflections library which might aid you with this.
You should be able to get all subtypes of HavingUniqueValues:
val subjects: Set<Class<out HavingUniqueValues>> =
Reflections("your.package").getSubTypesOf(HavingUniqueValues::class.java)
Now, this will result in a Set of all enum classes that implement HavingUniqueValues. You can iterate all of their values to know if they are unique or not:
subjects.forEach { enumClass ->
assertEquals(
enumClass.enumConstants.size,
enumClass.enumConstants.map(HavingUniqueValues::v).toSet().size
)
}
I used toSet() here to drop all non-inuque values.
This will pass the test:
enum class EnumName(override val v: Int) : HavingUniqueValues { ONE(1), TWO(2), THREE(3) }
This will not pass the test:
enum class EnumName(override val v: Int) : HavingUniqueValues { ONE(1), TWO(2), THREE(2) }
I tried accepted solution and it didn't work with enums. It seems Reflectons library doesn't support searching for implementations that are custom Enums, Exceptions etc. At least with default configuration provided in above answer. There are lot of links and documentation that answer why it won't work:
Why doesn't reflections.getSubTypesOf(Object.class) find enums?
https://github.com/ronmamo/reflections/issues/126
I was able to find and test similar solution with Classgraph
Here is example code that worked for me with enums:
try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("package.with.your.enums").scan()) {
ClassInfoList implementationsRefs = scanResult.getClassesImplementing("package.with.your.enums.yourInterfaceForEnums");
List<Class<?>> implementations = implementationsRefs.loadClasses();
//here goes your code that operates on "implementations"
}
Since you tagged your question with kotlintest, I've turned #egor's excellent answer into a KotlinTest copy n paste snippet for you.
class MyTest : StringSpec({
"unique values" {
val subjects: Set<Class<out HavingUniqueValues>> =
Reflections("your.package").getSubTypesOf(HavingUniqueValues::class.java)
subjects.forEach { enumClass ->
enumClass.enumConstants.size shouldBe
enumClass.enumConstants.map(HavingUniqueValues::v).toSet().size
}
}
})
Related
Lets assume you have a class:
class Person{
var age :Int?
var name :String?
}
and then you have collection of this class, let's call it people :List.
You can call sort as:
people.sortBy{person -> person.age}
or
people.sortBy{person -> person.name}
Im wondering if its possible to write function definition that would sort by a given field? such as:
fun sortbyField(field:???){
peple.sortBy{field}
}
I have no idea if its possible, if so, how to define "field" parameter.
Thanks!
You can make the function parameter accept a function type with a receiver, like Person.() -> T, and then, inside the bodies of lambdas passed to the function, it will be possible to access a property of the implicit receiver:
fun <T : Comparable<T>> sortUsing(fn: Person.() -> T) {
people.sortBy { it.fn() }
}
Usages:
sortUsing { name }
sortUsing { age }
Alternatively, you can pass a callable reference to the property as a functional argument, instead of a lambda:
people.sortBy(Person::name)
people.sortBy(Person::age)
This works for both functional parameters accepting a single argument, (Person) -> T, and for functional parameters with receiver, Person.() -> T.
You can simply use the field as a parameter if you do not call the function as a lambda expression:
people.sortedBy(Person::name)
Maybe the following is something you were looking for:
fun List<Person>.sortByHeader(header: String) = sortedWith(
when (header) {
"header_name" -> compareBy(nullsFirst(), Person::name)
"header_age" -> compareBy(nullsLast(), Person::age)
"header_time" -> compareBy(Person::time)
else -> compareBy(Person::id)
}
)
I used the following data class instead:
data class Person(val id: Int, val name: String?, val age : Int?, val time: LocalDateTime)
This way you can then call it using your header name, e.g.:
pepple.sortByHeader("header_id").run(::println)
pepple.sortByHeader("header_name").run(::println)
pepple.sortByHeader("header_time").run(::println)
pepple.sortByHeader("header_age").run(::println)
I just added some nullsFirst/nullsLast in case you want to have something like that in place as well.
If that is not what you were after, then using a function with receiver as shown by hotkeys answer might be more appropriate for you. The next alternative is using reflection, but I will omit this one, as that should be used rather as a last resort.
Yet another way to write it
people.sortBy { it.name }
In kotlin, when a lambda expect only one argument, you can simplify the syntax: people.sort { it -> it.name } becomes people.sort { it.name }. You have to use the name it though
I have an enum with values
enum class Foo(val serverVal:Int) {
BAR(1),
BUG(2)
}
that I would like to use with a class:
data class C1(val fooVal:Foo)
I want to be able to serialise it with a code that looks as close as can be to:
Gson().toJson(C1(Foo.BAR))
That would yield
{"fooVal":1}
Instead of the default conversion, which is, of course {"fooVal":"BAR"}. If it was a string value I could have used #SerializedName, but I can't because it's an Int, not a String.
Is there a simple way to add something to Foo, in order to show Gson how to take the Int value from Foo entries rather than their name?
Examples I saw in Java include EnumAdapterFactory and TypeAdapter which are quite cumbersome and defeat the purpose of a pretty code.
I would love to get a solution that is maintained inside the data structure.
enum class SomeEnum(val i:Int) {
V1(1), V2(10), V3(5);
companion object {
#SerializeMeLikeThis
fun toJson() = i;
#DeserializeMeLikeThat
fun fromJson(v:Int) = values().find{it.i == v}?:whatever
}
}
An ugly way but still encapsulated-ish
data class C2(#SerializedName("foo") var serverFoo:Int) {
// Becomes a nightmare with many params.
constructor(f:Foo) : this(F.serverVal)
var foo:Foo
get() = Foo.values().find{serverFoo == it.serverVal}?:whatever
set(v) { serverFoo = v.serverVal }
}
So it can be called
Gson().toJson(C2(BAR))
and
// Result: Foo.BAR
Gson().fromJson("""{"foo":"1"}""", C2::class.java).foo
Well, you can live on it...but it... :-(
Any nice way?
Thanks
Consider this example using Play's JSON API (play.api.libs.json):
case class FooJson(
// lots of other fields omitted
location: Option[LocationJson]
)
object FooJson {
implicit val writes = Json.writes[FooJson]
}
and
case class LocationJson(latitude: Double, longitude: Double)
object LocationJson {
implicit val writes = Json.writes[LocationJson]
}
If location is None, the resulting JSON won't have location field at all. This is fine and understadable. But if I wanted for some reason (say, to make my API more self-documenting), how can I explicitly output null in JSON?
{
"location": null
}
I also tried defining the field as location: LocationJson and passing option.orNull to it, but it does not work (scala.MatchError: null at play.api.libs.json.OWrites$$anon$2.writes). For non-custom types such as String or Double, this approach would produce null in JSON output.
So, while using Json.writes[FooJson] as shown above (or something equally simple, i.e. not having to write a custom Writes implementation), is there a clean way to include nulls in JSON?
What I'm asking is analogous to JsonInclude.Include.ALWAYS in the Jackson library (also Jackson's default behaviour). Similarly in Gson this would be trivial
(new GsonBuilder().serializeNulls().create()).
Play 2.4.4
Greg Methvin, a Play committer, wrote this answer to me in a related GitHub issue:
The JSON macros only support one way of encoding optional values,
which is to omit None values from the JSON. This is not a bug but
rather a limitation of the implementation. If you want to include
nulls you're unfortunately going to have to implement your own Writes.
I do think we should try to provide more configurability for the
macros though.
In this case, I'll let Play exclude this field when the value is null, even if it slightly sacrifices API consistency and self-documentability. It's still such a minor thing (in this particular API) that it doesn't warrant uglifying the code as much as a custom Writes would take for a case class with a dozen values.
I'm hoping they do make this more configurable in future Play versions.
Hello from the future.
As of Play 2.7, a fairly simple solution was introduced for automated JSON codecs. We can introduce the appropriate implicit value for JsonConfiguration in the scope for the Format/Reads/Writes. The following configuration will write nulls for empty Options instead of omitting the fields entirely.
import play.api.libs.json._
implicit val config = JsonConfiguration(optionHandlers = OptionHandlers.WritesNull)
implicit val residentWrites = Json.writes[Resident]
Reference
Here's a way to do it:
object MyWrites extends DefaultWrites{
override def OptionWrites[T](implicit fmt: Writes[T]): Writes[Option[T]] = new Writes[Option[T]] {
override def writes(o: Option[T]): JsValue = {
o match {
case Some(a) => Json.toJson(a)(fmt)
case None => JsNull
}
}
}
}
This will overwrite the default implementation which will not create an element. I used this in your sample code:
case class FooJson(
// ...
location: Option[LocationJson]
)
case class LocationJson(latitude: Double, longitude: Double)
object LocationJson {
implicit val writes = Json.writes[LocationJson]
}
implicit val fooJsonWriter: Writes[FooJson] = new Writes[FooJson] {
override def writes(o: FooJson): JsValue = {
JsObject(Seq(
"location" -> Json.toJson(o.location)
// Additional fields go here.
))
}
}
Json.toJson(FooJson(None))
And got this result res0: play.api.libs.json.JsValue = {"location":null}.
if we have null values then we have to add the option with members in case class which will resolve the issue
case class response(
name:String,
age: option[int]
)
object response {
implicit val format = Json.format[response]
}
Here the option is the answer for us. and if we are the JSON response for age is coming as null and this will handle the solution for us.
I have JUnit test like that:
Test fun testCategoriesLoading() {
val subscriber = TestSubscriber<List<ACategory>>()
service.categories().subscribe(subscriber)
subscriber.awaitTerminalEvent()
subscriber.assertNoErrors()
}
service is Retrofit, that uses GsonConverter to deserialize json into
data class ACategory(val id: String, val title: String, val parentId: String?, val hasChildren: Boolean)
instances.
Test is passing, even if ACategory filled with id = null, title = null etc.
So, as far as i know, gson using reflection, and kotlin lazily resolves this nullability constraints on first access.
Is there any way to force this resolve?
Some good-looking solution without direct access to fields manually? I really don't want to write every assert by hand.
You could use the new Kotlin reflection. If you have an instance of ACategory, call
ACategory::class.memberProperties
.filter { !it.returnType.isMarkedNullable }
.forEach {
assertNotNull(it.get(aCategory))
}
to access all properties that are marked as not nullable and assert they're not null. Make sure, you have the reflection lib on the classpath.
Make sure you're using M14.
We ended up with hack for data classes(only use case for us, so its ok).
Calling gsonConstructedObject.copy() reveals all exceptions
I'm reading structured JSON, using Play Frameworks' JSON Reads to build up an object graph with case classes.
An example:
case class Foo (
id: Int,
bar_id: Int,
baz_id: Int,
x: Int,
y: String
)
{
var bar: Bar = null
var baz: Baz = null
}
After building the Foo, I must come back later and decorate it by setting bar and baz. Those are defined in other JSON files and only known when all parsing is complete. But this means Foo can't be immutable.
What is the "right" way in Scala to make an immutable object, and then a decorated version of it, without repeating every field of Foo multiple times, over and over?
I know several ways that feel wrong:
make "bar: Option[Bar]" and "baz: Option[Baz]" case class parameters, and then I can use "copy" to make new versions of the Foo class with them set to something; but then I have to check them every single time they're accessed - inefficient, unsafe, not able to make a DecoratedFoo that just is guaranteed to have the right structure
make a second case class that is a copy-paste of all the structure in the first, but adding the two extra decorated parameters - but this means echoing the entire parameter list in the definition, and again when creating instances of it
Case class inheritance is apparently controversial, and in any case also appears to require me to repeat every single parameter anyway, in the subclass constructor?
Make a non-case superclass listing the common case class parameters. Then extend it in the case class. But this would seem to still require repeating every single parameter in the subclass constructor as well.
I see blogs with people talking about this problem and using reflection at runtime to populate the base attributes of their decorated copies - this avoids echo but now you have no type safety, specifying attribute names as strings, overhead, etc...
Surely Scala must have a way to let people compose more complicated immutable objects out of simpler ones without having to copy each and every part of them by hand?
You could introduce a new trait for the processed types, a class that extends that trait, and an implicit conversion:
case class Foo(bar: Int)
trait HasBaz {
val baz: Int
}
class FooWithBaz(val foo: Foo, val baz: Int) extends HasBaz
object FooWithBaz {
implicit def innerFoo(fwb: FooWithBaz): Foo = fwb.foo
implicit class RichFoo(val foo: Foo) extends AnyVal {
def withBaz(baz: Int) = new FooWithBaz(foo, baz)
}
}
So then you can do:
import FooWithBaz._
Foo(1).withBaz(5)
And, although withBaz returns a FooWithBaz, we can treat the return value like a Foo when necessary, because of the implicit conversion.
Combining Option and type parameters you can flag your case class, and track whether the processed fields are empty, statically:
import scala.language.higherKinds
object Acme {
case class Foo[T[X] <: Option[X] forSome { type X }](a: Int,
b: String,
c: T[Boolean],
d: T[Double])
// Necessary, Foo[None] won't compile
type Unprocessed[_] = None.type
// Just an alias
type Processed[X] = Some[X]
}
Example use case:
import Acme._
val raw: Foo[Unprocessed] = Foo[Unprocessed](42, "b", None, None)
def process(unprocessed: Foo[Unprocessed]): Foo[Processed] =
unprocessed.copy[Processed](c = Some(true), d = Some(42d))
val processed: Foo[Processed] = process(raw)
// No need to pattern match, use directly the x from the Some case class
println(processed.c.x)
println(processed.d.x)
I used this once in my current project. The main problem I encountered is when I want Foo to be covariant.
Alternatively, if you don't care about the bound on T:
case class Foo[+T[_]](a: Int, b: String, c: T[Boolean], d: T[Double])
then you can use Foo[Unprocessed] or Foo[Processed] when you need a Foo[Option].
scala> val foo: Foo[Option] = processed
foo: Acme.Foo[Option] = Foo(42,b,Some(true),Some(42.0))
One other strategy might be to create yet another case class:
case class Foo(
id: Int,
bar_id: Int,
baz_id: Int,
x: Int,
y: String
)
case class ProcessedFoo(
foo: Foo,
bar: Bar,
baz: Baz
)