refactor/anotation_ignore_change_to_optional: change all @ignore to @optional, also outbound.optional.fields and inbound.optional.fields

This commit is contained in:
shuang 2020-07-27 21:51:44 +08:00
parent 60efabec8a
commit 5968aed8ff
10 changed files with 109 additions and 95 deletions

View File

@ -31,7 +31,7 @@
<dependency>
<groupId>com.github.OpenBankProject.OBP-Adapter-Akka-SpringBoot</groupId>
<artifactId>adapter-akka-commons</artifactId>
<version>develop-SNAPSHOT</version>
<version>v1.1.0</version>
<exclusions>
<exclusion>
<groupId>*</groupId>

View File

@ -16,7 +16,7 @@ connector=mapped
#connector=stored_procedure_vDec2019
#connector=obpjvm
#connector=star
## proxy connector get data from LocalMappedConnector, and set the follow corresponding fields to be null: @ignore, inbound.ignore.fields props, outbound.ignore.fields props
## proxy connector get data from LocalMappedConnector, and set the follow corresponding fields to be null: @optional, inbound.optional.fields props, outbound.optional.fields props
## the proxy connector only for test purpose
#connector=proxy
#connector=...
@ -842,12 +842,12 @@ dynamic_endpoints_url_prefix=dynamic
# --------------------------------------------------------------------
## Inbound and Outbound ignore field names, case class name can be prefix.
inbound.ignore.fields=\
inbound.optional.fields=\
inboundAdapterCallContext.generalContext,\
inboundAdapterCallContext.sessionId,\
InBoundGetBanks:data.logoUrl
outbound.ignore.fields= \
outbound.optional.fields= \
outboundAdapterCallContext.sessionId, \
outboundAdapterCallContext.consumerId, \
outboundAdapterCallContext.generalContext

View File

@ -17,7 +17,7 @@
#connector=rest
#connector=kafka
#connector=obpjvm
## proxy connector get data from LocalMappedConnector, and set the follow corresponding fields to be null: @ignore, inbound.ignore.fields props, outbound.ignore.fields props
## proxy connector get data from LocalMappedConnector, and set the follow corresponding fields to be null: @optional, inbound.optional.fields props, outbound.optional.fields props
#connector=proxy
connector=mapped

View File

@ -34,20 +34,31 @@ object CustomJsonFormats {
}
object FieldIgnoreSerializer extends Serializer[AnyRef] {
private val typedIgnoreRegx = "(.+?):(.+)".r
object OptionalFieldSerializer extends Serializer[AnyRef] {
private val typedOptionalPathRegx = "(.+?):(.+)".r
private val memo = new Memo[universe.Type, List[String]]()
override def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, json.JValue), AnyRef] = Functions.doNothing
private lazy val propsConfigIgnoreFields = Array(
APIUtil.getPropsValue("outbound.ignore.fields", "").split("""\s*,\s*"""),
APIUtil.getPropsValue("inbound.ignore.fields", "").split("""\s*,\s*""")
).flatten.filterNot(StringUtils.isBlank).toList
private lazy val propsOutboundOptionalFields =
APIUtil.getPropsValue("outbound.optional.fields", "")
.split("""\s*,\s*""").filterNot(StringUtils.isBlank).toList
private lazy val propsInboundOptionalFields =
APIUtil.getPropsValue("inbound.optional.fields", "")
.split("""\s*,\s*""").filterNot(StringUtils.isBlank).toList
// keep current process InBound or OutBound instance, avoid dead loop.
private val threadLocal = new java.lang.ThreadLocal[Any]
override def serialize(implicit format: Formats): PartialFunction[Any, json.JValue] = {
case x if isInOutBoundType(x) && threadLocal.get() == null =>
case x if isOutboundType(x) && threadLocal.get() == null =>
threadLocal.set(x)
try{
toIgnoreFieldJson(x)
} finally {
threadLocal.remove()
}
case x if isInboundType(x) && threadLocal.get() == null =>
threadLocal.set(x)
try{
toIgnoreFieldJson(x)
@ -61,11 +72,22 @@ object FieldIgnoreSerializer extends Serializer[AnyRef] {
def toIgnoreFieldJson(any: Any, tp: universe.Type, ignoreFunc: List[String] => List[String] = Functions.unary)(implicit formats: Formats): JValue = {
val TYPE_NAME = tp.typeSymbol.name.decodedName.toString
// if props value like this InBoundGetBanks:data.logoUrl, the type name must match current process object type.
val filterPropsIgnoreFields = propsConfigIgnoreFields collect {
case typedIgnoreRegx(TYPE_NAME, ignorePath) => ignorePath
case x => x
val filterPropsIgnoreFields: List[String] = {
val optionalProps = if(isOutboundType(any)) {
this.propsOutboundOptionalFields
} else if(isInboundType(any)) {
this.propsInboundOptionalFields
} else {
Nil
}
optionalProps collect {
case typedOptionalPathRegx(TYPE_NAME, ignorePath) => ignorePath
case x if !x.contains(':') => x
}
}
val ignoreFieldNames: List[String] = getIgnores(tp) ::: filterPropsIgnoreFields
val ignoreFieldNames: List[String] = getOptionals(tp) ::: filterPropsIgnoreFields
val zson = json.Extraction.decompose(any)
ignoreFieldNames match {
case Nil => zson
@ -73,23 +95,20 @@ object FieldIgnoreSerializer extends Serializer[AnyRef] {
}
}
private def isInOutBoundType(any: Any) = {
if(ReflectUtils.isObpObject(any)) {
val className = any.getClass.getSimpleName
className.startsWith("OutBound") || className.startsWith("InBound")
} else {
false
}
}
private def isInboundType(any: Any) =
ReflectUtils.isObpObject(any) && any.getClass.getSimpleName.startsWith("InBound")
def getIgnores(tp: universe.Type): List[String] = {
private def isOutboundType(any: Any) =
ReflectUtils.isObpObject(any) && any.getClass.getSimpleName.startsWith("OutBound")
def getOptionals(tp: universe.Type): List[String] = {
if(!ReflectUtils.isObpType(tp)) {
return Nil
}
memo.memoize(tp){
val fields: List[universe.Symbol] = tp.decls.filter(decl => decl.isTerm && (decl.asTerm.isVal || decl.asTerm.isVar)).toList
val (ignoreFields, notIgnoreFields) = fields.partition(_.annotations.exists(_.tree.tpe <:< typeOf[ignore]))
val annotedFieldNames = ignoreFields.map(_.name.decodedName.toString.trim)
val (optionalFields, notIgnoreFields) = fields.partition(_.annotations.exists(_.tree.tpe <:< typeOf[optional]))
val annotedFieldNames = optionalFields.map(_.name.decodedName.toString.trim)
val subAnnotedFieldNames = notIgnoreFields.flatMap(it => {
val fieldName = it.name.decodedName.toString.trim
val fieldType: universe.Type = it.info match {
@ -100,7 +119,7 @@ object FieldIgnoreSerializer extends Serializer[AnyRef] {
case x => x
}
getIgnores(fieldType)
getOptionals(fieldType)
.map(it => s"$fieldName.$it")
})
annotedFieldNames ++ subAnnotedFieldNames

View File

@ -29,7 +29,7 @@ package code.api.v2_2_0
import java.util.Date
import code.actorsystem.ObpActorConfig
import code.api.util.{APIUtil, ApiPropsWithAlias, CustomJsonFormats, FieldIgnoreSerializer}
import code.api.util.{APIUtil, ApiPropsWithAlias, CustomJsonFormats, OptionalFieldSerializer}
import code.api.util.APIUtil.{EndpointInfo, MessageDoc, getPropsValue}
import code.api.v1_2_1.BankRoutingJsonV121
import com.openbankproject.commons.model.{AccountRoutingJsonV121, AmountOfMoneyJsonV121}
@ -846,7 +846,7 @@ object JSONFactory220 {
MessageDocsJson(messageDocsList.map(createMessageDocJson))
}
private implicit val formats = CustomJsonFormats.formats + FieldIgnoreSerializer
private implicit val formats = CustomJsonFormats.formats + OptionalFieldSerializer
def createMessageDocJson(md: MessageDoc): MessageDocJson = {
val inBoundType = ReflectUtils.getType(md.exampleInboundMessage)

View File

@ -2,7 +2,7 @@ package code.bankconnectors
import java.lang.reflect.Method
import code.api.util.{CallContext, CustomJsonFormats, FieldIgnoreSerializer, OBPQueryParam}
import code.api.util.{CallContext, CustomJsonFormats, OptionalFieldSerializer, OBPQueryParam}
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.dto.{InBoundTrait, OutInBoundTransfer}
import com.openbankproject.commons.model.TopicTrait
@ -56,7 +56,7 @@ object ConnectorUtils {
def processIgnoreFields(fields: List[String]): List[String] = fields.collect {
case x if x.startsWith("data.") => StringUtils.substringAfter(x, "data.")
}
val zson = FieldIgnoreSerializer.toIgnoreFieldJson(obj, ReflectUtils.classToType(inBoundClass), processIgnoreFields)
val zson = OptionalFieldSerializer.toIgnoreFieldJson(obj, ReflectUtils.classToType(inBoundClass), processIgnoreFields)
val jObj: JValue = "data" -> zson

View File

@ -6,7 +6,7 @@ import java.util.{Date, TimeZone}
import code.api.ResourceDocs1_4_0.MessageDocsSwaggerDefinitions.successStatus
import code.api.util.APIUtil.MessageDoc
import code.api.util.CustomJsonFormats.formats
import code.api.util.{APIUtil, FieldIgnoreSerializer}
import code.api.util.{APIUtil, OptionalFieldSerializer}
import code.bankconnectors.ConnectorBuilderUtil._
import com.openbankproject.commons.model.Status
import com.openbankproject.commons.util.Functions
@ -36,7 +36,7 @@ object MSsqlStoredProcedureBuilder {
// Boot.scala set default TimeZone, So here need also fix the TimeZone to make example Date is a fix value,
// not affect by local TimeZone.
TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
implicit val customFormats = formats + StatusSerializer + FieldIgnoreSerializer
implicit val customFormats = formats + StatusSerializer + OptionalFieldSerializer
val messageDocs: ArrayBuffer[MessageDoc] = StoredProcedureConnector_vDec2019.messageDocs
def toProcedureName(processName: String) = StringHelpers.snakify(processName.replace("obp.", "obp_"))
def toJson(any: Any) = json.prettyRender(json.Extraction.decompose(any))

View File

@ -28,7 +28,7 @@ package com.openbankproject.commons.model
import java.util.Date
import com.openbankproject.commons.util.{OBPRequired, ignore}
import com.openbankproject.commons.util.{OBPRequired, optional}
import scala.collection.immutable.List
import scala.math.BigDecimal
@ -183,10 +183,10 @@ trait BankAccount{
def currency : String
def name : String // Is this used? -->It is used for BerlinGroup V1.3, it has the name in account response.
// `Name of the account given by the bank or the PSU in online-banking.`
@ignore
@optional
def label: String
@deprecated("We should use accountRoutings instead")
@ignore
@optional
def iban : Option[String]
def number : String
def bankId : BankId
@ -194,16 +194,16 @@ trait BankAccount{
def lastUpdate : Date
def branchId: String
@deprecated("We should use accountRoutings instead")
@ignore
@optional
def accountRoutingScheme: String
@deprecated("We should use accountRoutings instead")
@ignore
@optional
def accountRoutingAddress: String
def accountRoutings: List[AccountRouting] // Introduced in v3.0.0
@ignore
@optional
def accountRules: List[AccountRule]
@deprecated("Get the account holder(s) via owners")
@ignore
@optional
def accountHolder : String
}
@ -239,7 +239,7 @@ as see from the perspective of the original party.
case class Counterparty(
@deprecated("older version, please first consider the V210, account scheme and address","05/05/2017")
@ignore
@optional
val nationalIdentifier: String, // This is the scheme a consumer would use to instruct a payment e.g. IBAN
val kind: String, // Type of bank account.
@ -248,15 +248,15 @@ case class Counterparty(
val counterpartyName: String,
val thisBankId: BankId, // i.e. the Account that sends/receives money to/from this Counterparty
val thisAccountId: AccountId, // These 2 fields specify the account that uses this Counterparty
@ignore
@optional
val otherBankRoutingScheme: String, // This is the scheme a consumer would use to specify the bank e.g. BIC
@ignore
@optional
val otherBankRoutingAddress: Option[String], // The (BIC) value e.g. 67895
@ignore
@optional
val otherAccountRoutingScheme: String, // This is the scheme a consumer would use to instruct a payment e.g. IBAN
@ignore
@optional
val otherAccountRoutingAddress: Option[String], // The (IBAN) value e.g. 2349870987820374
@ignore
@optional
val otherAccountProvider: String, // hasBankId and hasAccountId would refer to an OBP account
val isBeneficiary: Boolean // True if the originAccount can send money to the Counterparty
)

View File

@ -29,10 +29,9 @@ package com.openbankproject.commons.model
import java.util.Date
import com.openbankproject.commons.model.enums._
import com.openbankproject.commons.util.{JsonAble, ReflectUtils, ignore}
import net.liftweb.json
import net.liftweb.json.{Formats, JInt, JString}
import com.openbankproject.commons.util.{ReflectUtils, optional}
import net.liftweb.json.JsonAST.{JObject, JValue}
import net.liftweb.json.{JInt, JString}
import scala.collection.immutable.List
import scala.reflect.runtime.universe._
@ -119,22 +118,22 @@ case class BankAccountCommons(
balance :BigDecimal,
currency :String,
name :String,
@ignore
@optional
label :String,
@ignore
@optional
iban :Option[String],
number :String,
bankId :BankId,
lastUpdate :Date,
branchId :String,
@ignore
@optional
accountRoutingScheme :String,
@ignore
@optional
accountRoutingAddress :String,
accountRoutings :List[AccountRouting],
@ignore
@optional
accountRules :List[AccountRule],
@ignore
@optional
accountHolder :String) extends BankAccount
object BankAccountCommons extends Converter[BankAccount, BankAccountCommons]
@ -192,31 +191,31 @@ object CustomerAddressCommons extends Converter[CustomerAddress, CustomerAddress
//It will get the bankId, accountId and viewsToGenerate to create the OBP side data, such as views, accountHolder.
case class InboundAccountCommons(
bankId :String,
@ignore
@optional
branchId :String,
accountId :String,
@ignore
@optional
accountNumber :String,
@ignore
@optional
accountType :String,
@ignore
@optional
balanceAmount :String,
@ignore
@optional
balanceCurrency :String,
@ignore
@optional
owners :List[String],
viewsToGenerate :List[String],
@ignore
@optional
bankRoutingScheme :String,
@ignore
@optional
bankRoutingAddress :String,
@ignore
@optional
branchRoutingScheme :String,
@ignore
@optional
branchRoutingAddress :String,
@ignore
@optional
accountRoutingScheme :String,
@ignore
@optional
accountRoutingAddress :String) extends InboundAccount
object InboundAccountCommons extends Converter[InboundAccount, InboundAccountCommons]
@ -267,9 +266,9 @@ case class BankCommons(
websiteUrl :String,
bankRoutingScheme :String,
bankRoutingAddress :String,
@ignore
@optional
swiftBic :String,
@ignore
@optional
nationalIdentifier :String) extends Bank {
def this(bankId :BankId,
shortName :String,
@ -635,19 +634,19 @@ case class SepaCreditTransfers( //This is from berlinGroup
)
case class TransactionRequestBodyAllTypes (
@ignore
@optional
to_sandbox_tan: Option[TransactionRequestAccount],
@ignore
@optional
to_sepa: Option[TransactionRequestIban],
@ignore
@optional
to_counterparty: Option[TransactionRequestCounterpartyId],
@ignore
@optional
to_transfer_to_phone: Option[TransactionRequestTransferToPhone] = None, //TODO not stable
@ignore
@optional
to_transfer_to_atm: Option[TransactionRequestTransferToAtm]= None,//TODO not stable
@ignore
@optional
to_transfer_to_account: Option[TransactionRequestTransferToAccount]= None,//TODO not stable
@ignore
@optional
to_sepa_credit_transfers: Option[SepaCreditTransfers]= None,//TODO not stable, from berlin Group
value: AmountOfMoney,
@ -675,29 +674,29 @@ case class TransactionRequest (
end_date: Date,
challenge: TransactionRequestChallenge,
charge: TransactionRequestCharge,
@ignore
@optional
charge_policy: String,
@ignore
@optional
counterparty_id :CounterpartyId,
@ignore
@optional
name :String,
@ignore
@optional
this_bank_id : BankId,
@ignore
@optional
this_account_id : AccountId,
@ignore
@optional
this_view_id :ViewId,
@ignore
@optional
other_account_routing_scheme : String,
@ignore
@optional
other_account_routing_address : String,
@ignore
@optional
other_bank_routing_scheme : String,
@ignore
@optional
other_bank_routing_address : String,
@ignore
@optional
is_beneficiary :Boolean,
@ignore
@optional
future_date :Option[String] = None
)
case class TransactionRequestBody (
@ -708,7 +707,7 @@ case class TransactionRequestBody (
case class Transaction(
//A universally unique id
@ignore
@optional
uuid: String,
//id is unique for transactions of @thisAccount
id : TransactionId,

View File

@ -184,7 +184,7 @@ object FiledRenameSerializer extends Serializer[JsonFieldReName] {
def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
case x: JsonFieldReName => {
val ignoreFieldNames = getObjAnnotedFields(x, ru.typeOf[ignore])
val ignoreFieldNames = getObjAnnotedFields(x, ru.typeOf[optional])
val renamedJFields = ReflectUtils.getConstructorArgs(x)
.filter(pair => !ignoreFieldNames.contains(pair._1))
.map(pair => {
@ -442,10 +442,6 @@ object MapperSerializer extends Serializer[Mapper[_]] {
override def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, json.JValue), Mapper[_]] = Functions.doNothing
}
@scala.annotation.meta.field
@scala.annotation.meta.param
class ignore extends scala.annotation.StaticAnnotation
@scala.annotation.meta.field
@scala.annotation.meta.param
class optional extends scala.annotation.StaticAnnotation