Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to interpret simple schemas that contains enums and const #16

Open
jonaslagoni opened this issue Oct 8, 2021 · 6 comments
Open

Comments

@jonaslagoni
Copy link
Member

Generally, we have "class" data models that can be generated for object schemas, but there is another data model that most languages have which is enums.

We should be able to generate enums for the following schemas:

{
  "name": "States",
  "type": "string",
  "enum": ["Texas", "Alabama", "California"]
}
{
  "name": "CustomEnum",
  "type": "string",
  "const": "value1"
}
{
  "name": "AllTypesEnum",
  "enum": ["string", 1, true, {"test": "test"}, null]
}

Problems with enums

  1. In many languages, numbers cannot be used as keys for enums, which means that something like the following schema { ..., "const": 1 } cannot be interpreted to:
enum States { 1 = 1 }

The same thing applies for the schema { ..., "const": ["1"] }. This means in many cases we need a different naming format, such as if a number prepend the type such as: enum States { NUMBER_1 = 1 }, or are there other ways we can do this?
2. Object enums are also a bit tricky to figure out how to handle or even name in terms of what key to use. I.e. for the schema { ..., "const": {"test": "test"}} which key should it have?

@jdesrosiers
Copy link
Member

Although many language have Enum types, they are rarely (if ever) compatible with the JSON Schema concept of enums. I think most languages will need some sort of type that represents a JSON Schema enum.

TypeScript could handle it with union types: type States = "Texas" | "Alabama" | "California".

@jonaslagoni
Copy link
Member Author

Although many language have Enum types, they are rarely (if ever) compatible with the JSON Schema concept of enums. I think most languages will need some sort of type that represents a JSON Schema enum.

Can you clarify this?

Cause as I see it the enum types are fine for all concepts of JSON Schema enums. It just requires some extra work.
I.e. given the following enum schema:

{
      "name": "Union",
      "enum": ["Texas",  1, "1", true, {"test": "test"}],
}

In Java you can represent all enum values accurately as such (given we have taken a decision on the above-mentioned restrictions):

public enum Union {
  TEXAS("Texas"), NUMBER_1(1), STRING_1("1"), BOOLEAN_TRUE(true), TEST_TEST("{\"test\":\"test\"}");

  private Object value;

  Union(Object value) {
    this.value = value;
  }
    
  @JsonValue
  public Object getValue() {
    return value;
  }

  @Override
  public String toString() {
    return String.valueOf(value);
  }

  @JsonCreator
  public static Union fromValue(Object value) {
    for (Union e : Union.values()) {
      if (e.value.equals(value)) {
        return e;
      }
    }
    throw new IllegalArgumentException("Unexpected value '" + value + "'");
  }
}

@jonaslagoni
Copy link
Member Author

Also, we have two different types of enum data types that can be generated. At least when it comes to TS we call it 'enum' | 'union' where the union is the type of enum in your example:

type States = "Texas" | "Alabama" | "California"

And enum is in a class rather:

export enum Event {
  TEXAS = "Texas",
  ALABAMA = "Alabama",
  CALIFORNIA = "California"
}

Java for example dont have such an option, not in the same sense at least.

@jdesrosiers
Copy link
Member

I actually forgot that Java enums can have values. But that doesn't mean all languages support this. Often enums are just labels and the underlying value is actually just some integer that the language assigns. Generating code for languages whose enum types work that way would require some other type to be defined.

TypeScript is a better example of this than Java. TypeScript only allows the value of enums to be strings or numbers. Since a JSON Schema enum can be of any type, TypeScript enums are not entirely compatible. You could use them in the cases where the two concepts do overlap, such as the States example that only uses strings, but I'd rather implementations be consistent about how they emit code for enums. In TypeScript that would mean always using intersection types rather than an enum type. In Java, I think you can always use an enum type. In other languages, the implementation might need to provide a type in order to be consistent.

@gregsdennis
Copy link
Member

In Java you can represent all enum values accurately as such...

In C#, you can't do this. Enums are strongly typed, numerically backed name identifiers, nothing more. There are some design patterns on how to implement more complex enum values, but they're all custom built rather than being built-in.

Also, there are no union types in C#. There are workarounds, but unions, as such, are not supported.

@jdesrosiers
Copy link
Member

Good to know. C# would be one of those cases where the implementation would have to provide a type that represents an enum that is compatible with JSON Schema's concept of enum.

(Enums might be the only feature I'm aware of where Java is more expressive that C# 🤔)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants