Skip to content

Instantly share code, notes, and snippets.

@fullkomnun
Last active April 14, 2018 11:27
Show Gist options
  • Save fullkomnun/06f3f46853565a3dd997e8781dadaa1c to your computer and use it in GitHub Desktop.
Save fullkomnun/06f3f46853565a3dd997e8781dadaa1c to your computer and use it in GitHub Desktop.
Kotlin data types simple generator - currently generates with default values naively. "Despite having to generate data types kovfefe".
inline fun <reified T : Any> generate(): T = T::class.generate()
fun <T : Any> KClass<T>.generate(): T =
when {
isData -> generateDataClass()
isTopLevelAutoValue -> generateTopLevelAutoValue()
isNestedAutoValue -> generateNestedAutoValue()
java.isEnum -> java.enumConstants.first()
else -> doGenerate() as T
}
private fun <T : Any> KClass<T>.generateTopLevelAutoValue(): T {
val c = Class.forName("${java.`package`.name}.AutoValue_${java.simpleName}").kotlin
val con = c.constructors.first().apply { isAccessible = true }
return con.invoke() as T
}
private fun <T : Any> KClass<T>.generateNestedAutoValue(): T {
val c = Class.forName(
"${java.`package`.name}.AutoValue_${java.enclosingClass.simpleName}_${java.simpleName}").kotlin
val con = c.constructors.first().apply { isAccessible = true }
return con.invoke() as T
}
private val <T : Any> KClass<T>.isTopLevelAutoValue
get() =
isAbstract && !java.isMemberClass && java.`package` != null &&
isClass("${java.`package`.name}.AutoValue_${java.simpleName}")
private val <T : Any> KClass<T>.isNestedAutoValue
get() =
isAbstract && java.isMemberClass && isStatic && java.`package` != null &&
isClass(
"${java.`package`.name}.AutoValue_${java.enclosingClass.simpleName}_${java.simpleName}")
private val <T : Any> KClass<T>.isStatic get() = Modifier.isStatic(java.modifiers)
private fun isClass(className: String): Boolean =
try {
Class.forName(className)
true
} catch (e: Exception) {
false
}
private fun <T : Any> KClass<T>.generateDataClass(): T = primaryConstructor!!.invoke()
private fun <T : Any> KFunction<T>.invoke(): T {
val params = parameters
.filter { !it.isOptional }
.filter { it.type.classifier is KClass<*> }
.associate {
it to if (it.type.isMarkedNullable) null
else (it.type.classifier as KClass<*>).generate()
}
return callBy(params)
}
private fun <T : Any> KClass<T>.doGenerate(): Any =
when (qualifiedName) {
List::class.qualifiedName -> listOf<T>()
Set::class.qualifiedName -> setOf<T>()
else -> forClassName(qualifiedName!!)
}
private fun forClassName(className: String): Any =
when (className) {
"org.threeten.bp.LocalDate" -> LocalDate.now()
"org.threeten.bp.LocalDateTime" -> LocalDateTime.now()
"org.threeten.bp.LocalTime" -> LocalTime.now()
"org.threeten.bp.ZonedDateTime" -> ZonedDateTime.now()
"java.math.BigInteger" -> BigInteger.ZERO
"java.math.BigDecimal" -> BigDecimal.ZERO
"java.lang.String" -> ""
"kotlin.String" -> ""
"java.lang.Integer" -> 0
"kotlin.Int" -> 0
"java.lang.Long" -> 0L
"kotlin.Long" -> 0L
"java.lang.Boolean" -> false
"kotlin.Boolean" -> false
"java.lang.Float" -> 0.0f
"kotlin.Float" -> 0.0f
"java.lang.Double" -> 0.0
"kotlin.Double" -> 0.0
"java.lang.Character" -> 'a'
"kotlin.Char" -> 'a'
"java.lang.Byte" -> Byte.MAX_VALUE
"kotlin.Byte" -> Byte.MAX_VALUE
else -> throw IllegalArgumentException("Cannot generate $className")
}
enum class Pokemon { Squirtle, Bulbasaur, Charmander }
data class Goo(val num: Long, val kuku: BigDecimal, val opt: String = "yey", val pokemon: Pokemon)
data class Foo(val name: String, val age: Int = 31, val ld: LocalDate, val l: LocalDateTime, val zdt: ZonedDateTime, val nickname: String?, val list: List<Double>,
val letter: Char, val b: Byte, val bi: BigInteger, val bd: BigDecimal, val goo: Goo)
class KovfefeTest {
@Test
fun test() {
println(User::class.generate())
}
}
// output: User{name=, age=0, money=0, double=0.0, foo=Foo(name=, age=31, ld=2018-02-22,
// l=2018-02-22T09:02:26.110, zdt=2018-02-22T09:02:26.114+02:00[Asia/Jerusalem], nickname=null, list=[],
// letter=a, b=127, bi=0, bd=0, goo=Goo(num=0, kuku=0, opt=yey, pokemon=Squirtle)),
// it=Nested{names=[], uniqueNames=[]}}
@AutoValue
public abstract class User {
public abstract String getName();
public abstract int getAge();
public abstract BigDecimal getMoney();
public abstract Double getDouble();
public abstract Foo getFoo();
public abstract Enclosing.Nested getIt();
public static Builder builder() {
return new AutoValue_User.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setName(String newName);
public abstract Builder setAge(int newAge);
public abstract Builder setMoney(BigDecimal newMoney);
public abstract Builder setDouble(Double newDouble);
public abstract Builder setFoo(Foo newFoo);
public abstract Builder setIt(Enclosing.Nested newIt);
public abstract User build();
}
}
public class Enclosing {
@AutoValue static abstract class Nested {
abstract List<String> getNames();
abstract Set<String> getUniqueNames();
public static Nested create(List<String> newNames, Set<String> newUniqueNames) {
return new AutoValue_Enclosing_Nested(newNames, newUniqueNames);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment