Repository: victools/jsonschema-generator
Pull request #113 (2020-06-12 21:21:32)

feat: introduce configurable naming strategy for definition names
Hi @JanLabrie,

On GH-110 you mentioned that you already tackled the topic of adjusting the names/keys of subschemas in the `definitions`/`$defs`.
I'd appreciate if you could have a look at my proposal here.

I was aiming for flexibility while preserving the contract of the JSON Schema Specification (and OpenAPI Specification) regarding the allowed characters in this schema keys.

What do you reckon?


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9e9ecea..eea9605 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,19 @@ 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
+- Possibility to configure `SchemaDefinitionNamingStrategy` via `configBuilder.forTypesInGeneral().withDefinitionNamingStrategy()`
+- Explicit `DefaultSchemaDefinitionNamingStrategy` that is being applied if no other `SchemaDefinitionNamingStrategy` is being configured
+
+#### Changed
+- Determine names/keys of subschemas in `definitions`/`$defs` through configurable `SchemaDefinitionNamingStrategy`
+
+#### Fixed
+- For multiple definitions for the same type, they might be unnecessarily treated as having conflicting definition names requiring resolution
+
+#### Removed
+- Obsolete `TypeContext.getSchemaDefinitionName()`
 
 ## [4.12.2] - 2020-06-10
 ### `jsonschema-generator`
diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/SchemaBuilder.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/SchemaBuilder.java
index ff81254..8d47b0d 100644
--- a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/SchemaBuilder.java
+++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/SchemaBuilder.java
@@ -22,14 +22,18 @@ import com.github.victools.jsonschema.generator.impl.AttributeCollector;
 import com.github.victools.jsonschema.generator.impl.DefinitionKey;
 import com.github.victools.jsonschema.generator.impl.SchemaCleanUpUtils;
 import com.github.victools.jsonschema.generator.impl.SchemaGenerationContextImpl;
+import com.github.victools.jsonschema.generator.naming.CleanSchemaDefinitionNamingStrategy;
+import com.github.victools.jsonschema.generator.naming.DefaultSchemaDefinitionNamingStrategy;
+import com.github.victools.jsonschema.generator.naming.SchemaDefinitionNamingStrategy;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Function;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 /**
@@ -69,7 +73,7 @@ public class SchemaBuilder {
     private final TypeContext typeContext;
     private final SchemaGenerationContextImpl generationContext;
     private final List<ObjectNode> schemaNodes;
-    private final Function<String, String> definitionKeyCleanup;
+    private final CleanSchemaDefinitionNamingStrategy definitionNamingStrategy;
 
     /**
      * Constructor.
@@ -83,10 +87,16 @@ public class SchemaBuilder {
         this.generationContext = new SchemaGenerationContextImpl(this.config, this.typeContext);
         this.schemaNodes = new ArrayList<>();
 
+        SchemaDefinitionNamingStrategy baseNamingStrategy = config.getDefinitionNamingStrategy();
+        if (baseNamingStrategy == null) {
+            baseNamingStrategy = new DefaultSchemaDefinitionNamingStrategy();
+        }
         SchemaCleanUpUtils cleanupUtils = new SchemaCleanUpUtils(config);
-        this.definitionKeyCleanup = config.shouldUsePlainDefinitionKeys()
+        Function<String, String> definitionCleanUpTask = config.shouldUsePlainDefinitionKeys()
                 ? cleanupUtils::ensureDefinitionKeyIsPlain
                 : cleanupUtils::ensureDefinitionKeyIsUriCompatible;
+
+        this.definitionNamingStrategy = new CleanSchemaDefinitionNamingStrategy(baseNamingStrategy, definitionCleanUpTask);
     }
 
     /**
@@ -187,19 +197,35 @@ public class SchemaBuilder {
      */
     private ObjectNode buildDefinitionsAndResolveReferences(String designatedDefinitionPath, DefinitionKey mainSchemaKey,
             SchemaGenerationContextImpl generationContext) {
-        ObjectNode definitionsNode = this.config.createObjectNode();
-        boolean createDefinitionsForAll = this.config.shouldCreateDefinitionsForAllObjects();
-        boolean createDefinitionForMainSchema = this.config.shouldCreateDefinitionForMainSchema();
-        boolean inlineAllSchemas = this.config.shouldInlineAllSchemas();
-        for (Map.Entry<DefinitionKey, String> entry : this.getReferenceKeys(mainSchemaKey, generationContext).entrySet()) {
+        final ObjectNode definitionsNode = this.config.createObjectNode();
+        final boolean createDefinitionsForAll = this.config.shouldCreateDefinitionsForAllObjects();
+        final boolean inlineAllSchemas = this.config.shouldInlineAllSchemas();
+
+        final AtomicBoolean considerOnlyDirectReferences = new AtomicBoolean(false);
+        Predicate<DefinitionKey> shouldProduceDefinition = definitionKey -> {
+            if (inlineAllSchemas) {
+                return false;
+            }
+            if (definitionKey.equals(mainSchemaKey)) {
+                return true;
+            }
+            List<ObjectNode> references = generationContext.getReferences(definitionKey);
+            if (considerOnlyDirectReferences.get() && references.isEmpty()) {
+                return false;
+            }
+            List<ObjectNode> nullableReferences = generationContext.getNullableReferences(definitionKey);
+            return createDefinitionsForAll || (references.size() + nullableReferences.size()) > 1;
+        };
+        Map<DefinitionKey, String> baseReferenceKeys = this.getReferenceKeys(mainSchemaKey, shouldProduceDefinition, generationContext);
+        considerOnlyDirectReferences.set(true);
+        final boolean createDefinitionForMainSchema = this.config.shouldCreateDefinitionForMainSchema();
+        for (Map.Entry<DefinitionKey, String> entry : baseReferenceKeys.entrySet()) {
             String definitionName = entry.getValue();
             DefinitionKey definitionKey = entry.getKey();
             List<ObjectNode> references = generationContext.getReferences(definitionKey);
             List<ObjectNode> nullableReferences = generationContext.getNullableReferences(definitionKey);
             final String referenceKey;
-            boolean referenceInline = inlineAllSchemas
-                    || (references.isEmpty() || (!createDefinitionsForAll && (references.size() + nullableReferences.size()) < 2))
-                    && !definitionKey.equals(mainSchemaKey);
+            boolean referenceInline = !shouldProduceDefinition.test(definitionKey);
             if (referenceInline) {
                 // it is a simple type, just in-line the sub-schema everywhere
                 ObjectNode definition = generationContext.getDefinition(definitionKey);
@@ -225,7 +251,8 @@ public class SchemaBuilder {
                 }
                 generationContext.makeNullable(definition);
                 if (!inlineAllSchemas && (createDefinitionsForAll || nullableReferences.size() > 1)) {
-                    String nullableDefinitionName = definitionName + "-nullable";
+                    String nullableDefinitionName = this.definitionNamingStrategy
+                            .adjustNullableName(definitionKey, definitionName, generationContext);
                     definitionsNode.set(nullableDefinitionName, definition);
                     nullableReferences.forEach(node -> node.put(this.config.getKeyword(SchemaKeyword.TAG_REF),
                             this.config.getKeyword(SchemaKeyword.TAG_REF_MAIN) + '/' + designatedDefinitionPath + '/' + nullableDefinitionName));
@@ -242,38 +269,49 @@ public class SchemaBuilder {
      * Derive the applicable keys for the collected entries for the {@link SchemaKeyword#TAG_DEFINITIONS} in the given context.
      *
      * @param mainSchemaKey special definition key for the main schema
+     * @param shouldProduceDefinition filter to indicate whether a given key should be considered when determining definition names
      * @param generationContext generation context in which all traversed types and their definitions have been collected
      * @return encountered types with their corresponding reference keys
      */
-    private Map<DefinitionKey, String> getReferenceKeys(DefinitionKey mainSchemaKey, SchemaGenerationContextImpl generationContext) {
+    private Map<DefinitionKey, String> getReferenceKeys(DefinitionKey mainSchemaKey, Predicate<DefinitionKey> shouldProduceDefinition,
+            SchemaGenerationContextImpl generationContext) {
         boolean createDefinitionForMainSchema = this.config.shouldCreateDefinitionForMainSchema();
+        Function<DefinitionKey, String> definitionNamesForKey = key -> this.definitionNamingStrategy.getDefinitionNameForKey(key, generationContext);
         Map<String, List<DefinitionKey>> aliases = generationContext.getDefinedTypes().stream()
-                .collect(Collectors.groupingBy(this::getSchemaBaseDefinitionName, TreeMap::new, Collectors.toList()));
+                .collect(Collectors.groupingBy(definitionNamesForKey, TreeMap::new, Collectors.toList()));
         Map<DefinitionKey, String> referenceKeys = new LinkedHashMap<>();
         for (Map.Entry<String, List<DefinitionKey>> group : aliases.entrySet()) {
-            List<DefinitionKey> definitionKeys = group.getValue();
+            group.getValue().forEach(key -> referenceKeys.put(key, ""));
+            List<DefinitionKey> definitionKeys = group.getValue().stream()
+                    .filter(shouldProduceDefinition)
+                    .collect(Collectors.toList());
             if (definitionKeys.size() == 1
                     || (definitionKeys.size() == 2 && !createDefinitionForMainSchema && definitionKeys.contains(mainSchemaKey))) {
                 definitionKeys.forEach(key -> referenceKeys.put(key, group.getKey()));
             } else {
-                AtomicInteger counter = new AtomicInteger(0);
-                definitionKeys.forEach(key -> referenceKeys.put(key, group.getKey() + "-" + counter.incrementAndGet()));
+                Map<DefinitionKey, String> referenceKeyGroup = definitionKeys.stream()
+                        .collect(Collectors.toMap(key -> key, _key -> group.getKey(), (val1, _val2) -> val1, LinkedHashMap::new));
+                this.definitionNamingStrategy.adjustDuplicateNames(referenceKeyGroup, generationContext);
+                if (definitionKeys.size() != referenceKeyGroup.size()) {
+                    throw new IllegalStateException(SchemaDefinitionNamingStrategy.class.getSimpleName()
+                            + " of type " + this.definitionNamingStrategy.getClass().getSimpleName()
+                            + " altered list of subschemas with duplicate names.");
+                }
+                referenceKeys.putAll(referenceKeyGroup);
             }
         }
+        String remainingDuplicateKeys = referenceKeys.values().stream()
+                .filter(value -> !value.isEmpty())
+                .collect(Collectors.groupingBy(key -> key, Collectors.counting()))
+                .entrySet().stream()
+                .filter(entry -> entry.getValue() > 1)
+                .map(Map.Entry::getKey)
+                .collect(Collectors.joining(", "));
+        if (!remainingDuplicateKeys.isEmpty()) {
+            throw new IllegalStateException(SchemaDefinitionNamingStrategy.class.getSimpleName()
+                    + " of type " + this.definitionNamingStrategy.getClass().getSimpleName()
+                    + " produced duplicate keys: " + remainingDuplicateKeys);
+        }
         return referenceKeys;
     }
-
-    /**
-     * Returns the name to be associated with an entry in the generated schema's list of {@link SchemaKeyword#TAG_DEFINITIONS}.
-     * <br>
-     * Beware: if multiple types have the same name, the actual key in {@link SchemaKeyword#TAG_DEFINITIONS} may have a numeric counter appended to it
-     *
-     * @param key the definition key to be represented in the generated schema's {@link SchemaKeyword#TAG_DEFINITIONS}
-     * @return name in {@link SchemaKeyword#TAG_DEFINITIONS}
-     */
-    private String getSchemaBaseDefinitionName(DefinitionKey key) {
-        String schemaDefinitionName = this.typeContext.getSchemaDefinitionName(key.getType());
-        // ensure that the type description is converted into a compatible format
-        return this.definitionKeyCleanup.apply(schemaDefinitionName);
-    }
 }
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 0887ddb..028a612 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
@@ -20,6 +20,7 @@ import com.fasterxml.classmate.ResolvedType;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.github.victools.jsonschema.generator.naming.SchemaDefinitionNamingStrategy;
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
 import java.util.Collection;
@@ -142,6 +143,13 @@ public interface SchemaGeneratorConfig {
      */
     int sortProperties(MemberScope<?, ?> first, MemberScope<?, ?> second);
 
+    /**
+     * Getter for the naming strategy to be applied when determining key names in the "definitions"/"$defs".
+     *
+     * @return definition key naming strategy
+     */
+    SchemaDefinitionNamingStrategy getDefinitionNamingStrategy();
+
     /**
      * Look-up the non-standard JSON schema definition for a given property. Falling-back on the per-type custom definitions.
      *
diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/SchemaGeneratorGeneralConfigPart.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/SchemaGeneratorGeneralConfigPart.java
index 73dcab0..741dcc7 100644
--- a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/SchemaGeneratorGeneralConfigPart.java
+++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/SchemaGeneratorGeneralConfigPart.java
@@ -17,6 +17,7 @@
 package com.github.victools.jsonschema.generator;
 
 import com.github.victools.jsonschema.generator.impl.PropertySortUtils;
+import com.github.victools.jsonschema.generator.naming.SchemaDefinitionNamingStrategy;
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
 import java.util.ArrayList;
@@ -32,6 +33,7 @@ import java.util.Map;
 public class SchemaGeneratorGeneralConfigPart extends SchemaGeneratorTypeConfigPart<TypeScope> {
 
     private Comparator<MemberScope<?, ?>> propertySorter = PropertySortUtils.DEFAULT_PROPERTY_ORDER;
+    private SchemaDefinitionNamingStrategy definitionNamingStrategy = null;
 
     private final List<CustomDefinitionProviderV2> customDefinitionProviders = new ArrayList<>();
     private final List<SubtypeResolver> subtypeResolvers = new ArrayList<>();
@@ -60,6 +62,26 @@ public class SchemaGeneratorGeneralConfigPart extends SchemaGeneratorTypeConfigP
         return this.propertySorter;
     }
 
+    /**
+     * Replacing the current naming strategy for keys in the "definitions"/"$defs".
+     *
+     * @param namingStrategy naming strategy for "definitions"/"$defs" keys
+     * @return this builder instance (for chaining)
+     */
+    public SchemaGeneratorGeneralConfigPart withDefinitionNamingStrategy(SchemaDefinitionNamingStrategy namingStrategy) {
+        this.definitionNamingStrategy = namingStrategy;
+        return this;
+    }
+
+    /**
+     * Getter for the current naming strategy for keys in the "definitions"/"$defs".
+     *
+     * @return applicable naming strategy for "definitions"/"$defs" keys (or {@code null} if the a default strategy should be used)
+     */
+    public SchemaDefinitionNamingStrategy getDefinitionNamingStrategy() {
+        return this.definitionNamingStrategy;
+    }
+
     /**
      * Adding a custom schema provider – if it returns null for a given type, the next definition provider will be applied.
      * <br>
diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/TypeContext.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/TypeContext.java
index fdf72db..96bca70 100644
--- a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/TypeContext.java
+++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/TypeContext.java
@@ -206,20 +206,6 @@ public class TypeContext {
         return result;
     }
 
-    /**
-     * Returns the name to be associated with an entry in the generated schema's list of "definitions"/"$defs".
-     * <br>
-     * Beware: if multiple types have the same name, the actual key in "definitions"/"$defs" may have a numeric counter appended to it
-     *
-     * @param type the type to be represented in the generated schema's "definitions"/"$defs"
-     * @return name in "definitions"/"$defs"
-     */
-    public String getSchemaDefinitionName(ResolvedType type) {
-        // known limitation: if two types have the same name and the only difference is their package, the resulting schema will only contain one
-        // using getFullTypeDescription() instead would avoid that issue, but the resulting schema does not look as nice
-        return this.getSimpleTypeDescription(type);
-    }
-
     /**
      * Returns the type description for an argument in a method's property name.
      *
diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/DefinitionKey.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/DefinitionKey.java
index 6c03e91..109ffda 100644
--- a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/DefinitionKey.java
+++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/DefinitionKey.java
@@ -34,7 +34,7 @@ public class DefinitionKey {
      * @param type encountered type a schema definition is associated with
      * @param ignoredDefinitionProvider first custom definition provider that was ignored when creating the definition (is null in most cases)
      */
-    DefinitionKey(ResolvedType type, CustomDefinitionProviderV2 ignoredDefinitionProvider) {
+    protected DefinitionKey(ResolvedType type, CustomDefinitionProviderV2 ignoredDefinitionProvider) {
         this.type = type;
         this.ignoredDefinitionProvider = ignoredDefinitionProvider;
     }
@@ -55,7 +55,7 @@ public class DefinitionKey {
      *
      * @return first custom definition provider that was ignored when creating the definition (is null in most cases)
      */
-    CustomDefinitionProviderV2 getIgnoredDefinitionProvider() {
+    public CustomDefinitionProviderV2 getIgnoredDefinitionProvider() {
         return this.ignoredDefinitionProvider;
     }
 
diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/SchemaCleanUpUtils.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/SchemaCleanUpUtils.java
index 6596656..060b35d 100644
--- a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/SchemaCleanUpUtils.java
+++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/impl/SchemaCleanUpUtils.java
@@ -22,7 +22,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.github.victools.jsonschema.generator.SchemaGeneratorConfig;
 import com.github.victools.jsonschema.generator.SchemaKeyword;
 import com.github.victools.jsonschema.generator.SchemaVersion;
-import com.github.victools.jsonschema.generator.TypeContext;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -257,7 +256,7 @@ public class SchemaCleanUpUtils {
     /**
      * Replace characters in the given definition key that are deemed incompatible within a URI (as expected by JSON Schema).
      *
-     * @param definitionKey the output of the {@link TypeContext#getSchemaDefinitionName(com.fasterxml.classmate.ResolvedType)}
+     * @param definitionKey {@code SchemaDefinitionNamingStrategy} output
      * @return URI compatible version of the given definition key
      */
     public String ensureDefinitionKeyIsUriCompatible(String definitionKey) {
@@ -274,7 +273,7 @@ public class SchemaCleanUpUtils {
     /**
      * Replace characters in the given definition key that are neither alphanumeric nor a dot, dash or underscore (as expected by OpenAPI).
      *
-     * @param definitionKey the output of the {@link TypeContext#getSchemaDefinitionName(com.fasterxml.classmate.ResolvedType)}
+     * @param definitionKey {@code SchemaDefinitionNamingStrategy} output
      * @return simplified version of the given definition key
      */
     public String ensureDefinitionKeyIsPlain(String definitionKey) {
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 73ef006..c3ebba0 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
@@ -37,6 +37,7 @@ import com.github.victools.jsonschema.generator.SchemaKeyword;
 import com.github.victools.jsonschema.generator.SchemaVersion;
 import com.github.victools.jsonschema.generator.TypeAttributeOverrideV2;
 import com.github.victools.jsonschema.generator.TypeScope;
+import com.github.victools.jsonschema.generator.naming.SchemaDefinitionNamingStrategy;
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
 import java.util.Collection;
@@ -163,6 +164,11 @@ public class SchemaGeneratorConfigImpl implements SchemaGeneratorConfig {
         return this.typesInGeneralConfigPart.getPropertySorter().compare(first, second);
     }
 
+    @Override
+    public SchemaDefinitionNamingStrategy getDefinitionNamingStrategy() {
+        return this.typesInGeneralConfigPart.getDefinitionNamingStrategy();
+    }
+
     @Override
     @SuppressWarnings("unchecked")
     public <M extends MemberScope<?, ?>> CustomDefinition getCustomDefinition(M scope, SchemaGenerationContext context,
diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/naming/CleanSchemaDefinitionNamingStrategy.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/naming/CleanSchemaDefinitionNamingStrategy.java
new file mode 100644
index 0000000..d8769f9
--- /dev/null
+++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/naming/CleanSchemaDefinitionNamingStrategy.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020 VicTools.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.github.victools.jsonschema.generator.naming;
+
+import com.github.victools.jsonschema.generator.SchemaGenerationContext;
+import com.github.victools.jsonschema.generator.impl.DefinitionKey;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * Wrapper for a {@link SchemaDefinitionNamingStrategy} that performs a specific clean-up task on all returned values.
+ */
+public class CleanSchemaDefinitionNamingStrategy implements SchemaDefinitionNamingStrategy {
+
+    private final SchemaDefinitionNamingStrategy strategy;
+    private final Function<String, String> cleanUpTask;
+
+    /**
+     * Constructor expecting a naming strategy to be wrapped and the applicable clean-up task.
+     *
+     * @param strategy definition naming strategy to be wrapped
+     * @param cleanUpTask task discarding/replacing illegal characters
+     */
+    public CleanSchemaDefinitionNamingStrategy(SchemaDefinitionNamingStrategy strategy, Function<String, String> cleanUpTask) {
+        this.strategy = strategy;
+        this.cleanUpTask = cleanUpTask;
+    }
+
+    @Override
+    public String getDefinitionNameForKey(DefinitionKey key, SchemaGenerationContext generationContext) {
+        String output = this.strategy.getDefinitionNameForKey(key, generationContext);
+        return this.cleanUpTask.apply(output);
+    }
+
+    @Override
+    public void adjustDuplicateNames(Map<DefinitionKey, String> subschemasWithDuplicateNames, SchemaGenerationContext generationContext) {
+        this.strategy.adjustDuplicateNames(subschemasWithDuplicateNames, generationContext);
+        subschemasWithDuplicateNames.entrySet().forEach(entry -> entry.setValue(this.cleanUpTask.apply(entry.getValue())));
+    }
+
+    @Override
+    public String adjustNullableName(DefinitionKey key, String definitionName, SchemaGenerationContext generationContext) {
+        String output = this.strategy.adjustNullableName(key, definitionName, generationContext);
+        return this.cleanUpTask.apply(output);
+    }
+}
diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/naming/DefaultSchemaDefinitionNamingStrategy.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/naming/DefaultSchemaDefinitionNamingStrategy.java
new file mode 100644
index 0000000..1f5b408
--- /dev/null
+++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/naming/DefaultSchemaDefinitionNamingStrategy.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020 VicTools.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.github.victools.jsonschema.generator.naming;
+
+import com.fasterxml.classmate.ResolvedType;
+import com.github.victools.jsonschema.generator.SchemaGenerationContext;
+import com.github.victools.jsonschema.generator.TypeContext;
+import com.github.victools.jsonschema.generator.impl.DefinitionKey;
+
+/**
+ * Default implementation of a {@link SchemaDefinitionNamingStrategy} using the output of {@link TypeContext#getSimpleTypeDescription(ResolvedType)}
+ * as definition name/key.
+ */
+public class DefaultSchemaDefinitionNamingStrategy implements SchemaDefinitionNamingStrategy {
+
+    @Override
+    public String getDefinitionNameForKey(DefinitionKey key, SchemaGenerationContext generationContext) {
+        TypeContext typeContext = generationContext.getTypeContext();
+        ResolvedType type = key.getType();
+        return typeContext.getSimpleTypeDescription(type);
+    }
+}
diff --git a/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/naming/SchemaDefinitionNamingStrategy.java b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/naming/SchemaDefinitionNamingStrategy.java
new file mode 100644
index 0000000..f23857c
--- /dev/null
+++ b/jsonschema-generator/src/main/java/com/github/victools/jsonschema/generator/naming/SchemaDefinitionNamingStrategy.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2020 VicTools.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.github.victools.jsonschema.generator.naming;
+
+import com.github.victools.jsonschema.generator.SchemaGenerationContext;
+import com.github.victools.jsonschema.generator.impl.DefinitionKey;
+import java.util.Map;
+
+/**
+ * Naming strategy for the keys in the "definitions"/"$defs" containing shared/reused subschemas.
+ */
+public interface SchemaDefinitionNamingStrategy {
+
+    /**
+     * Getter for the name/key in the "definitions"/"$defs" to represent the given {@link DefinitionKey}.
+     *
+     * @param key definition reference for a type (there may be multiple different keys for the same type if custom definitions are involved)
+     * @param generationContext generation context providing access to the applied configuration and type context
+     * @return name/key in "definitions"/"$defs" for the indicated subschema
+     * @see SchemaGenerationContext#getGeneratorConfig()
+     * @see SchemaGenerationContext#getTypeContext()
+     */
+    String getDefinitionNameForKey(DefinitionKey key, SchemaGenerationContext generationContext);
+
+    /**
+     * Adjust the names/keys in the "definitions"/"$defs" for the given definition references that have the same names (according to
+     * {@link #getDefinitionNameForKey(DefinitionKey, SchemaGenerationContext)}) to ensure their uniqueness.
+     * <br>
+     * By default, a numeric counter is appended after a separating dash to each duplicate name.
+     *
+     * @param subschemasWithDuplicateNames definition references that initially have the same values that should be adjusted
+     * @param generationContext generation context providing access to the applied configuration and type context
+     * @see #getDefinitionNameForKey(DefinitionKey, SchemaGenerationContext)
+     */
+    default void adjustDuplicateNames(Map<DefinitionKey, String> subschemasWithDuplicateNames, SchemaGenerationContext generationContext) {
+        int index = 1;
+        for (Map.Entry<DefinitionKey, String> singleEntry : subschemasWithDuplicateNames.entrySet()) {
+            singleEntry.setValue(singleEntry.getValue() + "-" + index);
+            index++;
+        }
+    }
+
+    /**
+     * Provide an alternative definition name for the given key and name when it is nullable.
+     * <br>
+     * By default, a {@code "-nullable"} suffix will be appended.
+     *
+     * @param key definition reference for a type (there may be multiple different keys for the same type if custom definitions are involved)
+     * @param definitionName previous result of {@link #getDefinitionNameForKey(DefinitionKey, SchemaGenerationContext)} to be adjusted
+     * @param generationContext generation context providing access to the applied configuration and type context
+     * @return adjusted definition name
+     */
+    default String adjustNullableName(DefinitionKey key, String definitionName, SchemaGenerationContext generationContext) {
+        return definitionName + "-nullable";
+    }
+}


Test patch:
diff --git a/jsonschema-generator/src/test/java/com/github/victools/jsonschema/generator/SchemaGeneratorCustomDefinitionsTest.java b/jsonschema-generator/src/test/java/com/github/victools/jsonschema/generator/SchemaGeneratorCustomDefinitionsTest.java
index 4deb062..d029b98 100644
--- a/jsonschema-generator/src/test/java/com/github/victools/jsonschema/generator/SchemaGeneratorCustomDefinitionsTest.java
+++ b/jsonschema-generator/src/test/java/com/github/victools/jsonschema/generator/SchemaGeneratorCustomDefinitionsTest.java
@@ -16,12 +16,15 @@
 
 package com.github.victools.jsonschema.generator;
 
+import com.github.victools.jsonschema.generator.naming.SchemaDefinitionNamingStrategy;
 import com.fasterxml.classmate.ResolvedType;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.github.victools.jsonschema.generator.impl.DefinitionKey;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
 import org.junit.Assert;
@@ -149,7 +152,22 @@ public class SchemaGeneratorCustomDefinitionsTest {
                 .with(Option.DEFINITIONS_FOR_ALL_OBJECTS);
         configBuilder.forTypesInGeneral()
                 .withCustomDefinitionProvider(customDefinitionProviderOne)
-                .withCustomDefinitionProvider(customDefinitionProviderTwo);
+                .withCustomDefinitionProvider(customDefinitionProviderTwo)
+                .withDefinitionNamingStrategy(new SchemaDefinitionNamingStrategy() {
+                    @Override
+                    public String getDefinitionNameForKey(DefinitionKey key, SchemaGenerationContext generationContext) {
+                        return key.getType().getErasedType().getSimpleName().toLowerCase();
+                    }
+
+                    @Override
+                    public void adjustDuplicateNames(Map<DefinitionKey, String> duplicateNames, SchemaGenerationContext context) {
+                        char suffix = 'a';
+                        for (Map.Entry<DefinitionKey, String> singleEntry : duplicateNames.entrySet()) {
+                            singleEntry.setValue(singleEntry.getValue() + " (" + suffix + ")");
+                            suffix++;
+                        }
+                    }
+                });
         SchemaGenerator generator = new SchemaGenerator(configBuilder.build());
         JsonNode result = generator.generateSchema(TestDirectCircularClass.class);
         JSONAssert.assertEquals('\n' + result.toString() + '\n',
diff --git a/jsonschema-generator/src/test/java/com/github/victools/jsonschema/generator/naming/SchemaDefinitionNamingStrategyTest.java b/jsonschema-generator/src/test/java/com/github/victools/jsonschema/generator/naming/SchemaDefinitionNamingStrategyTest.java
new file mode 100644
index 0000000..51250c8
--- /dev/null
+++ b/jsonschema-generator/src/test/java/com/github/victools/jsonschema/generator/naming/SchemaDefinitionNamingStrategyTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2020 VicTools.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.github.victools.jsonschema.generator.naming;
+
+import com.github.victools.jsonschema.generator.naming.SchemaDefinitionNamingStrategy;
+import com.fasterxml.classmate.ResolvedType;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy.PropertyNamingStrategyBase;
+import com.github.victools.jsonschema.generator.SchemaGenerationContext;
+import com.github.victools.jsonschema.generator.TypeContext;
+import com.github.victools.jsonschema.generator.naming.DefaultSchemaDefinitionNamingStrategy;
+import com.github.victools.jsonschema.generator.impl.DefinitionKey;
+import com.github.victools.jsonschema.generator.impl.SchemaCleanUpUtils;
+import com.github.victools.jsonschema.generator.impl.TypeContextFactory;
+import java.math.BigDecimal;
+import java.util.Map;
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+/**
+ * Test/examples of possible {@link SchemaDefinitionNamingStrategy} implementations.
+ */
+@RunWith(JUnitParamsRunner.class)
+public class SchemaDefinitionNamingStrategyTest {
+
+    private static TypeContext typeContext = TypeContextFactory.createDefaultTypeContext();
+    private DefinitionKey key;
+    private SchemaGenerationContext generationContext;
+
+    @AfterClass
+    public static void discardTypeContext() {
+        SchemaDefinitionNamingStrategyTest.typeContext = null;
+    }
+
+    @Before
+    public void setUp() {
+        this.key = Mockito.mock(DefinitionKey.class);
+        this.generationContext = Mockito.mock(SchemaGenerationContext.class);
+        Mockito.when(this.generationContext.getTypeContext()).thenReturn(SchemaDefinitionNamingStrategyTest.typeContext);
+    }
+
+    public Object[] parametersForTestExampleStrategy() {
+        PropertyNamingStrategyBase jacksonSnakeCase = new PropertyNamingStrategy.SnakeCaseStrategy();
+        SchemaDefinitionNamingStrategy snakeCase = new DefaultSchemaDefinitionNamingStrategy() {
+            @Override
+            public String getDefinitionNameForKey(DefinitionKey key, SchemaGenerationContext generationContext) {
+                return jacksonSnakeCase.translate(super.getDefinitionNameForKey(key, generationContext))
+                        .replaceAll("<_", "<")
+                        .replaceAll(", _", ",");
+            }
+        };
+        PropertyNamingStrategyBase jacksonDotCase = new PropertyNamingStrategy.LowerDotCaseStrategy();
+        SchemaDefinitionNamingStrategy dotCase = new DefaultSchemaDefinitionNamingStrategy() {
+            @Override
+            public String getDefinitionNameForKey(DefinitionKey key, SchemaGenerationContext generationContext) {
+                return jacksonDotCase.translate(super.getDefinitionNameForKey(key, generationContext))
+                        .replaceAll("<.", "<")
+                        .replaceAll(", .", "-");
+            }
+        };
+        SchemaDefinitionNamingStrategy inclPackage = (definitionKey, context) -> context.getTypeContext()
+                .getFullTypeDescription(definitionKey.getType());
+
+        return new Object[][]{
+            {"Snake Case", snakeCase, typeContext.resolve(BigDecimal.class), "big_decimal", "big_decimal"},
+            {"Snake Case", snakeCase, typeContext.resolve(Map.class, String.class, BigDecimal.class),
+                "map(string,big_decimal)", "map_string.big_decimal_"},
+            {"Dot Case", dotCase, typeContext.resolve(BigDecimal.class), "big.decimal", "big.decimal"},
+            {"Dot Case", dotCase, typeContext.resolve(Map.class, String.class, BigDecimal.class),
+                "map(string-big.decimal)", "map_string-big.decimal_"},
+            {"Incl. Package", inclPackage, typeContext.resolve(BigDecimal.class), "java.math.BigDecimal", "java.math.BigDecimal"},
+            {"Incl. Package", inclPackage, typeContext.resolve(Map.class, String.class, BigDecimal.class),
+                "java.util.Map(java.lang.String,java.math.BigDecimal)", "java.util.Map_java.lang.String.java.math.BigDecimal_"}
+        };
+    }
+
+    @Test
+    @Parameters
+    @TestCaseName(value = "{method}({0}, {3} | {4}) [{index}]")
+    public void testExampleStrategy(String caseTitle, SchemaDefinitionNamingStrategy strategy, ResolvedType type,
+            String expectedUriCompatibleName, String expectedPlainName) {
+        Mockito.when(this.key.getType()).thenReturn(type);
+        String result = strategy.getDefinitionNameForKey(this.key, this.generationContext);
+        // before the produced name is used in an actual schema, the SchemaCleanUpUtils come into play one way or another
+        SchemaCleanUpUtils cleanUpUtils = new SchemaCleanUpUtils(null);
+        Assert.assertEquals(expectedUriCompatibleName, cleanUpUtils.ensureDefinitionKeyIsUriCompatible(result));
+        Assert.assertEquals(expectedPlainName, cleanUpUtils.ensureDefinitionKeyIsPlain(result));
+    }
+}
diff --git a/jsonschema-generator/src/test/resources/com/github/victools/jsonschema/generator/multiple-definitions-one-type-DRAFT_2019_09.json b/jsonschema-generator/src/test/resources/com/github/victools/jsonschema/generator/multiple-definitions-one-type-DRAFT_2019_09.json
index 97fbe92..3435648 100644
--- a/jsonschema-generator/src/test/resources/com/github/victools/jsonschema/generator/multiple-definitions-one-type-DRAFT_2019_09.json
+++ b/jsonschema-generator/src/test/resources/com/github/victools/jsonschema/generator/multiple-definitions-one-type-DRAFT_2019_09.json
@@ -1,7 +1,23 @@
 {
     "$schema": "https://json-schema.org/draft/2019-09/schema",
     "$defs": {
-        "String": {
+        "int(a)": {
+            "title": "Custom Definition #2 for int",
+            "anyOf": [{
+                    "type": "integer"
+                }, {
+                    "type": "null"
+                }]
+        },
+        "int(b)": {
+            "title": "Custom Definition #1 for int",
+            "anyOf": [{
+                    "$ref": "#/$defs/int(a)"
+                }, {
+                    "type": "null"
+                }]
+        },
+        "string": {
             "title": "Custom Definition #1 for String",
             "anyOf": [{
                     "type": "string"
@@ -9,40 +25,24 @@
                     "type": "null"
                 }]
         },
-        "TestDirectCircularClass-1": {
+        "testdirectcircularclass(a)": {
             "type": "object",
             "properties": {
                 "number": {
-                    "$ref": "#/$defs/int-2"
+                    "$ref": "#/$defs/int(b)"
                 },
                 "self": {
                     "$ref": "#"
                 },
                 "text": {
-                    "$ref": "#/$defs/String"
+                    "$ref": "#/$defs/string"
                 }
             }
         },
-        "TestDirectCircularClass-2": {
+        "testdirectcircularclass(b)": {
             "title": "Custom Definition #2 for com.github.victools.jsonschema.generator.SchemaGeneratorCustomDefinitionsTest$TestDirectCircularClass",
             "anyOf": [{
-                    "$ref": "#/$defs/TestDirectCircularClass-1"
-                }, {
-                    "type": "null"
-                }]
-        },
-        "int-1": {
-            "title": "Custom Definition #2 for int",
-            "anyOf": [{
-                    "type": "integer"
-                }, {
-                    "type": "null"
-                }]
-        },
-        "int-2": {
-            "title": "Custom Definition #1 for int",
-            "anyOf": [{
-                    "$ref": "#/$defs/int-1"
+                    "$ref": "#/$defs/testdirectcircularclass(a)"
                 }, {
                     "type": "null"
                 }]
@@ -50,7 +50,7 @@
     },
     "title": "Custom Definition #1 for TestDirectCircularClass",
     "anyOf": [{
-            "$ref": "#/$defs/TestDirectCircularClass-2"
+            "$ref": "#/$defs/testdirectcircularclass(b)"
         }, {
             "type": "null"
         }]
diff --git a/jsonschema-generator/src/test/resources/com/github/victools/jsonschema/generator/multiple-definitions-one-type-DRAFT_6.json b/jsonschema-generator/src/test/resources/com/github/victools/jsonschema/generator/multiple-definitions-one-type-DRAFT_6.json
index 5defbf7..fc7f847 100644
--- a/jsonschema-generator/src/test/resources/com/github/victools/jsonschema/generator/multiple-definitions-one-type-DRAFT_6.json
+++ b/jsonschema-generator/src/test/resources/com/github/victools/jsonschema/generator/multiple-definitions-one-type-DRAFT_6.json
@@ -1,7 +1,23 @@
 {
     "$schema": "http://json-schema.org/draft-06/schema#",
     "definitions": {
-        "String": {
+        "int(a)": {
+            "title": "Custom Definition #2 for int",
+            "anyOf": [{
+                    "type": "integer"
+                }, {
+                    "type": "null"
+                }]
+        },
+        "int(b)": {
+            "title": "Custom Definition #1 for int",
+            "anyOf": [{
+                    "$ref": "#/definitions/int(a)"
+                }, {
+                    "type": "null"
+                }]
+        },
+        "string": {
             "title": "Custom Definition #1 for String",
             "anyOf": [{
                     "type": "string"
@@ -9,40 +25,24 @@
                     "type": "null"
                 }]
         },
-        "TestDirectCircularClass-1": {
+        "testdirectcircularclass(a)": {
             "type": "object",
             "properties": {
                 "number": {
-                    "$ref": "#/definitions/int-2"
+                    "$ref": "#/definitions/int(b)"
                 },
                 "self": {
                     "$ref": "#"
                 },
                 "text": {
-                    "$ref": "#/definitions/String"
+                    "$ref": "#/definitions/string"
                 }
             }
         },
-        "TestDirectCircularClass-2": {
+        "testdirectcircularclass(b)": {
             "title": "Custom Definition #2 for com.github.victools.jsonschema.generator.SchemaGeneratorCustomDefinitionsTest$TestDirectCircularClass",
             "anyOf": [{
-                    "$ref": "#/definitions/TestDirectCircularClass-1"
-                }, {
-                    "type": "null"
-                }]
-        },
-        "int-1": {
-            "title": "Custom Definition #2 for int",
-            "anyOf": [{
-                    "type": "integer"
-                }, {
-                    "type": "null"
-                }]
-        },
-        "int-2": {
-            "title": "Custom Definition #1 for int",
-            "anyOf": [{
-                    "$ref": "#/definitions/int-1"
+                    "$ref": "#/definitions/testdirectcircularclass(a)"
                 }, {
                     "type": "null"
                 }]
@@ -50,7 +50,7 @@
     },
     "title": "Custom Definition #1 for TestDirectCircularClass",
     "anyOf": [{
-            "$ref": "#/definitions/TestDirectCircularClass-2"
+            "$ref": "#/definitions/testdirectcircularclass(b)"
         }, {
             "type": "null"
         }]
diff --git a/jsonschema-generator/src/test/resources/com/github/victools/jsonschema/generator/multiple-definitions-one-type-DRAFT_7.json b/jsonschema-generator/src/test/resources/com/github/victools/jsonschema/generator/multiple-definitions-one-type-DRAFT_7.json
index 9101af1..4ea7299 100644
--- a/jsonschema-generator/src/test/resources/com/github/victools/jsonschema/generator/multiple-definitions-one-type-DRAFT_7.json
+++ b/jsonschema-generator/src/test/resources/com/github/victools/jsonschema/generator/multiple-definitions-one-type-DRAFT_7.json
@@ -1,7 +1,23 @@
 {
     "$schema": "http://json-schema.org/draft-07/schema#",
     "definitions": {
-        "String": {
+        "int(a)": {
+            "title": "Custom Definition #2 for int",
+            "anyOf": [{
+                    "type": "integer"
+                }, {
+                    "type": "null"
+                }]
+        },
+        "int(b)": {
+            "title": "Custom Definition #1 for int",
+            "anyOf": [{
+                    "$ref": "#/definitions/int(a)"
+                }, {
+                    "type": "null"
+                }]
+        },
+        "string": {
             "title": "Custom Definition #1 for String",
             "anyOf": [{
                     "type": "string"
@@ -9,40 +25,24 @@
                     "type": "null"
                 }]
         },
-        "TestDirectCircularClass-1": {
+        "testdirectcircularclass(a)": {
             "type": "object",
             "properties": {
                 "number": {
-                    "$ref": "#/definitions/int-2"
+                    "$ref": "#/definitions/int(b)"
                 },
                 "self": {
                     "$ref": "#"
                 },
                 "text": {
-                    "$ref": "#/definitions/String"
+                    "$ref": "#/definitions/string"
                 }
             }
         },
-        "TestDirectCircularClass-2": {
+        "testdirectcircularclass(b)": {
             "title": "Custom Definition #2 for com.github.victools.jsonschema.generator.SchemaGeneratorCustomDefinitionsTest$TestDirectCircularClass",
             "anyOf": [{
-                    "$ref": "#/definitions/TestDirectCircularClass-1"
-                }, {
-                    "type": "null"
-                }]
-        },
-        "int-1": {
-            "title": "Custom Definition #2 for int",
-            "anyOf": [{
-                    "type": "integer"
-                }, {
-                    "type": "null"
-                }]
-        },
-        "int-2": {
-            "title": "Custom Definition #1 for int",
-            "anyOf": [{
-                    "$ref": "#/definitions/int-1"
+                    "$ref": "#/definitions/testdirectcircularclass(a)"
                 }, {
                     "type": "null"
                 }]
@@ -50,7 +50,7 @@
     },
     "title": "Custom Definition #1 for TestDirectCircularClass",
     "anyOf": [{
-            "$ref": "#/definitions/TestDirectCircularClass-2"
+            "$ref": "#/definitions/testdirectcircularclass(b)"
         }, {
             "type": "null"
         }]