Repository: victools/jsonschema-generator
Pull request #12 (2019-10-25 18:58:50)

Upgrade Jackson dependency to 2.10
Adjust handling of constant values to compensate for changed jackson behaviour.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c584bf4..160bc98 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ## Unreleased
 ### Fixed
 - Increase dependency version for jackson-databind (and jackson-core) to resolve security alerts.
+- Avoid unnecessary quotes when representing constant string values (due to changed jackson behaviour)
 
 ## [3.2.0] – 2019-09-01
 ### Added
diff --git a/pom.xml b/pom.xml
index 57049d9..80a37b3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
 
     <groupId>com.github.victools</groupId>
     <artifactId>jsonschema-generator</artifactId>
-    <version>3.2.1-SNAPSHOT</version>
+    <version>3.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <licenses>
@@ -69,7 +69,7 @@
         <maven.compiler.target>1.8</maven.compiler.target>
 
         <version.classmate>1.5.0</version.classmate>
-        <version.jackson>2.9.10</version.jackson>
+        <version.jackson>2.10.0</version.jackson>
         <version.jsonassert>1.5.0</version.jsonassert>
         <version.junit>4.12</version.junit>
         <version.junitparams>1.1.1</version.junitparams>
diff --git a/src/main/java/com/github/victools/jsonschema/generator/impl/AttributeCollector.java b/src/main/java/com/github/victools/jsonschema/generator/impl/AttributeCollector.java
index 21bd944..64811fe 100644
--- a/src/main/java/com/github/victools/jsonschema/generator/impl/AttributeCollector.java
+++ b/src/main/java/com/github/victools/jsonschema/generator/impl/AttributeCollector.java
@@ -181,16 +181,26 @@ public class AttributeCollector {
      */
     public AttributeCollector setEnum(ObjectNode node, Collection<?> enumValues) {
         if (enumValues != null) {
-            List<String> valuesAsString = enumValues.stream()
+            List<Object> values = enumValues.stream()
                     .filter(this::isSupportedEnumValue)
-                    .map(this::convertObjectToString)
+                    .filter(this::canBeConvertedToString)
                     .collect(Collectors.toList());
-            if (valuesAsString.size() == 1) {
-                String singleValue = valuesAsString.get(0);
-                node.putPOJO(SchemaConstants.TAG_CONST, singleValue);
-            } else if (!valuesAsString.isEmpty()) {
+            if (values.size() == 1) {
+                Object singleValue = values.get(0);
+                if (singleValue instanceof String) {
+                    node.put(SchemaConstants.TAG_CONST, (String) singleValue);
+                } else {
+                    node.putPOJO(SchemaConstants.TAG_CONST, singleValue);
+                }
+            } else if (!values.isEmpty()) {
                 ArrayNode array = node.arrayNode();
-                valuesAsString.forEach(array::addPOJO);
+                for (Object singleValue : values) {
+                    if (singleValue instanceof String) {
+                        array.add((String) singleValue);
+                    } else {
+                        array.addPOJO(singleValue);
+                    }
+                }
                 node.set(SchemaConstants.TAG_ENUM, array);
             }
         }
@@ -215,17 +225,17 @@ public class AttributeCollector {
     }
 
     /**
-     * Call {@link ObjectMapper#writeValueAsString(Object)} on the given object – ignoring any occurring {@link JsonProcessingException}.
+     * Call {@link ObjectMapper#writeValueAsString(Object)} on the given object and determining whether any {@link JsonProcessingException} occurs.
      *
      * @param target object to convert
-     * @return converted object
+     * @return whether the underlying ObjectMapper is able to convert the given object without encountering an exception
      */
-    private String convertObjectToString(Object target) {
+    private boolean canBeConvertedToString(Object target) {
         try {
-            return this.objectMapper.writeValueAsString(target);
+            return target == null || this.objectMapper.writeValueAsString(target) != null;
         } catch (JsonProcessingException ex) {
             logger.warn("Failed to convert value to string via ObjectMapper: {}", target, ex);
-            return target == null ? null : ('"' + target.toString() + '"');
+            return false;
         }
     }
 


Test patch:
diff --git a/src/test/java/com/github/victools/jsonschema/generator/AbstractTypeAwareTest.java b/src/test/java/com/github/victools/jsonschema/generator/AbstractTypeAwareTest.java
index 9d4c193..234858b 100644
--- a/src/test/java/com/github/victools/jsonschema/generator/AbstractTypeAwareTest.java
+++ b/src/test/java/com/github/victools/jsonschema/generator/AbstractTypeAwareTest.java
@@ -20,9 +20,6 @@ import com.fasterxml.classmate.ResolvedType;
 import com.fasterxml.classmate.ResolvedTypeWithMembers;
 import com.fasterxml.classmate.members.ResolvedField;
 import com.fasterxml.classmate.members.ResolvedMethod;
-import com.github.victools.jsonschema.generator.FieldScope;
-import com.github.victools.jsonschema.generator.MethodScope;
-import com.github.victools.jsonschema.generator.TypeContext;
 import com.github.victools.jsonschema.generator.impl.TypeContextFactory;
 import java.util.stream.Stream;
 import org.junit.Before;
diff --git a/src/test/java/com/github/victools/jsonschema/generator/impl/module/EnumModuleTest.java b/src/test/java/com/github/victools/jsonschema/generator/impl/module/EnumModuleTest.java
new file mode 100644
index 0000000..b96857d
--- /dev/null
+++ b/src/test/java/com/github/victools/jsonschema/generator/impl/module/EnumModuleTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2019 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.impl.module;
+
+import com.fasterxml.classmate.ResolvedType;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.github.victools.jsonschema.generator.AbstractTypeAwareTest;
+import com.github.victools.jsonschema.generator.CustomDefinition;
+import com.github.victools.jsonschema.generator.CustomDefinitionProvider;
+import com.github.victools.jsonschema.generator.FieldScope;
+import com.github.victools.jsonschema.generator.MethodScope;
+import com.github.victools.jsonschema.generator.OptionPreset;
+import com.github.victools.jsonschema.generator.SchemaConstants;
+import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder;
+import com.github.victools.jsonschema.generator.SchemaGeneratorConfigPart;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+/**
+ * Test for the {@link EnumModule} class.
+ */
+public class EnumModuleTest extends AbstractTypeAwareTest {
+
+    private EnumModule instanceAsStrings;
+    private EnumModule instanceAsObjects;
+    private SchemaGeneratorConfigBuilder builder;
+    private SchemaGeneratorConfigPart<FieldScope> fieldConfigPart;
+    private SchemaGeneratorConfigPart<MethodScope> methodConfigPart;
+
+    public EnumModuleTest() {
+        super(TestEnum.class);
+    }
+
+    @Before
+    public void setUp() {
+        this.instanceAsStrings = EnumModule.asStrings();
+        this.instanceAsObjects = EnumModule.asObjects();
+        this.builder = Mockito.spy(new SchemaGeneratorConfigBuilder(new ObjectMapper(), new OptionPreset()));
+        this.fieldConfigPart = Mockito.spy(new SchemaGeneratorConfigPart<>());
+        this.methodConfigPart = Mockito.spy(new SchemaGeneratorConfigPart<>());
+        Mockito.when(this.builder.forFields()).thenReturn(this.fieldConfigPart);
+        Mockito.when(this.builder.forMethods()).thenReturn(this.methodConfigPart);
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testApplyToConfigBuilder_asStrings() {
+        this.instanceAsStrings.applyToConfigBuilder(this.builder);
+
+        Mockito.verify(this.builder).getObjectMapper();
+        Mockito.verify(this.builder).with(Mockito.any(CustomDefinitionProvider.class));
+        Mockito.verifyNoMoreInteractions(this.builder);
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testApplyToConfigBuilder_asObjects() {
+        this.instanceAsObjects.applyToConfigBuilder(this.builder);
+
+        Mockito.verify(this.builder).forFields();
+        Mockito.verify(this.builder).forMethods();
+        Mockito.verifyNoMoreInteractions(this.builder);
+        Mockito.verify(this.fieldConfigPart).withIgnoreCheck(Mockito.any());
+        Mockito.verifyNoMoreInteractions(this.fieldConfigPart);
+        Mockito.verify(this.methodConfigPart).withIgnoreCheck(Mockito.any());
+        Mockito.verify(this.methodConfigPart).withNullableCheck(Mockito.any());
+        Mockito.verify(this.methodConfigPart).withEnumResolver(Mockito.any());
+        Mockito.verifyNoMoreInteractions(this.methodConfigPart);
+    }
+
+    @Test
+    public void testCustomSchemaDefinition_asStrings() {
+        this.instanceAsStrings.applyToConfigBuilder(this.builder);
+        ArgumentCaptor<CustomDefinitionProvider> captor = ArgumentCaptor.forClass(CustomDefinitionProvider.class);
+        Mockito.verify(this.builder).with(captor.capture());
+
+        ResolvedType testEnumType = this.getContext().resolve(TestEnum.class);
+        CustomDefinition schemaDefinition = captor.getValue().provideCustomSchemaDefinition(testEnumType, this.getContext());
+        Assert.assertFalse(schemaDefinition.isMeantToBeInline());
+        ObjectNode node = schemaDefinition.getValue();
+        Assert.assertEquals(2, node.size());
+
+        JsonNode typeNode = node.get(SchemaConstants.TAG_TYPE);
+        Assert.assertEquals(JsonNodeType.STRING, typeNode.getNodeType());
+        Assert.assertEquals(SchemaConstants.TAG_TYPE_STRING, typeNode.textValue());
+
+        JsonNode enumNode = node.get(SchemaConstants.TAG_ENUM);
+        Assert.assertEquals(JsonNodeType.ARRAY, enumNode.getNodeType());
+        Assert.assertEquals(3, ((ArrayNode) enumNode).size());
+        Assert.assertEquals(JsonNodeType.STRING, enumNode.get(0).getNodeType());
+        Assert.assertEquals("VALUE1", enumNode.get(0).textValue());
+        Assert.assertEquals(JsonNodeType.STRING, enumNode.get(1).getNodeType());
+        Assert.assertEquals("VALUE2", enumNode.get(1).textValue());
+        Assert.assertEquals(JsonNodeType.STRING, enumNode.get(2).getNodeType());
+        Assert.assertEquals("VALUE3", enumNode.get(2).textValue());
+    }
+
+    private static enum TestEnum {
+        VALUE1, VALUE2, VALUE3;
+    }
+}