Commit 09379e6f authored by Morten Kjetland's avatar Morten Kjetland
Browse files

Fixes #19 - Supports custom Class-to-format-Mapping

parent 9110899d
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ Current version: *1.0.10*
* Works well with Generated GUI's using [https://github.com/jdorn/json-editor](https://github.com/jdorn/json-editor)
  - (Must be configured to use this mode)
  - Special handling of Option-/Optional-properties using oneOf.
* Supports custom Class-to-format-Mapping
    

**Benefits**

@@ -86,6 +88,18 @@ This is how to generate jsonSchema used for generating HTML5 GUI using [json-edi
    val jsonSchemaAsString:String = objectMapper.writeValueAsString(jsonSchema)
```

This is how to generate jsonSchema using custom type-to-format-mapping using Scala:

```scala
    val objectMapper = new ObjectMapper
    val config:JsonSchemaConfig = JsonSchemaConfig.vanillaJsonSchemaDraft4.copy(
      customType2FormatMapping = Map( "java.time.OffsetDateTime" -> "date-time-ABC-Special" )
    )
    val jsonSchemaGenerator = new JsonSchemaGenerator(objectMapper, config = config)
    val jsonSchema:JsonNode = jsonSchemaGenerator.generateJsonSchema(classOf[YourPOJO])
    
    val jsonSchemaAsString:String = objectMapper.writeValueAsString(jsonSchema)
```

**Note about Scala and Option[Int]**:

@@ -116,6 +130,11 @@ Code - Using Java
    // If using JsonSchema to generate HTML5 GUI:
    // JsonSchemaGenerator html5 = new JsonSchemaGenerator(objectMapper, JsonSchemaConfig.html5EnabledSchema() );
    
    // If you want to confioure it manually:
    // JsonSchemaConfig config = JsonSchemaConfig.create(...);
    // JsonSchemaGenerator generator = new JsonSchemaGenerator(objectMapper, config);
               
    
    JsonNode jsonSchema = jsonSchemaGenerator.generateJsonSchema(YourPOJO.class);
    
    String jsonSchemaAsString = objectMapper.writeValueAsString(jsonSchema);
+1 −0
Original line number Diff line number Diff line
sbt.version=0.13.13
 No newline at end of file
+55 −11
Original line number Diff line number Diff line
@@ -30,9 +30,9 @@ object JsonSchemaConfig {
    usePropertyOrdering = false,
    hidePolymorphismTypeProperty = false,
    disableWarnings = false,
    useImprovedDateFormatMapping = false,
    useMinLengthForNotNull = false,
    useTypeIdForDefinitionName = false
    useTypeIdForDefinitionName = false,
    customType2FormatMapping = Map()
  )

  /**
@@ -49,10 +49,46 @@ object JsonSchemaConfig {
    usePropertyOrdering = true,
    hidePolymorphismTypeProperty = true,
    disableWarnings = false,
    useImprovedDateFormatMapping = true,
    useMinLengthForNotNull = true,
    useTypeIdForDefinitionName = false
    useTypeIdForDefinitionName = false,
    customType2FormatMapping = Map[String,String](
      // Java7 dates
      "java.time.LocalDateTime" -> "datetime-local",
      "java.time.OffsetDateTime" -> "datetime",
      "java.time.LocalDate" -> "date",

      // Joda-dates
      "org.joda.time.LocalDate" -> "date"
    )
  )

  // Java-API
  def create(
              autoGenerateTitleForProperties:Boolean,
              defaultArrayFormat:Optional[String],
              useOneOfForOption:Boolean,
              usePropertyOrdering:Boolean,
              hidePolymorphismTypeProperty:Boolean,
              disableWarnings:Boolean,
              useMinLengthForNotNull:Boolean,
              useTypeIdForDefinitionName:Boolean,
              customType2FormatMapping:java.util.Map[String, String]
            ):JsonSchemaConfig = {

    import scala.collection.JavaConverters._

    JsonSchemaConfig(
      autoGenerateTitleForProperties,
      Option(defaultArrayFormat.orElse(null)),
      useOneOfForOption,
      usePropertyOrdering,
      hidePolymorphismTypeProperty,
      disableWarnings,
      useMinLengthForNotNull,
      useTypeIdForDefinitionName,
      customType2FormatMapping.asScala.toMap
    )
  }

}

@@ -64,9 +100,9 @@ case class JsonSchemaConfig
  usePropertyOrdering:Boolean,
  hidePolymorphismTypeProperty:Boolean,
  disableWarnings:Boolean,
  useImprovedDateFormatMapping:Boolean,
  useMinLengthForNotNull:Boolean,
  useTypeIdForDefinitionName:Boolean
  useTypeIdForDefinitionName:Boolean,
  customType2FormatMapping:Map[String, String]
)


@@ -520,7 +556,7 @@ class JsonSchemaGenerator

            // If class is annotated with JsonSchemaFormat, we should add it
            val ac = AnnotatedClass.construct(_type, objectMapper.getDeserializationConfig())
            Option(ac.getAnnotations.get(classOf[JsonSchemaFormat])).map(_.value()).foreach {
            resolvePropertyFormat(_type, objectMapper).foreach {
              format =>
                setFormat(thisObjectNode, format)
            }
@@ -756,15 +792,23 @@ class JsonSchemaGenerator
    s.substring(0,1).toUpperCase() + s.substring(1)
  }

  def resolvePropertyFormat(_type: JavaType, objectMapper:ObjectMapper):Option[String] = {
    val ac = AnnotatedClass.construct(_type, objectMapper.getDeserializationConfig())
    resolvePropertyFormat(Option(ac.getAnnotation(classOf[JsonSchemaFormat])), _type.getRawClass.getName)
  }

  def resolvePropertyFormat(prop: BeanProperty):Option[String] = {
    // Prefer format specified in annotation
    Option(prop.getAnnotation(classOf[JsonSchemaFormat])).map {
    resolvePropertyFormat(Option(prop.getAnnotation(classOf[JsonSchemaFormat])), prop.getType.getRawClass.getName)
  }

  def resolvePropertyFormat(jsonSchemaFormatAnnotation:Option[JsonSchemaFormat], rawClassName:String):Option[String] = {
    // Prefer format specified in annotation
    jsonSchemaFormatAnnotation.map {
      jsonSchemaFormat =>
        jsonSchemaFormat.value()
    }.orElse {
      if( config.useImprovedDateFormatMapping ) {
        dateFormatMapping.get(prop.getType.getRawClass.getName)
      } else None
      config.customType2FormatMapping.get(rawClassName)
    }
  }

+12 −0
Original line number Diff line number Diff line
@@ -4,6 +4,11 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import scala.None;
import scala.Option;

import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class UseItFromJavaTest {

    static class MyJavaPojo {
@@ -17,6 +22,13 @@ public class UseItFromJavaTest {
        // TODO - This is not very beautiful from Java - Need to improve Java API
        g1.generateJsonSchema(MyJavaPojo.class);
        g1.generateJsonSchema(MyJavaPojo.class, "My title", "My description");

        // Create custom JsonSchemaConfig from java
        Map<String,String> customMapping = new HashMap<>();
        customMapping.put(OffsetDateTime.class.getName(), "date-time");
        JsonSchemaConfig config = JsonSchemaConfig.create(
                true, Optional.of("A"), true, true, true, true, true, true, customMapping);
        JsonSchemaGenerator g2 = new JsonSchemaGenerator(objectMapper, config);
    }

}
+1 −11
Original line number Diff line number Diff line
@@ -55,17 +55,7 @@ class JsonSchemaGeneratorTest extends FunSuite with Matchers {
  val jsonSchemaGeneratorScala = new JsonSchemaGenerator(_objectMapperScala, debug = true)
  val jsonSchemaGeneratorScalaHTML5 = new JsonSchemaGenerator(_objectMapperScala, debug = true, config = JsonSchemaConfig.html5EnabledSchema)

  val vanillaJsonSchemaDraft4WithIds = JsonSchemaConfig(
    autoGenerateTitleForProperties = true,
    defaultArrayFormat = Some("table"),
    useOneOfForOption = true,
    usePropertyOrdering = true,
    hidePolymorphismTypeProperty = true,
    disableWarnings = false,
    useImprovedDateFormatMapping = true,
    useMinLengthForNotNull = true,
    useTypeIdForDefinitionName = true
  )
  val vanillaJsonSchemaDraft4WithIds = JsonSchemaConfig.html5EnabledSchema.copy(useTypeIdForDefinitionName = true)
  val jsonSchemaGeneratorWithIds = new JsonSchemaGenerator(_objectMapperScala, debug = true, vanillaJsonSchemaDraft4WithIds)

  val testData = new TestData{}