11package com.fractalwrench.json2kotlin
22
3- import com.google.gson.JsonArray
43import com.google.gson.JsonElement
5- import com.google.gson.JsonObject
6- import com.google.gson.JsonPrimitive
74import com.squareup.kotlinpoet.*
85import java.util.HashMap
9- import java.util.HashSet
106
117
12- internal class JsonProcessor { // TODO crappy name
8+ internal class JsonProcessor ( private val typeDetector : JsonTypeDetector ) { // TODO crappy name
139
14- internal val jsonElementMap = HashMap <JsonElement , TypeSpec >() // FIXME feels wrong having this exposed
10+ internal val jsonElementMap = HashMap <JsonElement , TypeSpec >() // FIXME feels wrong having this exposed, return instead?
1511
1612 // FIXME should take TypedJsonElement rather than String as a param!
1713 fun findDistinctTypesForFields (fields : Collection <String >,
@@ -28,83 +24,10 @@ internal class JsonProcessor { // TODO crappy name
2824 private fun findDistinctTypesForField (commonElements : List <TypedJsonElement >, key : String ): List <TypeName ?> {
2925 return commonElements.map {
3026 val fieldValue = it.asJsonObject.get(key)
31- if (fieldValue != null ) typeForJsonField(fieldValue, key) else null
27+ if (fieldValue != null ) typeDetector. typeForJsonField(fieldValue, key, jsonElementMap ) else null
3228 }.distinct()
3329 }
3430
35-
36-
37- // TODO: refactor all the (simple) type deduction methods. They can take an extra Map parameter. This will greatly simplify any unit
38- // testing and pass Single-Responsibility test
39-
40-
41- private fun typeForJsonField (jsonElement : JsonElement , key : String ): TypeName {
42- with (jsonElement) {
43- return when {
44- isJsonPrimitive -> typeForJsonPrimitive(asJsonPrimitive)
45- isJsonArray -> typeForJsonArray(asJsonArray, key)
46- isJsonObject -> typeForJsonObject(asJsonObject, key)
47- isJsonNull -> Any ::class .asTypeName().asNullable()
48- else -> throw IllegalStateException (" Expected a JSON value" )
49- }
50- }
51- }
52-
53- private fun typeForJsonPrimitive (primitive : JsonPrimitive ): TypeName {
54- return when {
55- primitive.isBoolean -> Boolean ::class
56- primitive.isNumber -> Number ::class
57- primitive.isString -> String ::class
58- else -> throw IllegalStateException (" No type found for JSON primitive " + primitive)
59- }.asTypeName()
60- }
61-
62-
63- // FIXME feels really messy from here on out
64-
65-
66- private fun typeForJsonObject (jsonObject : JsonObject , key : String ): TypeName {
67- val existingTypeName = jsonElementMap[jsonObject]
68- if (existingTypeName != null ) {
69- return ClassName .bestGuess(existingTypeName.name!! )
70- }
71-
72- val identifier = key.toKotlinIdentifier().capitalize() // FIXME check symbol pool!
73- return ClassName .bestGuess(identifier)
74- }
75-
76- private fun typeForJsonArray (jsonArray : JsonArray , key : String ): TypeName {
77- val arrayTypes = HashSet <TypeName >()
78- var nullable = false
79-
80- jsonArray.withIndex().forEach {
81- val sanitisedName = key.toKotlinIdentifier() // FIXME check symbol pool!
82- with (it.value) {
83- when {
84- isJsonPrimitive -> arrayTypes.add(typeForJsonPrimitive(asJsonPrimitive))
85- isJsonArray -> arrayTypes.add(typeForJsonArray(asJsonArray, nameForArrayField(it.index, sanitisedName)))
86- isJsonObject -> arrayTypes.add(typeForJsonObject(asJsonObject, nameForArrayField(it.index, sanitisedName)))
87- isJsonNull -> nullable = true
88- else -> throw IllegalStateException (" Unexpected state in array" )
89- }
90- }
91- }
92- val arrayType = deduceArrayType(arrayTypes, nullable)
93- return ParameterizedTypeName .get(Array <Any >::class .asClassName(), arrayType)
94- }
95-
96- private fun deduceArrayType (arrayTypes : HashSet <TypeName >, nullable : Boolean ): TypeName {
97- val hasMultipleType = arrayTypes.size > 1 || arrayTypes.isEmpty()
98- val arrayTypeName = when {
99- hasMultipleType -> Any ::class .asTypeName()
100- else -> arrayTypes.asIterable().first()
101- }
102- return when {
103- nullable -> arrayTypeName.asNullable()
104- else -> arrayTypeName
105- }
106- }
107-
10831 /* *
10932 * Determines a single type which fits multiple types.
11033 */
0 commit comments