JsonToKotlinClass icon indicating copy to clipboard operation
JsonToKotlinClass copied to clipboard

Enum classes are duplicated and corrupt

Open huehnerlady opened this issue 4 years ago • 3 comments

Hi,

I am trying to use your project as a lib to generate our API classes from a json schema. I ran into the following problem: When there is an enum in the class, I could see 2 problems:

  1. The class is generated for every declaration
  2. The values of the enum are not with a String, so the code does not compile. -> see #352 Example: I have a json schema:
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "Foo",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "value1": {
      "type": "string"
    },
    "value2": {
      "type": "string",
      "$ref": "#/definitions/FooEnum"
    },
    "value3": {
      "type": "string",
      "$ref": "#/definitions/FooEnum"
    }
  },
  "definitions": {
    "FooEnum": {
      "type": "string",
      "enum": [
        "VALUE_1",
        "VALUE_2",
        "VALUE_3"
      ]
    }
  }
}

I would expect the following code to come out of this:


data class Foo(
    val value1: String? = null,
    val value2: FooEnum? = null,
    val value3: FooEnum? = null
) {
  enum class FooEnum(val value: String) {
    VALUE_1("VALUE_1"),

    VALUE_2("VALUE_2"),

    VALUE_3("VALUE_3");
  }
}

but I get:

data class Foo1(
    val value1: String? = null,
    val value2: FooEnum? = null,
    val value3: FooEnum? = null
) {
  enum class FooEnum(val value: String) {
    VALUE_1(VALUE_1),

    VALUE_2(VALUE_2),

    VALUE_3(VALUE_3);
  }

  enum class FooEnum(val value: String) {
    VALUE_1(VALUE_1),

    VALUE_2(VALUE_2),

    VALUE_3(VALUE_3);
  }
}

Unfortunately this does not compile with the following errors:

  • Duplicate JVM class name 'de/europace/privatkredit/kex/vorgaenge/api/Foo1$FooEnum' generated from: FooEnum, FooEnum
  • Type mismatch. Required:String, Found:Foo1.FooEnum

I am currently using the lib wu.seal.jsontokotlin:library:3.6.1

My generation code:

val file = File("Foo.json")
  val jsonString = file.readText()
  val actualOutput = JsonToKotlinBuilder()
      .setPackageName("some.package")
      .enableVarProperties(false) // optional, default : false
      .setPropertyTypeStrategy(PropertyTypeStrategy.Nullable) // optional, default :  PropertyTypeStrategy.NotNullable
      .setDefaultValueStrategy(DefaultValueStrategy.AllowNull) // optional, default : DefaultValueStrategy.AvoidNull
      .setAnnotationLib(TargetJsonConverter.None) // optional, default: TargetJsonConverter.None
      .enableOrderByAlphabetic(true) // optional : default : false
      .enableInnerClassModel(true) // optional, default : false
      .enableCreateAnnotationOnlyWhenNeeded(true) // optional, default : false
      .setIndent(2) // optional, default : 4
      .enableKeepAnnotationOnClass(false) // optional, default : false
      .enableKeepAnnotationOnClassAndroidX(false) // optional, default : false
      .enableAnnotationAndPropertyInSameLine(false) // optional, default : false
      .enableParcelableSupport(false) // optional, default : false
      .build(jsonString, "Foo") // finally, get KotlinClassCode string
  val kotlinClass = File("Api.kt")
  kotlinClass.createNewFile()
  kotlinClass.writeText(actualOutput)

huehnerlady avatar May 19 '21 14:05 huehnerlady

@TedZen PLS check this

wuseal avatar May 20 '21 02:05 wuseal

I've experienced the same issue. I believe it's due to this line: https://github.com/wuseal/JsonToKotlinClass/blob/aabaa6a86bb5bb6d83b737904d285331c277ad91/src/main/kotlin/wu/seal/jsontokotlin/model/builder/KotlinEnumCodeBuilder.kt#L37

I think it should read: val constantValue: Any = when (i) { instead of val constantValue: Any = when (generic) {

But I'm not certain. I was planning on cloning the repo and seeing whether that'd fix it later, but if someone more familiar can look at that and be like "ah, yes" that'd be awesome.

KundlJ avatar Jun 30 '21 14:06 KundlJ

After checking out the repo and poking around I realize my previous thought was incorrect, however in looking at the test code

.
.
.
"definitions": {
    "LogEventType": {
      "type": "integer",
      "description": "",
      "x-enumNames": [
        "Undefined",
        "Auth"
      ],
      "enum": [
        0,
        1
      ]
    }
  }
}
    """.trimIndent()

    val expectedEnum = """
        enum class LogEventType(val value: Int) {
            Undefined(0),

            Auth(1);
        }
    """.trimIndent()

I realized that JsonToKotlinClass expects x-enumNames for enum names and uses enum for enum values.

A solution that worked for me was to add escaped quotations into the enum fields. I'm not sure whether this conforms to json schema spec.

Example using the schema from the test code:

"definitions": {
    "LogEventType": {
      "type": "string",
      "description": "",
      "x-enumNames": [
        "Undefined",
        "Auth"
      ],
      "enum": [
        "\"Undefined\"",
        "\"Auth\""
      ]
    }
  }
}

Produces

enum class LogEventType(val value: String) {
            Undefined("Undefined"),

            Auth("Auth");
        }

KundlJ avatar Jul 01 '21 11:07 KundlJ