Repository: victools/jsonschema-generator
Pull request #136 (2020-09-12 12:55:10)

feat: support extra OpenAPI format values
- Adding new `Option.EXTRA_OPEN_API_FORMAT_VALUES`
- When enabled, some extra `"format"` values are being included for certain fixed types
- Extending unit tests to cover the `Option.ADDITIONAL_FIXED_TYPES`


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6e41ae0..7216223 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 ## [Unreleased]
+### `jsonschema-generator`
+#### Added
+- New `Option.EXTRA_OPEN_API_FORMAT_VALUES` to support automatic inclusion of `"format"` values for certain simple/fixed types
 
 ## [4.14.0] - 2020-08-02
 ### `jsonschema-generator`
diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/Option.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/Option.java
index 5e18966..894f7e3 100644
--- a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/Option.java
+++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/Option.java
@@ -251,6 +251,15 @@ public enum Option {
      * @since 4.11.0
      */
     PLAIN_DEFINITION_KEYS(null, null),
+    /**
+     * For the "format" attribute, JSON Schema defines various supported values. The OpenAPI specification assigns a few more of those in order to
+     * differentiate between standard data types (e.g. float vs. double) and even some more fixed data types (e.g. LocalDate, LocalDateTime) if
+     * {@link #ADDITIONAL_FIXED_TYPES} is enabled. By enabling this option, these extra "format" values will be set for the respective
+     * primitive/standard data types automatically.
+     *
+     * @since 4.15.0
+     */
+    EXTRA_OPEN_API_FORMAT_VALUES(null, null),
     /**
      * Whether as the last step of the schema generation, unnecessary "allOf" elements (i.e. where there are no conflicts/overlaps between the
      * contained sub-schemas) should be merged into one, in order to make the generated schema more readable. This also applies to manually added
diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/SchemaGeneratorConfig.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/SchemaGeneratorConfig.java
index b545c32..1241914 100644
--- a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/SchemaGeneratorConfig.java
+++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/SchemaGeneratorConfig.java
@@ -86,6 +86,13 @@ public interface SchemaGeneratorConfig {
      */
     boolean shouldUsePlainDefinitionKeys();
 
+    /**
+     * Determine whether extra {@link SchemaKeyword#TAG_FORMAT} values should be included for "simple types".
+     *
+     * @return whether to include extra {@link SchemaKeyword#TAG_FORMAT} values
+     */
+    boolean shouldIncludeExtraOpenApiFormatValues();
+
     /**
      * Determine whether unnecessary {@link SchemaKeyword#TAG_ALLOF} elements should be removed and merged into their declaring schema when there are
      * no conflicts between the sub-schemas.
diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/SchemaGeneratorConfigImpl.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/SchemaGeneratorConfigImpl.java
index d2db029..072cd73 100644
--- a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/SchemaGeneratorConfigImpl.java
+++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/SchemaGeneratorConfigImpl.java
@@ -124,6 +124,11 @@ public class SchemaGeneratorConfigImpl implements SchemaGeneratorConfig {
         return this.isOptionEnabled(Option.PLAIN_DEFINITION_KEYS);
     }
 
+    @Override
+    public boolean shouldIncludeExtraOpenApiFormatValues() {
+        return this.isOptionEnabled(Option.EXTRA_OPEN_API_FORMAT_VALUES);
+    }
+
     @Override
     public boolean shouldCleanupUnnecessaryAllOfElements() {
         return this.isOptionEnabled(Option.ALLOF_CLEANUP_AT_THE_END);
diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/module/SimpleTypeModule.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/module/SimpleTypeModule.java
index ad3c3d3..37a60f0 100644
--- a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/module/SimpleTypeModule.java
+++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/module/SimpleTypeModule.java
@@ -27,22 +27,9 @@ import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder;
 import com.github.victools.jsonschema.generator.SchemaKeyword;
 import com.github.victools.jsonschema.generator.TypeScope;
 import java.lang.reflect.Type;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.time.Instant;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.OffsetDateTime;
-import java.time.OffsetTime;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.util.Calendar;
 import java.util.Collections;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.UUID;
 import java.util.stream.Stream;
 
 /**
@@ -68,11 +55,17 @@ public class SimpleTypeModule implements Module {
         Stream.of(Boolean.class, boolean.class)
                 .forEach(module::withBooleanType);
 
-        Stream.of(Integer.class, int.class, Long.class, long.class, Short.class, short.class)
+        Stream.of(Integer.class, int.class)
+                .forEach(javaType -> module.withIntegerType(javaType, "int32"));
+        Stream.of(Long.class, long.class)
+                .forEach(javaType -> module.withIntegerType(javaType, "int64"));
+        Stream.of(Short.class, short.class)
                 .forEach(module::withIntegerType);
 
-        Stream.of(Double.class, double.class, Float.class, float.class)
-                .forEach(module::withNumberType);
+        Stream.of(Double.class, double.class)
+                .forEach(javaType -> module.withNumberType(javaType, "double"));
+        Stream.of(Float.class, float.class)
+                .forEach(javaType -> module.withNumberType(javaType, "float"));
 
         return module;
     }
@@ -80,7 +73,7 @@ public class SimpleTypeModule implements Module {
     /**
      * Factory method: creating an instance of the {@link SimpleTypeModule} containing mappings for various primitive types and their non-primitive
      * counter parts (e.g. {@code boolean} and {@code Boolean}) as well as other classes that are normally serialised in a JSON as non-objects, e.g.
-     * <br>{@link BigDecimal}, {@link BigInteger}, {@link UUID}, {@link LocalDate}, {@link LocalDateTime}, and a number of other date-time types.
+     * <br>{@code BigDecimal}, {@code BigInteger}, {@code UUID}, {@code LocalDate}, {@code LocalDateTime}, and a number of other date-time types.
      *
      * @return created module instance
      * @see #forPrimitiveTypes()
@@ -88,29 +81,37 @@ public class SimpleTypeModule implements Module {
     public static SimpleTypeModule forPrimitiveAndAdditionalTypes() {
         SimpleTypeModule module = SimpleTypeModule.forPrimitiveTypes();
 
-        Stream.of(LocalDate.class, LocalDateTime.class, LocalTime.class, ZonedDateTime.class, OffsetDateTime.class, OffsetTime.class,
-                Instant.class, ZoneId.class, Date.class, Calendar.class, UUID.class)
-                .forEach(module::withStringType);
-
-        module.withIntegerType(BigInteger.class);
+        module.withStringType(java.time.LocalDate.class, "date");
+        Stream.of(java.time.LocalDateTime.class, java.time.LocalTime.class, java.time.ZonedDateTime.class,
+                java.time.OffsetDateTime.class, java.time.OffsetTime.class, java.time.Instant.class,
+                java.util.Date.class, java.util.Calendar.class)
+                .forEach(javaType -> module.withStringType(javaType, "date-time"));
+        module.withStringType(java.util.UUID.class, "uuid");
+        module.withStringType(java.time.ZoneId.class);
+        module.withIntegerType(java.math.BigInteger.class);
 
-        Stream.of(BigDecimal.class, Number.class)
+        Stream.of(java.math.BigDecimal.class, Number.class)
                 .forEach(module::withNumberType);
 
         return module;
     }
 
     private final Map<Class<?>, SchemaKeyword> fixedJsonSchemaTypes = new HashMap<>();
+    private final Map<Class<?>, String> extraOpenApiFormatValues = new HashMap<>();
 
     /**
      * Add the given mapping for a (simple) java class to its JSON schema equivalent "type" attribute.
      *
      * @param javaType java class to map to a fixed JSON schema definition
      * @param jsonSchemaTypeValue "type" attribute value to set or {@link SchemaKeyword#TAG_TYPE_NULL} to indicate empty schema being desired
+     * @param openApiFormat optional {@link SchemaKeyword#TAG_FORMAT} value to set if the respective Option is enabled
      * @return this module instance (for chaining)
      */
-    private SimpleTypeModule with(Class<?> javaType, SchemaKeyword jsonSchemaTypeValue) {
+    private SimpleTypeModule with(Class<?> javaType, SchemaKeyword jsonSchemaTypeValue, String openApiFormat) {
         this.fixedJsonSchemaTypes.put(javaType, jsonSchemaTypeValue);
+        if (openApiFormat != null) {
+            this.extraOpenApiFormatValues.put(javaType, openApiFormat);
+        }
         return this;
     }
 
@@ -121,7 +122,7 @@ public class SimpleTypeModule implements Module {
      * @return this module instance (for chaining)
      */
     public final SimpleTypeModule withEmptySchema(Class<?> javaType) {
-        return this.with(javaType, SchemaKeyword.TAG_TYPE_NULL);
+        return this.with(javaType, SchemaKeyword.TAG_TYPE_NULL, null);
     }
 
     /**
@@ -133,7 +134,7 @@ public class SimpleTypeModule implements Module {
      */
     @Deprecated
     public final SimpleTypeModule withObjectType(Class<?> javaType) {
-        return this.with(javaType, SchemaKeyword.TAG_TYPE_OBJECT);
+        return this.with(javaType, SchemaKeyword.TAG_TYPE_OBJECT, null);
     }
 
     /**
@@ -143,7 +144,18 @@ public class SimpleTypeModule implements Module {
      * @return this module instance (for chaining)
      */
     public final SimpleTypeModule withStringType(Class<?> javaType) {
-        return this.with(javaType, SchemaKeyword.TAG_TYPE_STRING);
+        return this.withStringType(javaType, null);
+    }
+
+    /**
+     * Add the given mapping for a (simple) java class to its JSON schema equivalent "type" attribute: "{@link SchemaKeyword#TAG_TYPE_STRING}".
+     *
+     * @param javaType java class to map to a fixed JSON schema definition
+     * @param openApiFormat optional {@link SchemaKeyword#TAG_FORMAT} value, to set if respective Option is enabled
+     * @return this module instance (for chaining)
+     */
+    public final SimpleTypeModule withStringType(Class<?> javaType, String openApiFormat) {
+        return this.with(javaType, SchemaKeyword.TAG_TYPE_STRING, openApiFormat);
     }
 
     /**
@@ -153,7 +165,7 @@ public class SimpleTypeModule implements Module {
      * @return this module instance (for chaining)
      */
     public final SimpleTypeModule withBooleanType(Class<?> javaType) {
-        return this.with(javaType, SchemaKeyword.TAG_TYPE_BOOLEAN);
+        return this.with(javaType, SchemaKeyword.TAG_TYPE_BOOLEAN, null);
     }
 
     /**
@@ -163,17 +175,39 @@ public class SimpleTypeModule implements Module {
      * @return this module instance (for chaining)
      */
     public final SimpleTypeModule withIntegerType(Class<?> javaType) {
-        return this.with(javaType, SchemaKeyword.TAG_TYPE_INTEGER);
+        return this.withIntegerType(javaType, null);
+    }
+
+    /**
+     * Add the given mapping for a (simple) java class to its JSON schema equivalent "type" attribute: "{@link SchemaKeyword#TAG_TYPE_INTEGER}".
+     *
+     * @param javaType java class to map to a fixed JSON schema definition
+     * @param openApiFormat optional {@link SchemaKeyword#TAG_FORMAT} value, to set if respective Option is enabled
+     * @return this module instance (for chaining)
+     */
+    public final SimpleTypeModule withIntegerType(Class<?> javaType, String openApiFormat) {
+        return this.with(javaType, SchemaKeyword.TAG_TYPE_INTEGER, openApiFormat);
     }
 
     /**
-     * Add the given mapping for a (simple) java class to its JSON schema equivalent "type" attribute: "{@link SchemaKeyword#TAG_TYPE_NUMBER}".
+     * Add the given mapping for a (simple) java class to its JSON schema equivalent "type" attribute {@link SchemaKeyword#TAG_TYPE_NUMBER}.
      *
      * @param javaType java class to map to a fixed JSON schema definition
      * @return this module instance (for chaining)
      */
     public final SimpleTypeModule withNumberType(Class<?> javaType) {
-        return this.with(javaType, SchemaKeyword.TAG_TYPE_NUMBER);
+        return this.withNumberType(javaType, null);
+    }
+
+    /**
+     * Add the given mapping for a (simple) java class to its JSON schema equivalent "type" attribute {@link SchemaKeyword#TAG_TYPE_NUMBER}.
+     *
+     * @param javaType java class to map to a fixed JSON schema definition
+     * @param openApiFormat optional {@link SchemaKeyword#TAG_FORMAT} value, to set if respective Option is enabled
+     * @return this module instance (for chaining)
+     */
+    public final SimpleTypeModule withNumberType(Class<?> javaType, String openApiFormat) {
+        return this.with(javaType, SchemaKeyword.TAG_TYPE_NUMBER, openApiFormat);
     }
 
     /**
@@ -248,8 +282,14 @@ public class SimpleTypeModule implements Module {
             if (jsonSchemaTypeValue != SchemaKeyword.TAG_TYPE_NULL) {
                 customSchema.put(context.getKeyword(SchemaKeyword.TAG_TYPE), context.getKeyword(jsonSchemaTypeValue));
             }
+            if (context.getGeneratorConfig().shouldIncludeExtraOpenApiFormatValues()) {
+                String formatValue = SimpleTypeModule.this.extraOpenApiFormatValues.get(javaType.getErasedType());
+                if (formatValue != null) {
+                    customSchema.put(context.getKeyword(SchemaKeyword.TAG_FORMAT), formatValue);
+                }
+            }
             // set true as second parameter to indicate simple types to be always in-lined (i.e. not put into definitions)
-            return new CustomDefinition(customSchema, true);
+            return new CustomDefinition(customSchema, CustomDefinition.DefinitionType.INLINE, CustomDefinition.AttributeInclusion.YES);
         }
     }
 }


Test patch:
diff --git a/jsonschema-generator/src/test/java/com/github/victools/jsonschema/generator/SchemaGeneratorSimpleTypesTest.java b/jsonschema-generator/src/test/java/com/github/victools/jsonschema/generator/SchemaGeneratorSimpleTypesTest.java
index c101287..fb8f50a 100644
--- a/jsonschema-generator/src/test/java/com/github/victools/jsonschema/generator/SchemaGeneratorSimpleTypesTest.java
+++ b/jsonschema-generator/src/test/java/com/github/victools/jsonschema/generator/SchemaGeneratorSimpleTypesTest.java
@@ -32,38 +32,65 @@ import org.junit.runner.RunWith;
 @RunWith(JUnitParamsRunner.class)
 public class SchemaGeneratorSimpleTypesTest {
 
-    Object parametersForTestGenerateSchema_SimpleType() {
-        Object[][] typeCombinations = new Object[][]{
-            {Object.class, null},
-            {String.class, SchemaKeyword.TAG_TYPE_STRING},
-            {Character.class, SchemaKeyword.TAG_TYPE_STRING},
-            {char.class, SchemaKeyword.TAG_TYPE_STRING},
-            {CharSequence.class, SchemaKeyword.TAG_TYPE_STRING},
-            {Byte.class, SchemaKeyword.TAG_TYPE_STRING},
-            {byte.class, SchemaKeyword.TAG_TYPE_STRING},
-            {Boolean.class, SchemaKeyword.TAG_TYPE_BOOLEAN},
-            {boolean.class, SchemaKeyword.TAG_TYPE_BOOLEAN},
-            {Integer.class, SchemaKeyword.TAG_TYPE_INTEGER},
-            {int.class, SchemaKeyword.TAG_TYPE_INTEGER},
-            {Long.class, SchemaKeyword.TAG_TYPE_INTEGER},
-            {long.class, SchemaKeyword.TAG_TYPE_INTEGER},
-            {Short.class, SchemaKeyword.TAG_TYPE_INTEGER},
-            {short.class, SchemaKeyword.TAG_TYPE_INTEGER},
-            {Double.class, SchemaKeyword.TAG_TYPE_NUMBER},
-            {double.class, SchemaKeyword.TAG_TYPE_NUMBER},
-            {Float.class, SchemaKeyword.TAG_TYPE_NUMBER},
-            {float.class, SchemaKeyword.TAG_TYPE_NUMBER}
+    private Object[][] getSimpleTypeCombinations() {
+        return new Object[][]{
+            {Object.class, null, null},
+            {String.class, SchemaKeyword.TAG_TYPE_STRING, null},
+            {Character.class, SchemaKeyword.TAG_TYPE_STRING, null},
+            {char.class, SchemaKeyword.TAG_TYPE_STRING, null},
+            {CharSequence.class, SchemaKeyword.TAG_TYPE_STRING, null},
+            {Byte.class, SchemaKeyword.TAG_TYPE_STRING, null},
+            {byte.class, SchemaKeyword.TAG_TYPE_STRING, null},
+            {Boolean.class, SchemaKeyword.TAG_TYPE_BOOLEAN, null},
+            {boolean.class, SchemaKeyword.TAG_TYPE_BOOLEAN, null},
+            {Integer.class, SchemaKeyword.TAG_TYPE_INTEGER, "int32"},
+            {int.class, SchemaKeyword.TAG_TYPE_INTEGER, "int32"},
+            {Long.class, SchemaKeyword.TAG_TYPE_INTEGER, "int64"},
+            {long.class, SchemaKeyword.TAG_TYPE_INTEGER, "int64"},
+            {Short.class, SchemaKeyword.TAG_TYPE_INTEGER, null},
+            {short.class, SchemaKeyword.TAG_TYPE_INTEGER, null},
+            {Double.class, SchemaKeyword.TAG_TYPE_NUMBER, "double"},
+            {double.class, SchemaKeyword.TAG_TYPE_NUMBER, "double"},
+            {Float.class, SchemaKeyword.TAG_TYPE_NUMBER, "float"},
+            {float.class, SchemaKeyword.TAG_TYPE_NUMBER, "float"},
+            {java.time.LocalDate.class, SchemaKeyword.TAG_TYPE_STRING, "date"},
+            {java.time.LocalDateTime.class, SchemaKeyword.TAG_TYPE_STRING, "date-time"},
+            {java.time.LocalTime.class, SchemaKeyword.TAG_TYPE_STRING, "date-time"},
+            {java.time.ZonedDateTime.class, SchemaKeyword.TAG_TYPE_STRING, "date-time"},
+            {java.time.OffsetDateTime.class, SchemaKeyword.TAG_TYPE_STRING, "date-time"},
+            {java.time.OffsetTime.class, SchemaKeyword.TAG_TYPE_STRING, "date-time"},
+            {java.time.Instant.class, SchemaKeyword.TAG_TYPE_STRING, "date-time"},
+            {java.util.Date.class, SchemaKeyword.TAG_TYPE_STRING, "date-time"},
+            {java.util.Calendar.class, SchemaKeyword.TAG_TYPE_STRING, "date-time"},
+            {java.util.UUID.class, SchemaKeyword.TAG_TYPE_STRING, "uuid"},
+            {java.time.ZoneId.class, SchemaKeyword.TAG_TYPE_STRING, null},
+            {java.math.BigInteger.class, SchemaKeyword.TAG_TYPE_INTEGER, null},
+            {java.math.BigDecimal.class, SchemaKeyword.TAG_TYPE_NUMBER, null},
+            {Number.class, SchemaKeyword.TAG_TYPE_NUMBER, null},
         };
+    }
+
+    Object[] parametersForTestGenerateSchema_SimpleTypeWithoutFormat() {
+        Object[][] typeCombinations = this.getSimpleTypeCombinations();
         return EnumSet.allOf(SchemaVersion.class).stream()
                 .flatMap(schemaVersion -> Arrays.stream(typeCombinations).map(entry -> new Object[]{entry[0], entry[1], schemaVersion}))
                 .toArray();
     }
 
+    Object[] parametersForTestGenerateSchema_SimpleTypeWithFormat() {
+        Object[][] typeCombinations = this.getSimpleTypeCombinations();
+        return EnumSet.allOf(SchemaVersion.class).stream()
+                .flatMap(schemaVersion -> Arrays.stream(typeCombinations).map(entry -> new Object[]{entry[0], entry[1], entry[2], schemaVersion}))
+                .toArray();
+    }
+
     @Test
     @Parameters
-    public void testGenerateSchema_SimpleType(Class<?> targetType, SchemaKeyword expectedJsonSchemaType, SchemaVersion schemaVersion)
+    public void testGenerateSchema_SimpleTypeWithoutFormat(Class<?> targetType, SchemaKeyword expectedJsonSchemaType, SchemaVersion schemaVersion)
             throws Exception {
-        SchemaGeneratorConfig config = new SchemaGeneratorConfigBuilder(new ObjectMapper(), schemaVersion).build();
+        SchemaGeneratorConfig config = new SchemaGeneratorConfigBuilder(new ObjectMapper(), schemaVersion)
+                .with(Option.ADDITIONAL_FIXED_TYPES)
+                .build();
         SchemaGenerator generator = new SchemaGenerator(config);
         JsonNode result = generator.generateSchema(targetType);
         if (expectedJsonSchemaType == null) {
@@ -76,11 +103,34 @@ public class SchemaGeneratorSimpleTypesTest {
     }
 
     @Test
-    @Parameters(method = "parametersForTestGenerateSchema_SimpleType")
+    @Parameters
+    public void testGenerateSchema_SimpleTypeWithFormat(Class<?> targetType, SchemaKeyword expectedJsonSchemaType, String expectedFormat,
+            SchemaVersion schemaVersion) throws Exception {
+        SchemaGeneratorConfig config = new SchemaGeneratorConfigBuilder(new ObjectMapper(), schemaVersion)
+                .with(Option.ADDITIONAL_FIXED_TYPES, Option.EXTRA_OPEN_API_FORMAT_VALUES)
+                .build();
+        SchemaGenerator generator = new SchemaGenerator(config);
+        JsonNode result = generator.generateSchema(targetType);
+        if (expectedJsonSchemaType == null) {
+            Assert.assertTrue(result.isEmpty());
+        } else if (expectedFormat == null) {
+            Assert.assertEquals(1, result.size());
+            Assert.assertEquals(expectedJsonSchemaType.forVersion(schemaVersion),
+                    result.get(SchemaKeyword.TAG_TYPE.forVersion(schemaVersion)).asText());
+        } else {
+            Assert.assertEquals(2, result.size());
+            Assert.assertEquals(expectedJsonSchemaType.forVersion(schemaVersion),
+                    result.get(SchemaKeyword.TAG_TYPE.forVersion(schemaVersion)).asText());
+            Assert.assertEquals(expectedFormat, result.get(SchemaKeyword.TAG_FORMAT.forVersion(schemaVersion)).asText());
+        }
+    }
+
+    @Test
+    @Parameters(method = "parametersForTestGenerateSchema_SimpleTypeWithoutFormat")
     public void testGenerateSchema_SimpleType_withAdditionalPropertiesOption(Class<?> targetType, SchemaKeyword expectedJsonSchemaType,
             SchemaVersion schemaVersion) throws Exception {
         SchemaGeneratorConfig config = new SchemaGeneratorConfigBuilder(new ObjectMapper(), schemaVersion)
-                .with(Option.FORBIDDEN_ADDITIONAL_PROPERTIES_BY_DEFAULT)
+                .with(Option.ADDITIONAL_FIXED_TYPES, Option.FORBIDDEN_ADDITIONAL_PROPERTIES_BY_DEFAULT)
                 .build();
         SchemaGenerator generator = new SchemaGenerator(config);
         JsonNode result = generator.generateSchema(targetType);