Merge remote-tracking branch 'Hongwei/develop' into develop

This commit is contained in:
hongwei 2020-07-02 09:21:39 +02:00
commit 460d0f3c6c
8 changed files with 122 additions and 6 deletions

View File

@ -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>

View File

@ -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

View File

@ -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
})
}
}

View File

@ -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)

View File

@ -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)))
}
}

View File

@ -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>

View File

@ -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 {

View File

@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.tesobe</groupId>
<artifactId>obp-parent</artifactId>
<version>1.5.2</version>
<version>1.5.3</version>
<packaging>pom</packaging>
<name>Open Bank Project API Parent</name>
<inceptionYear>2011</inceptionYear>