diff --git a/obp-api/pom.xml b/obp-api/pom.xml index 8cb326447..a3d760481 100644 --- a/obp-api/pom.xml +++ b/obp-api/pom.xml @@ -31,7 +31,7 @@ com.github.OpenBankProject.OBP-Adapter-Akka-SpringBoot adapter-akka-commons - develop-SNAPSHOT + v1.1.0 * diff --git a/obp-api/src/main/resources/props/sample.props.template b/obp-api/src/main/resources/props/sample.props.template index 7215e64ea..58c26d39d 100644 --- a/obp-api/src/main/resources/props/sample.props.template +++ b/obp-api/src/main/resources/props/sample.props.template @@ -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 diff --git a/obp-api/src/main/resources/props/test.default.props.template b/obp-api/src/main/resources/props/test.default.props.template index 5a9047f3f..8844926d5 100644 --- a/obp-api/src/main/resources/props/test.default.props.template +++ b/obp-api/src/main/resources/props/test.default.props.template @@ -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 diff --git a/obp-api/src/main/scala/code/api/util/CustomJsonFormats.scala b/obp-api/src/main/scala/code/api/util/CustomJsonFormats.scala index 546d90756..49d544a26 100644 --- a/obp-api/src/main/scala/code/api/util/CustomJsonFormats.scala +++ b/obp-api/src/main/scala/code/api/util/CustomJsonFormats.scala @@ -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 diff --git a/obp-api/src/main/scala/code/api/v2_2_0/JSONFactory2.2.0.scala b/obp-api/src/main/scala/code/api/v2_2_0/JSONFactory2.2.0.scala index 48e3906bc..559722fe1 100644 --- a/obp-api/src/main/scala/code/api/v2_2_0/JSONFactory2.2.0.scala +++ b/obp-api/src/main/scala/code/api/v2_2_0/JSONFactory2.2.0.scala @@ -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) diff --git a/obp-api/src/main/scala/code/bankconnectors/ConnectorUtils.scala b/obp-api/src/main/scala/code/bankconnectors/ConnectorUtils.scala index aca113b77..31ea6ba64 100644 --- a/obp-api/src/main/scala/code/bankconnectors/ConnectorUtils.scala +++ b/obp-api/src/main/scala/code/bankconnectors/ConnectorUtils.scala @@ -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 diff --git a/obp-api/src/main/scala/code/bankconnectors/storedprocedure/MSsqlStoredProcedureBuilder.scala b/obp-api/src/main/scala/code/bankconnectors/storedprocedure/MSsqlStoredProcedureBuilder.scala index 4fb8494e6..1b81824a9 100644 --- a/obp-api/src/main/scala/code/bankconnectors/storedprocedure/MSsqlStoredProcedureBuilder.scala +++ b/obp-api/src/main/scala/code/bankconnectors/storedprocedure/MSsqlStoredProcedureBuilder.scala @@ -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)) diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala index 3d207da76..e391198ce 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala @@ -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 ) diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModel.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModel.scala index 71b4eb3a9..f0604ef38 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModel.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/CommonModel.scala @@ -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, diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/util/JsonSerializers.scala b/obp-commons/src/main/scala/com/openbankproject/commons/util/JsonSerializers.scala index 18de6f324..169fe3c8b 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/util/JsonSerializers.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/util/JsonSerializers.scala @@ -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 \ No newline at end of file