Skip to content

Commit

Permalink
add bean validation to Kotlin
Browse files Browse the repository at this point in the history
  • Loading branch information
Richard Easterling authored and Richard Easterling committed Dec 12, 2017
1 parent f5a9457 commit 3fa7289
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 43 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.gradle
**/build/
**/out/
out/

# Ignore Gradle GUI config
gradle-app.setting
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# schema-gen-examples
schema-gen examples and tests.
[schema-gen](https://github.com/reaster/schema-gen) examples and tests.
6 changes: 4 additions & 2 deletions java-gpx/src/main/java-gen/com/topografix/gpx/Bounds.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.Size;

public class Bounds
{
@JacksonXmlProperty(isAttribute = true)
@DecimalMin("-90.0")
@DecimalMax("90.0")
//@DecimalMin("-90.0")
//@DecimalMax("90.0")
@Size(min=-90, max=90)
private double minlat;
@JacksonXmlProperty(isAttribute = true)
@DecimalMin("-180.0")
Expand Down
7 changes: 2 additions & 5 deletions kotlin-gpx/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ repositories {
mavenCentral()
}

//sourceCompatibility = 1.8
//targetCompatibility = 1.8

compileKotlin {
kotlinOptions {
jvmTarget = '1.8'
Expand All @@ -82,8 +79,8 @@ dependencies {
compile 'com.fasterxml.jackson.module:jackson-modules-java8:2.9.2'
compile 'com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.2'
compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.0'
//compile 'org.hibernate.validator:hibernate-validator:6.0.2.Final'
//compile 'org.glassfish:javax.el:3.0.1-b08'
compile 'org.hibernate.validator:hibernate-validator:6.0.2.Final'
compile 'org.glassfish:javax.el:3.0.1-b08'
testCompile 'junit:junit:4.11'
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
}
71 changes: 38 additions & 33 deletions kotlin-gpx/src/main/kotlin-gen/Gpx.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import com.fasterxml.jackson.annotation.JsonValue
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText
import javax.validation.Valid
import javax.validation.constraints.DecimalMax
import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min

enum class FixTypeEnum(@JsonValue val value:String)
{
Expand All @@ -22,51 +27,51 @@ enum class FixTypeEnum(@JsonValue val value:String)
data class Gpx(
@JacksonXmlProperty(localName="version",isAttribute = true) val version:String = "1.1",
@JacksonXmlProperty(localName="creator",isAttribute = true) var creator:String = "",
var metadata:Metadata? = null,
@JacksonXmlElementWrapper(localName="wpts", useWrapping=false) @JacksonXmlProperty(localName="wpt") var wpts:MutableList<Wpt>? = mutableListOf(),
@JacksonXmlElementWrapper(localName="rtes", useWrapping=false) @JacksonXmlProperty(localName="rte") var rtes:MutableList<Rte>? = mutableListOf(),
@JacksonXmlElementWrapper(localName="trks", useWrapping=false) @JacksonXmlProperty(localName="trk") var trks:MutableList<Trk>? = mutableListOf(),
var extensions:Extensions? = null
@field:Valid var metadata:Metadata? = null,
@JacksonXmlElementWrapper(localName="wpts", useWrapping=false) @JacksonXmlProperty(localName="wpt") @field:Valid var wpts:MutableList<Wpt>? = mutableListOf(),
@JacksonXmlElementWrapper(localName="rtes", useWrapping=false) @JacksonXmlProperty(localName="rte") @field:Valid var rtes:MutableList<Rte>? = mutableListOf(),
@JacksonXmlElementWrapper(localName="trks", useWrapping=false) @JacksonXmlProperty(localName="trk") @field:Valid var trks:MutableList<Trk>? = mutableListOf(),
@field:Valid var extensions:Extensions? = null
)
{
}

data class Metadata(
var name:String? = null,
var desc:String? = null,
var author:Person? = null,
var copyright:Copyright? = null,
@JacksonXmlElementWrapper(localName="links", useWrapping=false) @JacksonXmlProperty(localName="link") var links:MutableList<Link>? = mutableListOf(),
@field:Valid var author:Person? = null,
@field:Valid var copyright:Copyright? = null,
@JacksonXmlElementWrapper(localName="links", useWrapping=false) @JacksonXmlProperty(localName="link") @field:Valid var links:MutableList<Link>? = mutableListOf(),
var time:java.time.LocalDateTime? = java.time.LocalDateTime.now(),
var keywords:String? = null,
var bounds:Bounds? = null,
var extensions:Extensions? = null
@field:Valid var bounds:Bounds? = null,
@field:Valid var extensions:Extensions? = null
)
{
}

data class Wpt(
@JacksonXmlProperty(localName="lat",isAttribute = true) var lat:Double = 0.0,
@JacksonXmlProperty(localName="lon",isAttribute = true) var lon:Double = 0.0,
@JacksonXmlProperty(localName="lat",isAttribute = true) @get:DecimalMin("-90.0") @get:DecimalMax("90.0") var lat:Double = 0.0,
@JacksonXmlProperty(localName="lon",isAttribute = true) @get:DecimalMin("-180.0") @get:DecimalMax("180.0") var lon:Double = 0.0,
var ele:Double? = 0.0,
var time:java.time.LocalDateTime? = java.time.LocalDateTime.now(),
var magvar:Double? = 0.0,
@get:DecimalMin("0.0") @get:DecimalMax("360.0") var magvar:Double? = 0.0,
var geoidheight:Double? = 0.0,
var name:String? = null,
var cmt:String? = null,
var desc:String? = null,
var src:String? = null,
@JacksonXmlElementWrapper(localName="links", useWrapping=false) @JacksonXmlProperty(localName="link") var links:MutableList<Link>? = mutableListOf(),
@JacksonXmlElementWrapper(localName="links", useWrapping=false) @JacksonXmlProperty(localName="link") @field:Valid var links:MutableList<Link>? = mutableListOf(),
var sym:String? = null,
var type:String? = null,
var fix:FixTypeEnum? = null,
@field:Valid var fix:FixTypeEnum? = null,
var sat:Int? = 0,
var hdop:Double? = 0.0,
var vdop:Double? = 0.0,
var pdop:Double? = 0.0,
var ageofdgpsdata:Double? = 0.0,
var dgpsid:Int? = 0,
var extensions:Extensions? = null
@get:Min(0) @get:Max(1023) var dgpsid:Int? = 0,
@field:Valid var extensions:Extensions? = null
)
{
}
Expand All @@ -76,11 +81,11 @@ data class Rte(
var cmt:String? = null,
var desc:String? = null,
var src:String? = null,
@JacksonXmlElementWrapper(localName="links", useWrapping=false) @JacksonXmlProperty(localName="link") var links:MutableList<Link>? = mutableListOf(),
@JacksonXmlElementWrapper(localName="links", useWrapping=false) @JacksonXmlProperty(localName="link") @field:Valid var links:MutableList<Link>? = mutableListOf(),
var number:Int? = 0,
var type:String? = null,
var extensions:Extensions? = null,
@JacksonXmlElementWrapper(localName="rtepts", useWrapping=false) @JacksonXmlProperty(localName="rtept") var rtepts:MutableList<Wpt>? = mutableListOf()
@field:Valid var extensions:Extensions? = null,
@JacksonXmlElementWrapper(localName="rtepts", useWrapping=false) @JacksonXmlProperty(localName="rtept") @field:Valid var rtepts:MutableList<Wpt>? = mutableListOf()
)
{
}
Expand All @@ -90,18 +95,18 @@ data class Trk(
var cmt:String? = null,
var desc:String? = null,
var src:String? = null,
@JacksonXmlElementWrapper(localName="links", useWrapping=false) @JacksonXmlProperty(localName="link") var links:MutableList<Link>? = mutableListOf(),
@JacksonXmlElementWrapper(localName="links", useWrapping=false) @JacksonXmlProperty(localName="link") @field:Valid var links:MutableList<Link>? = mutableListOf(),
var number:Int? = 0,
var type:String? = null,
var extensions:Extensions? = null,
@JacksonXmlElementWrapper(localName="trksegs", useWrapping=false) @JacksonXmlProperty(localName="trkseg") var trksegs:MutableList<Trkseg>? = mutableListOf()
@field:Valid var extensions:Extensions? = null,
@JacksonXmlElementWrapper(localName="trksegs", useWrapping=false) @JacksonXmlProperty(localName="trkseg") @field:Valid var trksegs:MutableList<Trkseg>? = mutableListOf()
)
{
}

data class Trkseg(
@JacksonXmlElementWrapper(localName="trkpts", useWrapping=false) @JacksonXmlProperty(localName="trkpt") var trkpts:MutableList<Wpt>? = mutableListOf(),
var extensions:Extensions? = null
@JacksonXmlElementWrapper(localName="trkpts", useWrapping=false) @JacksonXmlProperty(localName="trkpt") @field:Valid var trkpts:MutableList<Wpt>? = mutableListOf(),
@field:Valid var extensions:Extensions? = null
)
{
}
Expand Down Expand Up @@ -131,26 +136,26 @@ data class Email(

data class Person(
var name:String? = null,
var email:Email? = null,
var link:Link? = null
@field:Valid var email:Email? = null,
@field:Valid var link:Link? = null
)
{
}

data class Pt(
@JacksonXmlProperty(localName="lat",isAttribute = true) var lat:Double = 0.0,
@JacksonXmlProperty(localName="lon",isAttribute = true) var lon:Double = 0.0,
@JacksonXmlProperty(localName="lat",isAttribute = true) @get:DecimalMin("-90.0") @get:DecimalMax("90.0") var lat:Double = 0.0,
@JacksonXmlProperty(localName="lon",isAttribute = true) @get:DecimalMin("-180.0") @get:DecimalMax("180.0") var lon:Double = 0.0,
var ele:Double? = 0.0,
var time:java.time.LocalDateTime? = java.time.LocalDateTime.now()
)
{
}

data class Bounds(
@JacksonXmlProperty(localName="minlat",isAttribute = true) var minlat:Double = 0.0,
@JacksonXmlProperty(localName="minlon",isAttribute = true) var minlon:Double = 0.0,
@JacksonXmlProperty(localName="maxlat",isAttribute = true) var maxlat:Double = 0.0,
@JacksonXmlProperty(localName="maxlon",isAttribute = true) var maxlon:Double = 0.0
@JacksonXmlProperty(localName="minlat",isAttribute = true) @get:DecimalMin("-90.0") @get:DecimalMax("90.0") var minlat:Double = 0.0,
@JacksonXmlProperty(localName="minlon",isAttribute = true) @get:DecimalMin("-180.0") @get:DecimalMax("180.0") var minlon:Double = 0.0,
@JacksonXmlProperty(localName="maxlat",isAttribute = true) @get:DecimalMin("-90.0") @get:DecimalMax("90.0") var maxlat:Double = 0.0,
@JacksonXmlProperty(localName="maxlon",isAttribute = true) @get:DecimalMin("-180.0") @get:DecimalMax("180.0") var maxlon:Double = 0.0
)
{
}
Expand Down
78 changes: 77 additions & 1 deletion kotlin-gpx/src/test/kotlin/GpxTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.time.LocalDateTime
import javax.validation.ConstraintViolation
import javax.validation.Validation
import javax.validation.constraints.Size
import javax.validation.constraints.Max
import javax.validation.Validator
import javax.validation.ValidatorFactory
import kotlin.test.assertFalse
import kotlin.test.assertTrue


Expand Down Expand Up @@ -46,6 +53,7 @@ const val XML = """
</wpt>
<wpt lat="40.789547754060159" lon="-119.211019828752043">
<name>Akle' the Dragon</name>
<dgpsid>9999</dgpsid>
</wpt>
<trk>
<name>Runway 7L/25R</name>
Expand All @@ -67,7 +75,7 @@ const val XML = """
</trk>
</gpx>"""

class GpxJacksonTest()
class GpxTest()
{

@test fun testBlackRockCityXmlFileParsing()
Expand Down Expand Up @@ -173,4 +181,72 @@ class GpxJacksonTest()
val bounds2:Bounds = mapper.readValue(json0)
assertEquals(bounds0, bounds2)
}

@test fun testBasicValidationInKotlin()
{
data class User (
@get:Size(min=5, max=15) // added annotation use-site target here
val name: String,
@get:Max(130)
val age:Int
)
//given a validator
val factory = Validation.buildDefaultValidatorFactory()
val validator = factory.getValidator()
val moo = User("moo", 150)
val violations = validator.validate(moo)
assertFalse(violations.isEmpty())
val v1 = violations.find { it.propertyPath.toString() == "name" }
if (v1 != null) {
println(v1.message)
assertTrue(v1.leafBean is User)
assertEquals("name", v1.propertyPath.toString())
assertEquals("moo", v1.invalidValue)
assertTrue(v1.message.contains("5 and 15"))
}
val v2 = violations.find { it.propertyPath.toString() == "age" }
if (v2 != null) {
println(v2.message)
assertTrue(v2.leafBean is User)
assertEquals(150, v2.invalidValue)
assertTrue(v2.message.contains("130"))
}
}

@test fun beanValidation()
{
//given a validator
val factory = Validation.buildDefaultValidatorFactory()
val validator = factory.getValidator()

val xmlMapper = XmlMapper()
xmlMapper.registerModule(ParameterNamesModule())
xmlMapper.registerModule(JavaTimeModule())
xmlMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
xmlMapper.configure(SerializationFeature.INDENT_OUTPUT, true);

//marshall xml code into schema-gen generated POJOs
val gpx = xmlMapper.readValue<Gpx>(XML)
//and run validator on gpx tree
val violations = validator.validate(gpx)

//then should find nested min size violation in gpx.metadata.bounds.minlat
assertFalse(violations.isEmpty())
val v1 = violations.find { it.propertyPath.toString().endsWith("dgpsid") }
if (v1 != null) {
println(v1.message)
assertTrue(v1.leafBean is Wpt)
assertEquals(9999, v1.invalidValue)
assertTrue(v1.message.contains("1023"))
}
val v2 = violations.find { it.propertyPath.toString().endsWith("minlat") }
if (v2 != null) {
println(v2.message)
assertTrue(v2.leafBean is Bounds)
assertEquals(v2.getInvalidValue(), gpx.metadata?.bounds?.minlat)
assertTrue(v2.message.contains("90.0"))
}
}

}
Binary file not shown.

0 comments on commit 3fa7289

Please sign in to comment.