mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 13:07:02 +00:00
Merge remote-tracking branch 'Hongwei/develop' into develop
This commit is contained in:
commit
460d0f3c6c
@ -8,7 +8,7 @@
|
||||
<groupId>com.tesobe</groupId>
|
||||
<artifactId>obp-parent</artifactId>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<artifactId>obp-api</artifactId>
|
||||
<packaging>war</packaging>
|
||||
|
||||
@ -828,4 +828,8 @@ dynamic_endpoints_url_prefix=dynamic
|
||||
# Note: The user is also refreshed after every login.
|
||||
# You can also explicitly refresh the user using the refresh user endpoint.
|
||||
# refresh_user.interval=30
|
||||
# --------------------------------------------------------------------
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
## Inbound and Outbound ignore field names
|
||||
inbound.ignore.fields=
|
||||
outbound.ignore.fields=outboundAdapterCallContext.generalContext,outboundAdapterCallContext.outboundAdapterAuthInfo.linkedCustomers,outboundAdapterCallContext.outboundAdapterAuthInfo.authViews,outboundAdapterCallContext.outboundAdapterAuthInfo.authViews.view,outboundAdapterCallContext.outboundAdapterAuthInfo.authViews.account,outboundAdapterCallContext.outboundAdapterAuthInfo.authViews.view,outboundAdapterCallContext.outboundAdapterAuthInfo.authViews.account,inboundAdapterCallContext.generalContext
|
||||
|
||||
@ -8,13 +8,20 @@ import code.api.cache.Caching
|
||||
import code.api.util.ApiRole.rolesMappedToClasses
|
||||
import code.api.v3_1_0.ListResult
|
||||
import code.util.Helper.MdcLoggable
|
||||
import code.util.JsonUtils
|
||||
import com.openbankproject.commons.util.Functions.Memo
|
||||
import com.openbankproject.commons.util._
|
||||
import com.tesobe.CacheKeyFromArguments
|
||||
import net.liftweb.json
|
||||
import net.liftweb.json.JsonAST.JValue
|
||||
import net.liftweb.json.{TypeInfo, _}
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
|
||||
import scala.collection.immutable.List
|
||||
import scala.concurrent.duration._
|
||||
import scala.reflect.ManifestFactory
|
||||
import scala.reflect.runtime.universe
|
||||
import scala.reflect.runtime.universe._
|
||||
|
||||
trait CustomJsonFormats {
|
||||
implicit val formats: Formats = CustomJsonFormats.formats
|
||||
@ -184,5 +191,58 @@ object JNothingSerializer extends Serializer[Any] with MdcLoggable {
|
||||
}
|
||||
}
|
||||
|
||||
object FieldIgnoreSerializer extends Serializer[AnyRef] {
|
||||
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
|
||||
|
||||
|
||||
override def serialize(implicit format: Formats): PartialFunction[Any, json.JValue] = {
|
||||
case x if isInOutBoundType(x) =>
|
||||
val ignoreFieldNames: List[String] = getIgnores(ReflectUtils.getType(x)) ::: propsConfigIgnoreFields
|
||||
val zson = json.Extraction.decompose(x)(CustomJsonFormats.formats)
|
||||
ignoreFieldNames match {
|
||||
case Nil => zson
|
||||
case ignores => JsonUtils.deleteFields(zson, ignores)
|
||||
}
|
||||
}
|
||||
|
||||
private def isInOutBoundType(any: Any) = {
|
||||
if(ReflectUtils.isObpObject(any)) {
|
||||
val className = any.getClass.getSimpleName
|
||||
className.startsWith("OutBound") || className.startsWith("InBound")
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
def getIgnores(tp: universe.Type): List[String] = {
|
||||
if(!ReflectUtils.isObpType(tp)) {
|
||||
return Nil
|
||||
}
|
||||
memo.memoize(tp, it => {
|
||||
val fields: List[universe.Symbol] = it.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 subAnnotedFieldNames = notIgnoreFields.flatMap(it => {
|
||||
val fieldName = it.name.decodedName.toString.trim
|
||||
val fieldType: universe.Type = it.info match {
|
||||
case x if x <:< typeOf[Iterable[_]] && !(x <:< typeOf[Map[_,_]]) =>
|
||||
x.typeArgs.head
|
||||
case x if x <:< typeOf[Array[_]] =>
|
||||
x.typeArgs.head
|
||||
case x => x
|
||||
}
|
||||
|
||||
getIgnores(fieldType)
|
||||
.map(it => s"$fieldName.$it")
|
||||
})
|
||||
annotedFieldNames ++ subAnnotedFieldNames
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ import java.util.Date
|
||||
import java.util.regex.Pattern
|
||||
|
||||
import code.actorsystem.ObpActorConfig
|
||||
import code.api.util.{APIUtil, ApiPropsWithAlias, CustomJsonFormats}
|
||||
import code.api.util.{APIUtil, ApiPropsWithAlias, CustomJsonFormats, FieldIgnoreSerializer}
|
||||
import code.api.util.APIUtil.{MessageDoc, getPropsValue}
|
||||
import code.api.v1_2_1.BankRoutingJsonV121
|
||||
import com.openbankproject.commons.model.{AccountRoutingJsonV121, AmountOfMoneyJsonV121}
|
||||
@ -368,7 +368,7 @@ case class CustomerViewJsonV220(
|
||||
|
||||
|
||||
|
||||
object JSONFactory220 extends CustomJsonFormats {
|
||||
object JSONFactory220 {
|
||||
|
||||
def stringOrNull(text : String) =
|
||||
if(text == null || text.isEmpty)
|
||||
@ -847,6 +847,8 @@ object JSONFactory220 extends CustomJsonFormats {
|
||||
MessageDocsJson(messageDocsList.map(createMessageDocJson))
|
||||
}
|
||||
|
||||
private implicit val formats = CustomJsonFormats.formats + FieldIgnoreSerializer
|
||||
|
||||
def createMessageDocJson(md: MessageDoc): MessageDocJson = {
|
||||
val inBoundType = ReflectUtils.getType(md.exampleInboundMessage)
|
||||
|
||||
|
||||
@ -522,4 +522,36 @@ object JsonUtils {
|
||||
case _: JArray => typeOf[JArray]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* delete a group of field, field can be nested.
|
||||
* @param jValue
|
||||
* @param fields
|
||||
* @return a new JValue that not contains given fields.
|
||||
*/
|
||||
def deleteFields(jValue: JValue, fields: List[String]) = fields match {
|
||||
case Nil => jValue
|
||||
case x => x.foldLeft(jValue)(deleteField)
|
||||
}
|
||||
|
||||
/**
|
||||
* delete one field, the field can be nested, e.g: "foo.bar.barzz"
|
||||
* @param jValue
|
||||
* @param fieldName
|
||||
* @return a new JValue that not contains given field.
|
||||
*/
|
||||
def deleteField(jValue:JValue, fieldName: String): JValue = jValue match {
|
||||
case JNull | JNothing => jValue
|
||||
case _: JObject =>
|
||||
if(!fieldName.contains(".")) {
|
||||
jValue.removeField(_.name == fieldName)
|
||||
} else {
|
||||
val Array(field, nestedField) = StringUtils.split(fieldName, ".", 2)
|
||||
jValue.transformField {
|
||||
case JField(name, value) if name == field => JField(name, deleteField(value, nestedField))
|
||||
}
|
||||
}
|
||||
case JArray(arr) => JArray(arr.map(deleteField(_, fieldName)))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<groupId>com.tesobe</groupId>
|
||||
<artifactId>obp-parent</artifactId>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<artifactId>obp-commons</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@ -63,6 +63,24 @@ object Functions {
|
||||
coll.filterNot(it => it.isInstanceOf[Array[_]] || it.isInstanceOf[GenTraversableOnce[_]])
|
||||
}
|
||||
|
||||
/**
|
||||
* momoize function, to avoid re calculate values
|
||||
* @tparam A key
|
||||
* @tparam R cached value
|
||||
*/
|
||||
class Memo[A, R] {
|
||||
private val cache = new java.util.concurrent.atomic.AtomicReference(Map[A, R]())
|
||||
|
||||
def memoize(x: A, f: A => R): R = {
|
||||
val c = cache.get
|
||||
def addToCache() = {
|
||||
val ret = f(x)
|
||||
cache.set(c + (x -> ret))
|
||||
ret
|
||||
}
|
||||
c.getOrElse(x, addToCache)
|
||||
}
|
||||
}
|
||||
|
||||
// implicit functions place in this object
|
||||
object Implicits {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user