mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 15:56:57 +00:00
feature/add_required_field_annotation : make required field information shown in generated swagger doc
This commit is contained in:
parent
5453c78ddc
commit
7787919f15
@ -1,6 +1,7 @@
|
||||
package code.api.ResourceDocs1_4_0
|
||||
|
||||
import java.util.Date
|
||||
|
||||
import code.api.Constant._
|
||||
import code.api.Constant
|
||||
import code.api.UKOpenBanking.v2_0_0.JSONFactory_UKOpenBanking_200
|
||||
@ -25,7 +26,7 @@ import com.openbankproject.commons.model
|
||||
import com.openbankproject.commons.model.PinResetReason.{FORGOT, GOOD_SECURITY_PRACTICE}
|
||||
import com.openbankproject.commons.model.enums.CardAttributeType
|
||||
import com.openbankproject.commons.model.{UserAuthContextUpdateStatus, ViewBasic, _}
|
||||
import com.openbankproject.commons.util.ReflectUtils
|
||||
import com.openbankproject.commons.util.{ApiVersion, FieldNameApiVersions, ReflectUtils, RequiredArgs, RequiredInfo}
|
||||
|
||||
import scala.collection.immutable.List
|
||||
|
||||
@ -432,7 +433,12 @@ object SwaggerDefinitionsJSON {
|
||||
example_inbound_message = defaultJValue,
|
||||
outboundAvroSchema = Some(defaultJValue),
|
||||
inboundAvroSchema = Some(defaultJValue),
|
||||
adapter_implementation = adapterImplementationJson
|
||||
adapter_implementation = adapterImplementationJson,
|
||||
requiredFieldInfo = {
|
||||
val fieldNameApiVersions = FieldNameApiVersions("data.bankId", List(ApiVersion.v3_1_0.toString))
|
||||
val requiredInfo = RequiredInfo(List(fieldNameApiVersions))
|
||||
Some(requiredInfo)
|
||||
}
|
||||
)
|
||||
|
||||
val messageDocsJson = MessageDocsJson(message_docs = List(messageDocJson))
|
||||
|
||||
@ -27,9 +27,9 @@ object CustomJsonFormats {
|
||||
|
||||
val formats: Formats = net.liftweb.json.DefaultFormats + BigDecimalSerializer + FiledRenameSerializer + ListResultSerializer + EnumValueSerializer + JsonAbleSerializer
|
||||
|
||||
val losslessFormats: Formats = net.liftweb.json.DefaultFormats.lossless + BigDecimalSerializer + FiledRenameSerializer + ListResultSerializer + EnumValueSerializer
|
||||
val losslessFormats: Formats = net.liftweb.json.DefaultFormats.lossless + BigDecimalSerializer + FiledRenameSerializer + ListResultSerializer + EnumValueSerializer + JsonAbleSerializer
|
||||
|
||||
val emptyHintFormats = DefaultFormats.withHints(ShortTypeHints(List())) + BigDecimalSerializer + FiledRenameSerializer + ListResultSerializer + EnumValueSerializer
|
||||
val emptyHintFormats = DefaultFormats.withHints(ShortTypeHints(List())) + BigDecimalSerializer + FiledRenameSerializer + ListResultSerializer + EnumValueSerializer + JsonAbleSerializer
|
||||
|
||||
implicit val nullTolerateFormats = formats + JNothingSerializer
|
||||
|
||||
@ -37,7 +37,7 @@ object CustomJsonFormats {
|
||||
val dateFormat = net.liftweb.json.DefaultFormats.dateFormat
|
||||
|
||||
override val typeHints = ShortTypeHints(rolesMappedToClasses)
|
||||
} + BigDecimalSerializer + FiledRenameSerializer + ListResultSerializer + EnumValueSerializer
|
||||
} + BigDecimalSerializer + FiledRenameSerializer + ListResultSerializer + EnumValueSerializer + JsonAbleSerializer
|
||||
}
|
||||
|
||||
object BigDecimalSerializer extends Serializer[BigDecimal] {
|
||||
|
||||
@ -8,16 +8,13 @@ import code.api.v3_1_0.ListResult
|
||||
import code.crm.CrmEvent.CrmEvent
|
||||
import code.transactionrequests.TransactionRequestTypeCharge
|
||||
import com.openbankproject.commons.model.{Product, _}
|
||||
import com.openbankproject.commons.util.{EnumValue, OBPEnumeration}
|
||||
import com.openbankproject.commons.util.{EnumValue, OBPEnumeration, ReflectUtils}
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.json
|
||||
import net.liftweb.json.{JDouble, JInt, JString}
|
||||
import net.liftweb.json.JsonAST.{JArray, JBool, JObject, JValue}
|
||||
import net.liftweb.util.StringHelpers
|
||||
|
||||
import scala.reflect.runtime.currentMirror
|
||||
import scala.reflect.runtime.universe._
|
||||
|
||||
object JSONFactory1_4_0 {
|
||||
|
||||
|
||||
@ -403,19 +400,13 @@ object JSONFactory1_4_0 {
|
||||
case v => v
|
||||
}
|
||||
|
||||
val r = currentMirror.reflect(extractedEntity)
|
||||
val mapOfFields: Map[String, Any] = extractedEntity match {
|
||||
|
||||
case ListResult(name, results) => Map((name, results))
|
||||
case JObject(jFields) => jFields.map(it => (it.name, it.value)).toMap
|
||||
case _ => r.symbol.typeSignature.members.toStream
|
||||
.collect { case s: TermSymbol if !s.isMethod => r.reflectField(s)}
|
||||
.map(r => r.symbol.name.toString.trim -> r.get)
|
||||
.toMap
|
||||
case _ => ReflectUtils.getFieldValues(extractedEntity.asInstanceOf[AnyRef])()
|
||||
}
|
||||
|
||||
|
||||
|
||||
val convertParamName = (name: String) => extractedEntity match {
|
||||
case _ : JsonFieldReName => StringHelpers.snakify(name)
|
||||
case _ => name
|
||||
@ -457,7 +448,9 @@ object JSONFactory1_4_0 {
|
||||
case Some(i: String) => "\"" + key + """": {"type":"string"}"""
|
||||
case List(i: String, _*) => "\"" + key + """": {"type": "array","items": {"type": "string"}}"""
|
||||
case Some(List(i: String, _*)) => "\"" + key + """": {"type": "array","items": {"type": "string"}}"""
|
||||
//Int
|
||||
case Array(i: String, _*) => "\"" + key + """": {"type": "array","items": {"type": "string"}}"""
|
||||
case Some(Array(i: String, _*)) => "\"" + key + """": {"type": "array","items": {"type": "string"}}"""
|
||||
//Int
|
||||
case _: Int | _:JInt => "\"" + key + """": {"type":"integer"}"""
|
||||
case Some(i: Int) => "\"" + key + """": {"type":"integer"}"""
|
||||
case List(i: Int, _*) => "\"" + key + """": {"type": "array","items": {"type": "integer"}}"""
|
||||
|
||||
@ -410,7 +410,7 @@ trait APIMethods220 {
|
||||
messageDocs <- Full{connectorObject.messageDocs.toList}
|
||||
} yield {
|
||||
val json = JSONFactory220.createMessageDocsJson(messageDocs)
|
||||
successJsonResponse(Extraction.decompose(json))
|
||||
successJsonResponse(Extraction.decompose(json)(CustomJsonFormats.formats))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ import code.model._
|
||||
import com.openbankproject.commons.model.Product
|
||||
import code.users.Users
|
||||
import com.openbankproject.commons.model._
|
||||
import com.openbankproject.commons.util.{ReflectUtils, RequiredArgs, RequiredFieldValidation}
|
||||
import com.openbankproject.commons.util.{ReflectUtils, RequiredFieldValidation, RequiredInfo}
|
||||
import net.liftweb.common.{Box, Full}
|
||||
import net.liftweb.json.Extraction.decompose
|
||||
import net.liftweb.json.JsonAST.JValue
|
||||
@ -830,7 +830,7 @@ object JSONFactory220 extends CustomJsonFormats {
|
||||
outboundAvroSchema: Option[JValue] = None,
|
||||
inboundAvroSchema: Option[JValue] = None,
|
||||
adapter_implementation : AdapterImplementationJson,
|
||||
requiredFieldInfo: Map[String, RequiredArgs] = Map.empty
|
||||
requiredFieldInfo: Option[RequiredInfo] = None
|
||||
)
|
||||
|
||||
case class AdapterImplementationJson(
|
||||
@ -849,8 +849,6 @@ object JSONFactory220 extends CustomJsonFormats {
|
||||
|
||||
def createMessageDocJson(md: MessageDoc): MessageDocJson = {
|
||||
val inBoundType = ReflectUtils.getType(md.exampleInboundMessage)
|
||||
val regex = Pattern.compile("""(code|com\.openbankproject\.commons)\..+""")
|
||||
def findRequiredInfoFor(tp: Type): Boolean = regex.matcher(tp.toString).matches()
|
||||
|
||||
MessageDocJson(
|
||||
process = md.process,
|
||||
@ -868,7 +866,11 @@ object JSONFactory220 extends CustomJsonFormats {
|
||||
md.adapterImplementation.map(_.group).getOrElse(""),
|
||||
md.adapterImplementation.map(_.suggestedOrder).getOrElse(100)
|
||||
),
|
||||
requiredFieldInfo = RequiredFieldValidation.getAllNestedRequiredInfo(inBoundType, findRequiredInfoFor)
|
||||
requiredFieldInfo = {
|
||||
val requiredArgses = RequiredFieldValidation.getAllNestedRequiredInfo(inBoundType)
|
||||
val requiredInfo = RequiredInfo(requiredArgses)
|
||||
Some(requiredInfo)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
package com.openbankproject.commons.util
|
||||
import java.util.regex.Pattern
|
||||
|
||||
import scala.collection.{IterableLike, immutable}
|
||||
import scala.collection.generic.CanBuildFrom
|
||||
import scala.reflect.runtime.universe.Type
|
||||
/**
|
||||
* function utils
|
||||
*/
|
||||
@ -14,4 +18,48 @@ object Functions {
|
||||
def doNothing[T, D]: PartialFunction[T,D] = {
|
||||
case _ if false => ???
|
||||
}
|
||||
|
||||
def truePredicate[T]: T => Boolean = _ => true
|
||||
def falsePredicate[T]: T => Boolean = _ => false
|
||||
|
||||
private val obpTypeNamePattern = Pattern.compile("""(code|com\.openbankproject\.commons)\..+""")
|
||||
|
||||
def isOBPType(tp: Type) = obpTypeNamePattern.matcher(tp.typeSymbol.fullName).matches()
|
||||
def isOBPClass(clazz: Class[_]) = obpTypeNamePattern.matcher(clazz.getName).matches()
|
||||
|
||||
implicit class RichCollection[A, Repr](iterable: IterableLike[A, Repr]){
|
||||
def distinctBy[B, That](f: A => B)(implicit canBuildFrom: CanBuildFrom[Repr, A, That]) = {
|
||||
val builder = canBuildFrom(iterable.repr)
|
||||
val set = scala.collection.mutable.Set[B]()
|
||||
iterable.foreach(it => {
|
||||
val calculatedElement = f(it)
|
||||
if(set.add(calculatedElement)) {
|
||||
builder += it
|
||||
}
|
||||
})
|
||||
builder.result
|
||||
}
|
||||
def toMapByKey[K](f: A => K): immutable.Map[K, A] = {
|
||||
val b = immutable.Map.newBuilder[K, A]
|
||||
for (x <- iterable)
|
||||
b += f(x) -> x
|
||||
|
||||
b.result()
|
||||
}
|
||||
def toMapByValue[V](f: A => V): immutable.Map[A, V] = {
|
||||
val b = immutable.Map.newBuilder[A, V]
|
||||
for (x <- iterable)
|
||||
b += x -> f(x)
|
||||
|
||||
b.result()
|
||||
}
|
||||
|
||||
def toMap[K, V](keyFn: A => K, valueFn: A => V): immutable.Map[K, V] = {
|
||||
val b = immutable.Map.newBuilder[K, V]
|
||||
for (x <- iterable)
|
||||
b += keyFn(x) -> valueFn(x)
|
||||
|
||||
b.result()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,9 +58,9 @@ object ReflectUtils {
|
||||
val TermName(fieldName) = it.name
|
||||
if(it.isLazy) {
|
||||
// get lazy value
|
||||
fieldName -> instanceMirror.reflectMethod(it.asMethod)()
|
||||
fieldName.trim -> instanceMirror.reflectMethod(it.asMethod)()
|
||||
} else {
|
||||
fieldName -> instanceMirror.reflectField(it).get
|
||||
fieldName.trim -> instanceMirror.reflectField(it).get
|
||||
}
|
||||
})
|
||||
.toMap
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
package com.openbankproject.commons.util
|
||||
|
||||
import java.util.Objects
|
||||
|
||||
import com.openbankproject.commons.util.ApiVersion.allVersion
|
||||
import net.liftweb.json.JValue
|
||||
import net.liftweb.json.JsonAST.{JArray, JString}
|
||||
import net.liftweb.json.JsonAST.{JArray, JField, JObject, JString}
|
||||
|
||||
import scala.annotation.StaticAnnotation
|
||||
import scala.collection.immutable.ListMap
|
||||
import scala.reflect.runtime.universe._
|
||||
import Functions.RichCollection
|
||||
|
||||
|
||||
/**
|
||||
@ -37,8 +38,36 @@ class OBPRequired(value: Array[ApiVersion] = Array(ApiVersion.allVersion),
|
||||
exclude: Array[ApiVersion] = Array.empty
|
||||
) extends StaticAnnotation
|
||||
|
||||
/**
|
||||
* cooperate with RequiredInfo to deal with generate swagger doc and json serialization problem (show wrong structure of json)
|
||||
* @param filedName
|
||||
* @param apiVersions
|
||||
*/
|
||||
case class FieldNameApiVersions(filedName: String, apiVersions: List[String])
|
||||
|
||||
case class RequiredArgs(include: Array[ApiVersion],
|
||||
/**
|
||||
* cooperate with RequiredInfo to deal with generate swagger doc and json serialization problem (show wrong structure of json)
|
||||
* @param infos
|
||||
*/
|
||||
case class RequiredInfo(infos: List[FieldNameApiVersions]) extends JsonAble {
|
||||
|
||||
override def toJValue: JObject = {
|
||||
val jFields = infos.map(info => JField(
|
||||
info.filedName,
|
||||
JArray(info.apiVersions.map(JString(_))))
|
||||
)
|
||||
JObject(jFields)
|
||||
}
|
||||
}
|
||||
|
||||
object RequiredInfo {
|
||||
def apply(requiredArgs: Seq[RequiredArgs]): RequiredInfo = {
|
||||
val fieldNameApiVersionses = requiredArgs.toList.map(arg => FieldNameApiVersions(arg.fieldPath, arg.apiVersions))
|
||||
RequiredInfo(fieldNameApiVersionses)
|
||||
}
|
||||
}
|
||||
|
||||
case class RequiredArgs(fieldPath:String, include: Array[ApiVersion],
|
||||
exclude: Array[ApiVersion] = Array.empty) extends JsonAble {
|
||||
{
|
||||
val includeAll = include.contains(allVersion)
|
||||
@ -69,10 +98,10 @@ case class RequiredArgs(include: Array[ApiVersion],
|
||||
}
|
||||
|
||||
override def equals(obj: Any): Boolean = obj match {
|
||||
case RequiredArgs(inc, exc) => include.sameElements(inc) && exclude.sameElements(exc)
|
||||
case RequiredArgs(path, inc, exc) => Objects.equals(fieldPath, path) && include.sameElements(inc) && exclude.sameElements(exc)
|
||||
case _ => false
|
||||
}
|
||||
override def toJValue: JValue = (include, exclude) match {
|
||||
override val toJValue: JArray = (include, exclude) match {
|
||||
case (_, Array()) =>
|
||||
val includeList = include.toList.map(_.toString).map(JString(_))
|
||||
JArray(includeList)
|
||||
@ -80,6 +109,10 @@ case class RequiredArgs(include: Array[ApiVersion],
|
||||
val excludeList = include.toList.map("-" + _.toString).map(JString(_))
|
||||
JArray(excludeList)
|
||||
}
|
||||
val apiVersions: List[String] = (include, exclude) match {
|
||||
case (_, Array()) => include.toList.map(_.toString)
|
||||
case _ => include.toList.map("-" + _.toString)
|
||||
}
|
||||
}
|
||||
|
||||
object RequiredFieldValidation {
|
||||
@ -123,35 +156,43 @@ object RequiredFieldValidation {
|
||||
* @param tp to process type
|
||||
* @return map of field name to RequiredArgs
|
||||
*/
|
||||
def getAnnotations(tp: Type): Map[String, RequiredArgs] = {
|
||||
def getAnnotations(tp: Type): Iterable[RequiredArgs] = {
|
||||
val members = tp.members
|
||||
|
||||
val constructors = members.filter(_.isConstructor).map(_.asMethod)
|
||||
|
||||
def getFieldNameAndAnnotation(symbol: Symbol): List[(String, RequiredArgs)] = {
|
||||
(symbol.name.decodedName, getAnnotation(symbol)) match{
|
||||
case (TermName(name), Some(requiredArgs)) => List(name.trim -> requiredArgs)
|
||||
case _ => Nil
|
||||
def getFieldNameAndAnnotation(symbol: Symbol): Option[RequiredArgs] = {
|
||||
val fieldName = symbol.name.decodedName.toString.trim
|
||||
getAnnotation(fieldName, symbol) match{
|
||||
case some: Some[RequiredArgs] => some
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
// constructor param name to RequiredArgs
|
||||
val constructorParamToRequiredArgs: Map[String, RequiredArgs] = constructors
|
||||
val constructorParamToRequiredArgs: Iterable[RequiredArgs] = constructors
|
||||
.flatMap(_.paramLists.head) // all the constructor's parameters
|
||||
.flatMap(getFieldNameAndAnnotation)
|
||||
.toMap
|
||||
.map(getFieldNameAndAnnotation)
|
||||
.collect {
|
||||
case Some(requiredArgs) => requiredArgs
|
||||
}
|
||||
val constructorParamNames = constructorParamToRequiredArgs.map(_.fieldPath).toSet
|
||||
// those annotated field name to RequiredArgs
|
||||
val annotatedFieldNameToRequiredArgs: Map[String, RequiredArgs] =
|
||||
members.filter(it => {
|
||||
!it.isConstructor && !constructorParamToRequiredArgs.contains(it.name.decodedName.toString.trim)
|
||||
})
|
||||
.flatMap(getFieldNameAndAnnotation)
|
||||
.toMap
|
||||
val requiredFields: Map[String, RequiredArgs] = constructorParamToRequiredArgs ++ annotatedFieldNameToRequiredArgs
|
||||
requiredFields
|
||||
val annotatedFieldNameToRequiredArgs: Iterable[RequiredArgs] =
|
||||
members
|
||||
.filter(it => {
|
||||
!it.isConstructor && !constructorParamNames.contains(it.name.decodedName.toString.trim)
|
||||
})
|
||||
.map(getFieldNameAndAnnotation)
|
||||
.collect {
|
||||
case Some(requiredArgs) => requiredArgs
|
||||
}
|
||||
.distinctBy(_.fieldPath)
|
||||
|
||||
constructorParamToRequiredArgs ++ annotatedFieldNameToRequiredArgs
|
||||
}
|
||||
|
||||
def getAnnotation(symbol: Symbol): Option[RequiredArgs] = {
|
||||
def getAnnotation(fieldName: String, symbol: Symbol): Option[RequiredArgs] = {
|
||||
val annotation: Option[Annotation] =
|
||||
(symbol :: symbol.overrides)
|
||||
.flatMap(_.annotations)
|
||||
@ -159,47 +200,45 @@ object RequiredFieldValidation {
|
||||
|
||||
annotation.map { it: Annotation =>
|
||||
it.tree.children.tail match {
|
||||
case (include: Tree)::(exclude: Tree)::Nil => RequiredArgs(getVersions(include), getVersions(exclude))
|
||||
case (include: Tree)::(exclude: Tree)::Nil => RequiredArgs(fieldName, getVersions(include), getVersions(exclude))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def getAllNestedRequiredInfo(tp: Type,
|
||||
fieldName: String,
|
||||
predicate: Type => Boolean
|
||||
): Map[String, RequiredArgs] = {
|
||||
def getAllNestedRequiredInfo(tp: Type,
|
||||
predicate: Type => Boolean = Functions.isOBPType,
|
||||
fieldName: String = null
|
||||
): Seq[RequiredArgs] = {
|
||||
|
||||
if(!predicate(tp)) {
|
||||
return Map.empty
|
||||
return Nil
|
||||
}
|
||||
|
||||
val fieldToRequiredInfo: Map[String, RequiredArgs] = getAnnotations(tp)
|
||||
val fieldToRequiredInfo: Iterable[RequiredArgs] = getAnnotations(tp)
|
||||
|
||||
// current type's fields full path to RequiredInfo
|
||||
val currentPathToRequiredInfo = fieldName match {
|
||||
case null => fieldToRequiredInfo
|
||||
case _ => fieldToRequiredInfo.map(it=> (s"$fieldName.${it._1}", it._2))
|
||||
case _ => fieldToRequiredInfo.map(it=> it.copy(fieldPath = s"$fieldName.${it.fieldPath}"))
|
||||
}
|
||||
|
||||
// find all sub fields RequiredInfo
|
||||
val subPathToRequiredInfo: Map[String, RequiredArgs] = tp.members.collect {
|
||||
case m: MethodSymbolApi if m.isGetter => (m.name.decodedName.toString.trim, ReflectUtils.getNestFirstTypeArg(m.returnType))
|
||||
case m: TermSymbolApi if m.isCaseAccessor || m.isVal => (m.name.decodedName.toString.trim, m.info)
|
||||
}.filter(tuple => predicate(tuple._2))
|
||||
val subPathToRequiredInfo: Iterable[RequiredArgs] = tp.members.collect {
|
||||
case m: MethodSymbolApi if m.isGetter => {
|
||||
(m.name.decodedName.toString.trim, ReflectUtils.getNestFirstTypeArg(m.returnType))
|
||||
}
|
||||
case m: TermSymbolApi if m.isCaseAccessor || m.isVal => {
|
||||
(m.name.decodedName.toString.trim, ReflectUtils.getNestFirstTypeArg(m.info))
|
||||
}
|
||||
} .filter(tuple => predicate(tuple._2))
|
||||
.distinctBy(_._1)
|
||||
.flatMap(pair => {
|
||||
val (memberName, membersType) = pair
|
||||
val subFieldName = if(fieldName == null) memberName else s"$fieldName.$memberName"
|
||||
getAllNestedRequiredInfo(membersType, subFieldName, predicate)
|
||||
}).toMap
|
||||
getAllNestedRequiredInfo(membersType, predicate, subFieldName)
|
||||
})
|
||||
|
||||
currentPathToRequiredInfo ++ subPathToRequiredInfo
|
||||
}
|
||||
|
||||
def getAllNestedRequiredInfo(tp: Type,
|
||||
predicate: Type => Boolean = _ => true
|
||||
): Map[String, RequiredArgs] = {
|
||||
val unSortedResult = getAllNestedRequiredInfo(tp, null, predicate)
|
||||
ListMap(unSortedResult.toSeq.sortBy(_._1): _*)
|
||||
(currentPathToRequiredInfo ++ subPathToRequiredInfo).toSeq.sortBy(_.fieldPath)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,65 +1,66 @@
|
||||
package com.openbankproject.commons.util
|
||||
|
||||
import com.openbankproject.commons.util.ApiVersion
|
||||
import com.openbankproject.commons.util.ApiVersion._
|
||||
import org.scalatest.{FlatSpec, Matchers, Tag}
|
||||
import org.scalatest.PartialFunctionValues._
|
||||
|
||||
import scala.reflect.runtime.universe._
|
||||
import Functions.RichCollection
|
||||
|
||||
class RequiredFieldValidationTest extends FlatSpec with Matchers {
|
||||
object tag extends Tag("RequiredFieldValidation")
|
||||
|
||||
"when annotated at constructor param and overriding val" should "all the annotations be extract by call RequiredFieldValidation.getAnnotations" taggedAs tag in {
|
||||
val symbols = RequiredFieldValidation.getAnnotations(typeOf[Bar])
|
||||
val symbols = RequiredFieldValidation.getAnnotations(typeOf[Bar]).toMapByKey(_.fieldPath)
|
||||
|
||||
symbols should have size 3
|
||||
|
||||
symbols("name") should equal(RequiredArgs(Array(ApiVersion.allVersion), Array(v3_0_0)))
|
||||
symbols("name") should equal(RequiredArgs("name", Array(ApiVersion.allVersion), Array(v3_0_0)))
|
||||
|
||||
symbols("age") should equal (
|
||||
RequiredArgs(Array(v2_0_0, v1_2_1, v1_4_0), Array.empty)
|
||||
RequiredArgs("age", Array(v2_0_0, v1_2_1, v1_4_0), Array.empty)
|
||||
)
|
||||
|
||||
symbols("email") should equal(RequiredArgs(Array(ApiVersion.allVersion), Array()))
|
||||
symbols("email") should equal(RequiredArgs("email", Array(ApiVersion.allVersion), Array()))
|
||||
}
|
||||
|
||||
"method RequiredFieldValidation.getAllNestedRequiredInfo" should "extract all nested required info" taggedAs tag in {
|
||||
val stringToArgs: Map[String, RequiredArgs] = RequiredFieldValidation.getAllNestedRequiredInfo(typeOf[Outer])
|
||||
val requiredArgses = RequiredFieldValidation.getAllNestedRequiredInfo(typeOf[Outer])
|
||||
val stringToArgs: Map[String, RequiredArgs] = requiredArgses.toMapByKey(_.fieldPath)
|
||||
|
||||
val expectedRequireFooAnnoInfo = RequiredArgs(Array( v1_4_0))
|
||||
stringToArgs.valueAt("requireFoo") should equal (expectedRequireFooAnnoInfo)
|
||||
val expectedRequireFooAnnoInfo = RequiredArgs("", Array( v1_4_0))
|
||||
stringToArgs.valueAt("requireFoo") should equal (expectedRequireFooAnnoInfo.copy(fieldPath = "requireFoo"))
|
||||
|
||||
val expectedNameAnnoInfo = RequiredArgs(Array(ApiVersion.allVersion))
|
||||
val expectedAgeAnnoInfo = RequiredArgs(Array(v2_0_0, v1_2_1, v1_4_0))
|
||||
val expectedEmailAnnoInfo = RequiredArgs(Array(ApiVersion.allVersion), Array(v2_0_0))
|
||||
val expectedNameAnnoInfo = RequiredArgs("", Array(ApiVersion.allVersion))
|
||||
val expectedAgeAnnoInfo = RequiredArgs("", Array(v2_0_0, v1_2_1, v1_4_0))
|
||||
val expectedEmailAnnoInfo = RequiredArgs("", Array(ApiVersion.allVersion), Array(v2_0_0))
|
||||
|
||||
stringToArgs.valueAt("foo.name") should equal (expectedNameAnnoInfo)
|
||||
stringToArgs.valueAt("foo.age") should equal (expectedAgeAnnoInfo)
|
||||
stringToArgs.valueAt("foo.email") should equal (expectedEmailAnnoInfo)
|
||||
stringToArgs.valueAt("foo.name") should equal (expectedNameAnnoInfo.copy(fieldPath = "foo.name"))
|
||||
stringToArgs.valueAt("foo.age") should equal (expectedAgeAnnoInfo.copy(fieldPath = "foo.age"))
|
||||
stringToArgs.valueAt("foo.email") should equal (expectedEmailAnnoInfo.copy(fieldPath = "foo.email"))
|
||||
|
||||
stringToArgs.valueAt("requireFoo.name") should equal (expectedNameAnnoInfo)
|
||||
stringToArgs.valueAt("requireFoo.age") should equal (expectedAgeAnnoInfo)
|
||||
stringToArgs.valueAt("requireFoo.email") should equal (expectedEmailAnnoInfo)
|
||||
stringToArgs.valueAt("requireFoo.name") should equal (expectedNameAnnoInfo.copy(fieldPath = "requireFoo.name"))
|
||||
stringToArgs.valueAt("requireFoo.age") should equal (expectedAgeAnnoInfo.copy(fieldPath = "requireFoo.age"))
|
||||
stringToArgs.valueAt("requireFoo.email") should equal (expectedEmailAnnoInfo.copy(fieldPath = "requireFoo.email"))
|
||||
|
||||
stringToArgs.valueAt("list.name") should equal (expectedNameAnnoInfo)
|
||||
stringToArgs.valueAt("list.age") should equal (expectedAgeAnnoInfo)
|
||||
stringToArgs.valueAt("list.email") should equal (expectedEmailAnnoInfo)
|
||||
stringToArgs.valueAt("list.name") should equal (expectedNameAnnoInfo.copy(fieldPath = "list.name"))
|
||||
stringToArgs.valueAt("list.age") should equal (expectedAgeAnnoInfo.copy(fieldPath = "list.age"))
|
||||
stringToArgs.valueAt("list.email") should equal (expectedEmailAnnoInfo.copy(fieldPath = "list.email"))
|
||||
|
||||
stringToArgs.valueAt("array.name") should equal (expectedNameAnnoInfo)
|
||||
stringToArgs.valueAt("array.age") should equal (expectedAgeAnnoInfo)
|
||||
stringToArgs.valueAt("array.email") should equal (expectedEmailAnnoInfo)
|
||||
stringToArgs.valueAt("array.name") should equal (expectedNameAnnoInfo.copy(fieldPath = "array.name"))
|
||||
stringToArgs.valueAt("array.age") should equal (expectedAgeAnnoInfo.copy(fieldPath = "array.age"))
|
||||
stringToArgs.valueAt("array.email") should equal (expectedEmailAnnoInfo.copy(fieldPath = "array.email"))
|
||||
|
||||
val expectedMiddleRequiredAnnoInfo = RequiredArgs(Array(ApiVersion.allVersion))
|
||||
stringToArgs.valueAt("middle.middleRequired") should equal (expectedMiddleRequiredAnnoInfo)
|
||||
val expectedMiddleRequiredAnnoInfo = RequiredArgs("", Array(ApiVersion.allVersion))
|
||||
stringToArgs.valueAt("middle.middleRequired") should equal (expectedMiddleRequiredAnnoInfo.copy(fieldPath = "middle.middleRequired"))
|
||||
|
||||
stringToArgs.valueAt("middle.middleRequired.name") should equal (expectedNameAnnoInfo)
|
||||
stringToArgs.valueAt("middle.middleRequired.age") should equal (expectedAgeAnnoInfo)
|
||||
stringToArgs.valueAt("middle.middleRequired.email") should equal (expectedEmailAnnoInfo)
|
||||
stringToArgs.valueAt("middle.middleRequired.name") should equal (expectedNameAnnoInfo.copy(fieldPath = "middle.middleRequired.name"))
|
||||
stringToArgs.valueAt("middle.middleRequired.age") should equal (expectedAgeAnnoInfo.copy(fieldPath = "middle.middleRequired.age"))
|
||||
stringToArgs.valueAt("middle.middleRequired.email") should equal (expectedEmailAnnoInfo.copy(fieldPath = "middle.middleRequired.email"))
|
||||
|
||||
stringToArgs.valueAt("middle.middleNoRequire.name") should equal (expectedNameAnnoInfo)
|
||||
stringToArgs.valueAt("middle.middleNoRequire.age") should equal (expectedAgeAnnoInfo)
|
||||
stringToArgs.valueAt("middle.middleNoRequire.email") should equal (expectedEmailAnnoInfo)
|
||||
stringToArgs.valueAt("middle.middleNoRequire.name") should equal (expectedNameAnnoInfo.copy(fieldPath = "middle.middleNoRequire.name"))
|
||||
stringToArgs.valueAt("middle.middleNoRequire.age") should equal (expectedAgeAnnoInfo.copy(fieldPath = "middle.middleNoRequire.age"))
|
||||
stringToArgs.valueAt("middle.middleNoRequire.email") should equal (expectedEmailAnnoInfo.copy(fieldPath = "middle.middleNoRequire.email"))
|
||||
|
||||
stringToArgs should have size (20)
|
||||
}
|
||||
|
||||
2
pom.xml
2
pom.xml
@ -11,7 +11,7 @@
|
||||
<inceptionYear>2011</inceptionYear>
|
||||
<properties>
|
||||
<scala.version>2.12</scala.version>
|
||||
<scala.compiler>2.12.10</scala.compiler>
|
||||
<scala.compiler>2.12.6</scala.compiler>
|
||||
<akka.version>2.5.19</akka.version>
|
||||
<akka-streams-kafka.version>0.22</akka-streams-kafka.version>
|
||||
<kafka.version>1.1.0</kafka.version>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user