Skip to content

Commit e33f32c

Browse files
authored
Merge pull request #279 from wuseal/3.6.0/jsonschema
3.6.0/jsonschema
2 parents 5f079bd + 978d170 commit e33f32c

25 files changed

+1869
-197
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ before_install:
33
- chmod +x library/gradlew
44
- chmod +x library/gradle/wrapper/gradle-wrapper.jar
55
script:
6+
- ./gradlew check
67
- cd library && ./gradlew build test
78
- cd ../
89
deploy:

build.gradle

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
buildscript {
2-
ext.kotlin_version = '1.3.41'
2+
ext.kotlin_version = '1.3.61'
33

44
repositories {
55
mavenLocal()
@@ -49,4 +49,9 @@ dependencies {
4949
exclude group: "org.jetbrains.kotlin"
5050
}
5151
}
52+
compileKotlin {
53+
kotlinOptions {
54+
languageVersion = "1.3"
55+
}
56+
}
5257

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package wu.seal.jsontokotlin
2+
3+
import java.math.BigDecimal
4+
5+
/**
6+
* Created by Rody66 in 2019-04-18 3:16
7+
*
8+
* @author Rody66
9+
*/
10+
//https://json-schema.org/understanding-json-schema/reference/string.html#format
11+
//TODO this map should be moved to ConfigManager (UI)
12+
val JSON_SCHEMA_FORMAT_MAPPINGS = mapOf(
13+
"date-time" to "org.threeten.bp.OffsetDateTime",
14+
"date" to "org.threeten.bp.LocalDate",
15+
"time" to "org.threeten.bp.LocalTime",
16+
"decimal" to BigDecimal::class.java.canonicalName
17+
18+
//here can be another formats
19+
)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package wu.seal.jsontokotlin
2+
3+
/**
4+
* Created by kezhenxu94 in 2019-03-28 22:21
5+
*
6+
* @author kezhenxu94 (kezhenxu94 at 163 dot com)
7+
*/
8+
val JSON_SCHEMA_TYPE_MAPPINGS = mapOf(
9+
"object" to Any::class,
10+
"array" to Array<Any>::class,
11+
"string" to String::class,
12+
"integer" to Int::class,
13+
"number" to Double::class,
14+
"boolean" to Boolean::class,
15+
"enum" to Enum::class,
16+
17+
//See: https://json-schema.org/understanding-json-schema/reference/null.html
18+
"null" to Any::class
19+
)

src/main/kotlin/wu/seal/jsontokotlin/feedback/ExceptionHandler.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package wu.seal.jsontokotlin.feedback
22

3+
import com.google.gson.Gson
34
import com.google.gson.GsonBuilder
45
import com.intellij.openapi.ui.Messages
56
import java.io.PrintWriter
@@ -17,7 +18,7 @@ import java.util.*
1718
* handler the exception
1819
*/
1920

20-
val prettyPrintGson = GsonBuilder().setPrettyPrinting().create()
21+
val prettyPrintGson: Gson = GsonBuilder().setPrettyPrinting().create()
2122

2223
fun getUncaughtExceptionHandler(jsonString: String, callBack: () -> Unit): Thread.UncaughtExceptionHandler = Thread.UncaughtExceptionHandler { _, e ->
2324
val logBuilder = StringBuilder()

src/main/kotlin/wu/seal/jsontokotlin/model/classscodestruct/DataClass.kt

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@ import wu.seal.jsontokotlin.interceptor.IKotlinClassInterceptor
44
import wu.seal.jsontokotlin.utils.LogUtil
55
import wu.seal.jsontokotlin.utils.getCommentCode
66
import wu.seal.jsontokotlin.utils.getIndent
7+
import wu.seal.jsontokotlin.utils.toAnnotationComments
78
import java.lang.IllegalStateException
89

910
data class DataClass(
1011
val annotations: List<Annotation> = listOf(),
1112
override val name: String,
1213
val properties: List<Property> = listOf(),
1314
val parentClassTemplate: String = "",
14-
override val modifiable: Boolean = true
15+
override val modifiable: Boolean = true,
16+
val comments: String = "",
17+
val fromJsonSchema: Boolean = false
1518
) : ModifiableKotlinClass, NoGenericKotlinClass {
1619

1720
override val hasGeneric: Boolean = false
@@ -45,7 +48,8 @@ data class DataClass(
4548
property.typeObject.let {
4649
val newTypObj = when (it) {
4750
is GenericKotlinClass -> property.typeObject.replaceReferencedClasses(replaceRule)
48-
is ModifiableKotlinClass -> replaceRule[property.typeObject] ?: error("Modifiable Kotlin Class Must have a replacement")
51+
is ModifiableKotlinClass -> replaceRule[property.typeObject]
52+
?: error("Modifiable Kotlin Class Must have a replacement")
4953
else -> it
5054
}
5155
LogUtil.i("replace type: ${property.type} to ${newTypObj.name}")
@@ -57,8 +61,10 @@ data class DataClass(
5761
}
5862

5963
override fun getCode(): String {
64+
if (fromJsonSchema && properties.isEmpty()) return ""
6065
val indent = getIndent()
61-
val code = buildString {
66+
return buildString {
67+
append(comments.toAnnotationComments())
6268
if (annotations.isNotEmpty()) {
6369
val annotationsCode = annotations.joinToString("\n") { it.getAnnotationString() }
6470
if (annotationsCode.isNotBlank()) {
@@ -72,10 +78,16 @@ data class DataClass(
7278
}
7379
properties.forEachIndexed { index, property ->
7480
val code = property.getCode()
75-
val addIndentCode = code.split("\n").joinToString("\n") { indent + it }
76-
append(addIndentCode)
81+
val commentCode = getCommentCode(property.comment)
82+
if (fromJsonSchema && commentCode.isNotBlank()) {
83+
append("/**\n * $commentCode\n */\n".split("\n").joinToString("\n") { indent + it })
84+
append(code)
85+
}else{
86+
val addIndentCode = code.split("\n").joinToString("\n") { indent + it }
87+
append(addIndentCode)
88+
}
7789
if (index != properties.size - 1) append(",")
78-
if (property.comment.isNotBlank()) append(" // ").append(getCommentCode(property.comment))
90+
if (!fromJsonSchema && commentCode.isNotBlank()) append(" // ").append(commentCode)
7991
append("\n")
8092
}
8193
append(")")
@@ -93,7 +105,6 @@ data class DataClass(
93105
append("}")
94106
}
95107
}
96-
return code
97108
}
98109

99110

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package wu.seal.jsontokotlin.model.classscodestruct
2+
3+
import wu.seal.jsontokotlin.utils.getIndent
4+
import wu.seal.jsontokotlin.utils.toAnnotationComments
5+
import java.lang.StringBuilder
6+
7+
/**
8+
* Created by ted on 2020/3/14 18:14.
9+
*/
10+
data class EnumClass(
11+
override val name: String,
12+
val xEnumNames: List<String>?,
13+
override val generic: KotlinClass,
14+
override val referencedClasses: List<KotlinClass> = listOf(generic),
15+
val enum: List<Any>,
16+
val comments: String = "",
17+
override val modifiable: Boolean = true
18+
) : ModifiableKotlinClass, NoGenericKotlinClass {
19+
20+
override fun getOnlyCurrentCode(): String {
21+
val indent = getIndent()
22+
return StringBuilder().append(comments.toAnnotationComments())
23+
.append("enum class $name(val value: ${generic.name}) {\n")
24+
.append(generateValues().joinToString("\n\n") { "$indent$it" })
25+
.append("\n}").toString()
26+
}
27+
28+
override fun rename(newName: String): KotlinClass = copy(name = newName)
29+
30+
private fun generateValues(): List<String> {
31+
val list = mutableListOf<String>()
32+
for (i in enum.indices) {
33+
val constantValue: Any = if (generic == KotlinClass.INT) (enum[i] as Double).toInt()
34+
else enum[i].toString()
35+
val constantName = xEnumNames?.get(i)
36+
?: if (constantValue is Int) "_$constantValue" else constantValue.toString()
37+
val finalValue = "${constantName}(${constantValue})" + if (i != enum.size - 1) "," else ";"
38+
list.add(finalValue)
39+
}
40+
return list
41+
}
42+
43+
override fun getCode(): String {
44+
return getOnlyCurrentCode()
45+
}
46+
47+
override fun replaceReferencedClasses(replaceRule: Map<KotlinClass, KotlinClass>): EnumClass {
48+
return if (replaceRule.isEmpty()) this else copy(generic = replaceRule.values.toList()[0], referencedClasses = replaceRule.values.toList())
49+
}
50+
}

src/main/kotlin/wu/seal/jsontokotlin/model/classscodestruct/NormalClass.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ data class NormalClass(
6363

6464
override fun getCode(): String {
6565
val indent = getIndent()
66-
val code = buildString {
66+
return buildString {
6767
if (annotations.isNotEmpty()) {
6868
val annotationsCode = annotations.joinToString("\n") { it.getAnnotationString() }
6969
if (annotationsCode.isNotBlank()) {
@@ -98,7 +98,6 @@ data class NormalClass(
9898
append("}")
9999
}
100100
}
101-
return code
102101
}
103102

104103

src/main/kotlin/wu/seal/jsontokotlin/model/classscodestruct/Property.kt

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
package wu.seal.jsontokotlin.model.classscodestruct
22

33
data class Property(
4-
val annotations: List<Annotation> = listOf(),
5-
val keyword: String = "val",
6-
val originName: String,
7-
val originJsonValue: String? = "",
8-
val name: String = originName,
9-
val type: String,
10-
val value: String = "",
11-
val comment: String = "",
12-
val typeObject: KotlinClass,
13-
private var separatorBetweenAnnotationAndProperty:String = "\n"
4+
val annotations: List<Annotation> = listOf(),
5+
val keyword: String = "val",
6+
val originName: String,
7+
val originJsonValue: String? = "",
8+
val name: String = originName,
9+
val type: String,
10+
val value: String = "",
11+
val comment: String = "",
12+
val typeObject: KotlinClass,
13+
private var separatorBetweenAnnotationAndProperty: String = "\n",
14+
val nullable: Boolean = false
1415
) {
1516
fun letLastAnnotationStayInSameLine() {
1617
separatorBetweenAnnotationAndProperty = " "
@@ -26,6 +27,7 @@ data class Property(
2627
}
2728
}
2829
append(keyword).append(" ").append(name).append(": ").append(type)
30+
if(nullable) append("?")
2931
if (value.isNotBlank()) {
3032
append(" = ").append(value)
3133
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package wu.seal.jsontokotlin.model.jsonschema
2+
3+
import com.google.gson.annotations.SerializedName
4+
5+
open class JsonObjectDef(
6+
//See: https://json-schema.org/understanding-json-schema/structuring.html
7+
@SerializedName("\$id")
8+
val id: String? = null,
9+
@SerializedName("\$ref")
10+
val ref: String? = null,
11+
12+
val title: String? = null,
13+
val description: String? = null,
14+
15+
/** type may contains a string or an array of string (ArrayList),
16+
* where usually the first entry is "null" (property isTypeNullable)
17+
* and the second entry is the type string (property typeString)
18+
* */
19+
protected val type: Any? = null,
20+
21+
val properties: Map<String, PropertyDef>? = null,
22+
val additionalProperties: Any? = null,
23+
val required: Array<String>? = null,
24+
25+
/** See: https://json-schema.org/understanding-json-schema/reference/combining.html */
26+
val oneOf: Array<PropertyDef>? = null,
27+
val allOf: Array<PropertyDef>? = null,
28+
val anyOf: Array<PropertyDef>? = null,
29+
val not: Array<PropertyDef>? = null,
30+
31+
@SerializedName("x-abstract")
32+
val x_abstract: Boolean? = null
33+
34+
) {
35+
36+
/** returns correct JsonSchema type as string */
37+
val typeString: String?
38+
get() = if (type is ArrayList<*>) type.first { it != "null" } as String else type as? String
39+
40+
/** returns true if the object can be null */
41+
val isTypeNullable: Boolean
42+
get() = when {
43+
type is ArrayList<*> -> type.any { it == "null" }
44+
oneOf?.any { it.type == "null" } == true -> true
45+
else -> typeString == "null"
46+
}
47+
48+
}

0 commit comments

Comments
 (0)