joelittlejohn / jsonschema2pojo

Generate Java types from JSON or JSON Schema and annotate those types for data-binding with Jackson, Gson, etc
http://www.jsonschema2pojo.org
Apache License 2.0
6.23k stars 1.66k forks source link

New Feature - Generate Static Constant Instances for examples defined on object schemas #1631

Open ddcruver opened 2 weeks ago

ddcruver commented 2 weeks ago

Use Case

An schema of an type=object has a examples property which could be used for generating public static constant instances of the class and attach to the generated object's class.

Given the schema:

{
    "$id": "https://github.com/jsonschema2pojo/schemas/examples/animal/Animal.schema.json",
    "$schema": "http://json-schema.org/draft-07/schema#",
    "description": "",
    "type": "object",
    "javaType": "org.jsonschema2pojo.examples.animal.Animal",
    "properties": {
        "name": {
            "type": "string"
        },
        "scientificName": {
            "type": "string"
        },
        "domain": {
            "type": "string"
        },
        "kingdom": {
            "type": "string"
        }
    },
    "additionalProperties": false,
    "required": [
        "name",
        "scientificName",
        "domain",
        "kingdom"
    ],
    "definitions": {
    },
    "examples": [
        {
            "name": "Dog",
            "scientificName": "Canis familiaris",
            "domain": "Eukaryota",
            "kingdom": "Animalia"
        }
    ]
}

I could generate something like this...

package org.jsonschema2pojo.examples.animal;

import java.io.Serializable;
import javax.annotation.Generated;
import javax.validation.constraints.NotNull;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

/**
 * 
 */
@JsonInclude(JsonInclude.Include.USE_DEFAULTS)
@JsonPropertyOrder({
    "name",
    "scientificName",
    "domain",
    "kingdom"
})
@Generated("jsonschema2pojo")
public class Animal implements Serializable
{

    public static final Animal DOG = new Animal("Dog", "Canis fmiliaris", "Eukaryota", "Animalia");

    /**
     * 
     * (Required)
     * 
     */
    @JsonProperty("name")
    @NotNull
    private String name;

Details

General Implementation

The all properties constructor would be used for constructing the object regardless if builders are being used.

Also at least for an initial implementation I would limit it to simple fields, like the primary types and boxed types, strings, but anything else might be a little more complex to construct as a public static CLASS INSTANCE_NAME declaration.

Configurations

Should there be just a single enabling field <generateExamplesAsStaticFields>true</generateExamplesAsStaticFields>? And/or should it be configured per schema file under a field like "generateExamplesOnObject": "true" which may override the single global configuration if also defined.

Missing Values Defined

The example SHOULD include all fields that are marked as required in the schema. Should we fail the generation if not all "required" values are provided. Also for any fields that are not provided we should just initialize them to null or possibly the default value of that field if one is provided.

Name Generation

While we could add something like add custom fields like `javaExamplesInstanceNames: [ "DOG" ] I think just taking the first field, if string use that, if not try to convert it to string, then move onto next field. Once we get a string then upcase it and replace space or other characters into underscores.

Closing Remarks

As usual I will be willing to implement this feature, just want some feedback on if there would be a desire adding this to jsonschema2pojo.

joelittlejohn commented 3 days ago

Hi Dan. Really interesting! I had no idea about this new "examples" field.

My initial thought is that this is similar to the "default". The problem is that the examples can be arbitrarily complex, and in the worst case you are implementing the data binding logic of something like Jackson all over again (but as generated source code). On top of this, the examples may not be valid (for an arbitrarily complex set of reasons), and I note that the spec does not actually dictate that they must be valid, so a schema is valid if it contains invalid examples.

I wonder if a simpler first step could be to add the examples (as JSON snippets) to the Javadoc.

I'm struggling to think of examples where fully constructed Java values are particularly useful. Did you have a need for them, or was this proposal just an idea for a useful feature after seeing the "examples" property?