diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/util/ModelDeserializer.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/util/ModelDeserializer.java index d2f232e4be..25a0e2b09c 100644 --- a/modules/swagger-core/src/main/java/io/swagger/v3/core/util/ModelDeserializer.java +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/util/ModelDeserializer.java @@ -12,6 +12,7 @@ import io.swagger.v3.oas.models.media.BooleanSchema; import io.swagger.v3.oas.models.media.ComposedSchema; import io.swagger.v3.oas.models.media.DateSchema; +import io.swagger.v3.oas.models.media.DateTimeLocalSchema; import io.swagger.v3.oas.models.media.DateTimeSchema; import io.swagger.v3.oas.models.media.EmailSchema; import io.swagger.v3.oas.models.media.IntegerSchema; @@ -85,6 +86,8 @@ public Schema deserialize(JsonParser jp, DeserializationContext ctxt) schema = Json.mapper().convertValue(node, DateSchema.class); } else if ("date-time".equals(format)) { schema = Json.mapper().convertValue(node, DateTimeSchema.class); + } else if ("date-time-local".equals(format)) { + schema = Json.mapper().convertValue(node, DateTimeLocalSchema.class); } else if ("email".equals(format)) { schema = Json.mapper().convertValue(node, EmailSchema.class); } else if ("password".equals(format)) { diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/util/PrimitiveType.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/util/PrimitiveType.java index 52e8aade4b..7ee366dda2 100644 --- a/modules/swagger-core/src/main/java/io/swagger/v3/core/util/PrimitiveType.java +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/util/PrimitiveType.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.models.media.BooleanSchema; import io.swagger.v3.oas.models.media.ByteArraySchema; import io.swagger.v3.oas.models.media.DateSchema; +import io.swagger.v3.oas.models.media.DateTimeLocalSchema; import io.swagger.v3.oas.models.media.DateTimeSchema; import io.swagger.v3.oas.models.media.FileSchema; import io.swagger.v3.oas.models.media.IntegerSchema; @@ -221,6 +222,16 @@ public Schema createProperty31() { return new JsonSchema().typesItem("string").format("partial-time"); } }, + DATE_TIME_LOCAL(java.time.LocalDateTime.class, "date-time-local") { + @Override + public Schema createProperty() { + return new DateTimeLocalSchema(); + } + @Override + public Schema createProperty31() { + return new JsonSchema().typesItem("string").format("date-time-local"); + } + }, FILE(java.io.File.class, "file") { @Override public FileSchema createProperty() { @@ -316,6 +327,7 @@ public Schema createProperty31() { dms.put("string_date", "date"); dms.put("string_date-time", "date-time"); dms.put("string_partial-time", "partial-time"); + dms.put("string_date-time-local", "date-time-local"); dms.put("string_password", "password"); dms.put("boolean_", "boolean"); dms.put("object_", "object"); @@ -353,14 +365,13 @@ public Schema createProperty31() { final Map externalClasses = new HashMap<>(); addKeys(externalClasses, DATE, "org.joda.time.LocalDate", "java.time.LocalDate"); addKeys(externalClasses, DATE_TIME, - "java.time.LocalDateTime", "java.time.ZonedDateTime", "java.time.OffsetDateTime", "javax.xml.datatype.XMLGregorianCalendar", - "org.joda.time.LocalDateTime", "org.joda.time.ReadableDateTime", "org.joda.time.DateTime", "java.time.Instant"); + addKeys(externalClasses, DATE_TIME_LOCAL, "java.time.LocalDateTime", "org.joda.time.LocalDateTime"); EXTERNAL_CLASSES = Collections.unmodifiableMap(externalClasses); final Map names = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); diff --git a/modules/swagger-core/src/test/java/io/swagger/v3/core/deserialization/JsonDeserializationTest.java b/modules/swagger-core/src/test/java/io/swagger/v3/core/deserialization/JsonDeserializationTest.java index 3b38d0a97b..b86e25e457 100644 --- a/modules/swagger-core/src/test/java/io/swagger/v3/core/deserialization/JsonDeserializationTest.java +++ b/modules/swagger-core/src/test/java/io/swagger/v3/core/deserialization/JsonDeserializationTest.java @@ -273,6 +273,7 @@ public void deserializeDateExample() throws IOException { Map props = swagger.getComponents().getSchemas().get("MyModel").getProperties(); assertTrue(Yaml.pretty().writeValueAsString(props.get("date")).contains("example: 2019-08-05")); assertTrue(Yaml.pretty().writeValueAsString(props.get("dateTime")).contains("example: 2019-08-05T12:34:56Z")); + assertTrue(Yaml.pretty().writeValueAsString(props.get("dateTimeLocal")).contains("example: 2019-08-05T12:34:56")); } diff --git a/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/DateTimeLocalTest.java b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/DateTimeLocalTest.java new file mode 100644 index 0000000000..2ebebf2753 --- /dev/null +++ b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/DateTimeLocalTest.java @@ -0,0 +1,38 @@ +package io.swagger.v3.core.resolving; + +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverterContextImpl; +import io.swagger.v3.core.jackson.ModelResolver; +import io.swagger.v3.core.matchers.SerializationMatchers; +import org.testng.annotations.Test; + +import java.time.LocalDateTime; + +public class DateTimeLocalTest extends SwaggerTestBase { + @Test + public void testLocalDateTimeDefaultMapping() { + final ModelResolver modelResolver = new ModelResolver(mapper()); + ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver); + + context.resolve(new AnnotatedType(TestObjectDateTimeLocal.class)); + + SerializationMatchers.assertEqualsToYaml(context.getDefinedModels(), "TestObjectDateTimeLocal:\n" + + " type: object\n" + + " properties:\n" + + " localDateTime:\n" + + " type: string\n" + + " format: date-time-local"); + } + + static class TestObjectDateTimeLocal { + private LocalDateTime localDateTime; + + public LocalDateTime getLocalDateTime() { + return localDateTime; + } + + public void setLocalDateTime(LocalDateTime localDateTime) { + this.localDateTime = localDateTime; + } + } +} diff --git a/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket2992Test.java b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket2992Test.java index 75eebf5df4..3fbe7c47e2 100644 --- a/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket2992Test.java +++ b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket2992Test.java @@ -49,13 +49,13 @@ public void testLocalTime() throws Exception { " $ref: \"#/components/schemas/LocalTime\"\n" + " d:\n" + " type: string\n" + - " format: date-time\n" + + " format: date-time-local\n" + " e:\n" + " type: string\n" + - " format: date-time\n" + + " format: date-time-local\n" + " f:\n" + " type: string\n" + - " format: date-time"); + " format: date-time-local"); PrimitiveType.enablePartialTime(); context = new ModelConverterContextImpl(modelResolver); @@ -79,13 +79,13 @@ public void testLocalTime() throws Exception { " format: partial-time\n" + " d:\n" + " type: string\n" + - " format: date-time\n" + + " format: date-time-local\n" + " e:\n" + " type: string\n" + - " format: date-time\n" + + " format: date-time-local\n" + " f:\n" + " type: string\n" + - " format: date-time"); + " format: date-time-local"); } } diff --git a/modules/swagger-core/src/test/java/io/swagger/v3/core/serialization/properties/PropertySerializationTest.java b/modules/swagger-core/src/test/java/io/swagger/v3/core/serialization/properties/PropertySerializationTest.java index 3cd5ea4022..6153f1003f 100644 --- a/modules/swagger-core/src/test/java/io/swagger/v3/core/serialization/properties/PropertySerializationTest.java +++ b/modules/swagger-core/src/test/java/io/swagger/v3/core/serialization/properties/PropertySerializationTest.java @@ -6,6 +6,7 @@ import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.BooleanSchema; import io.swagger.v3.oas.models.media.DateSchema; +import io.swagger.v3.oas.models.media.DateTimeLocalSchema; import io.swagger.v3.oas.models.media.DateTimeSchema; import io.swagger.v3.oas.models.media.IntegerSchema; import io.swagger.v3.oas.models.media.MapSchema; @@ -81,6 +82,23 @@ public void deserializeDateTimeProperty() throws IOException { JsonAssert.assertJsonEquals(m, m.writeValueAsString(p), json); } + @Test(description = "it should serialize a DateTimeLocalProperty") + public void serializeDateTimeLocalProperty() throws IOException { + final DateTimeLocalSchema p = new DateTimeLocalSchema(); + final String json = "{\"type\":\"string\",\"format\":\"date-time-local\"}"; + JsonAssert.assertJsonEquals(m, m.writeValueAsString(p), json); + } + + @Test(description = "it should deserialize a DateTimeLocalProperty") + public void deserializeDateTimeLocalProperty() throws IOException { + final String json = "{\"type\":\"string\",\"format\":\"date-time-local\"}"; + final Schema p = m.readValue(json, Schema.class); + assertEquals(p.getType(), "string"); + assertEquals(p.getFormat(), "date-time-local"); + assertEquals(p.getClass(), DateTimeLocalSchema.class); + JsonAssert.assertJsonEquals(m, m.writeValueAsString(p), json); + } + @Test(description = "it should serialize a DoubleProperty") public void serializeDoubleProperty() throws IOException { final NumberSchema p = new NumberSchema() diff --git a/modules/swagger-core/src/test/resources/specFiles/swos-126.yaml b/modules/swagger-core/src/test/resources/specFiles/swos-126.yaml index 3210d84301..ffd1d2fd3c 100644 --- a/modules/swagger-core/src/test/resources/specFiles/swos-126.yaml +++ b/modules/swagger-core/src/test/resources/specFiles/swos-126.yaml @@ -16,4 +16,8 @@ components: dateTime: type: string format: date-time - example: '2019-08-05T12:34:56Z' \ No newline at end of file + example: '2019-08-05T12:34:56Z' + dateTimeLocal: + type: string + format: date-time-local + example: '2019-08-05T12:34:56' \ No newline at end of file diff --git a/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/media/DateTimeLocalSchema.java b/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/media/DateTimeLocalSchema.java new file mode 100644 index 0000000000..15347d3678 --- /dev/null +++ b/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/media/DateTimeLocalSchema.java @@ -0,0 +1,85 @@ +package io.swagger.v3.oas.models.media; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; + +/** + * DateTimeLocalSchema + *

+ * Schema for date-time-local format as defined in the Format Registry + * date-time-local + */ +public class DateTimeLocalSchema extends Schema { + + public DateTimeLocalSchema() { + super("string", "date-time-local"); + } + + @Override + public DateTimeLocalSchema type(String type) { + super.setType(type); + return this; + } + + @Override + public DateTimeLocalSchema format(String format) { + super.setFormat(format); + return this; + } + + public DateTimeLocalSchema _default(LocalDateTime _default) { + super.setDefault(_default); + return this; + } + + @Override + protected LocalDateTime cast(Object value) { + if (value != null) { + try { + if (value instanceof String) { + return LocalDateTime.parse((String) value); + } else if (value instanceof LocalDateTime) { + return (LocalDateTime) value; + } + } catch (Exception e) { + } + } + return null; + } + + public DateTimeLocalSchema _enum(List _enum) { + super.setEnum(_enum); + return this; + } + + public DateTimeLocalSchema addEnumItem(LocalDateTime _enumItem) { + super.addEnumItemObject(_enumItem); + return this; + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return super.equals(o); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class DateTimeLocalSchema {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append("}"); + return sb.toString(); + } +}