All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alpine.common.serialization.json.InterfaceAdapter.scala Maven / Gradle / Ivy

package com.alpine.common.serialization.json

import java.lang.reflect.{ParameterizedType, Type}

import com.google.gson._
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl

/**
 * For serializing/deserializing arbitrary interface types.
 * From stackoverflow with some modifications to handle generic
 * interfaces.
 */
class InterfaceAdapter[T](classLoaderUtil: Option[_ <: ClassLoaderUtil] = None)
  extends JsonSerializer[T] with JsonDeserializer[T] {

  private val helper = new ClassSerializer(classLoaderUtil)

  def serialize(`object`: T, interfaceType: Type, context: JsonSerializationContext): JsonElement = {
    val wrapper: JsonObject = new JsonObject
    val rawType = `object`.getClass
    val completeType: Type = getCompleteType(rawType, interfaceType)
    val typeSerialization: String = helper.getKeyForType(`object`.getClass)
    wrapper.addProperty(JsonUtil.typeKey, typeSerialization)
    wrapper.add(JsonUtil.dataKey, context.serialize(`object`, completeType))
    wrapper
  }

  def deserialize(elem: JsonElement, interfaceType: Type, context: JsonDeserializationContext): T = {
    val wrapper: JsonObject = elem.asInstanceOf[JsonObject]
    val typeName: JsonElement = get(wrapper, JsonUtil.typeKey)
    val data: JsonElement = get(wrapper, JsonUtil.dataKey)
    val rawType = helper.getTypeForKey(typeName.getAsString)
    val completeType: Type = getCompleteType(rawType, interfaceType)
    context.deserialize(data, completeType)
  }

  /**
   * Takes parameter types from the interfaceType (if it is parameterized), and attaches them to the rawType.
   */
  private def getCompleteType(rawType: Class[_], interfaceType: Type): Type = {
    if (interfaceType.isInstanceOf[ParameterizedType]) {
      ParameterizedTypeImpl.make(rawType, interfaceType.asInstanceOf[ParameterizedType].getActualTypeArguments, null)
    } else {
      rawType
    }
  }

  private def get(wrapper: JsonObject, memberName: String): JsonElement = {
    val elem: JsonElement = wrapper.get(memberName)
    if (elem == null) {
      throw new JsonParseException("no '" + memberName + "' member found in what was expected to be an interface wrapper")
    }
    elem
  }
}

object InterfaceAdapter {

  def apply[T](classLoaderUtil: ClassLoaderUtil) = {
    new InterfaceAdapter[T](Some(classLoaderUtil))
  }
}

trait ClassLoaderUtil {
  def getExportTypeClassLoader(className: String) : Option[ClassLoader]
}

private class ClassSerializer(classLoaderUtil: Option[ClassLoaderUtil]) {

  @throws(classOf[JsonParseException])
  def getTypeForKey(x: String): Class[_] = {
    try {
      Class.forName(x)
    }
    catch {
      case e: ClassNotFoundException =>
        val className: String = x
        var clazz: Class[_] = null
        if (classLoaderUtil.nonEmpty) {
          val classLoader: Option[ClassLoader] = classLoaderUtil.get.getExportTypeClassLoader(className)
          if (classLoader.isDefined) {
            try {
              clazz = classLoader.get.loadClass(className)
            }
            catch {
              case e2: ClassNotFoundException =>
                throw new JsonParseException(e2)
            }
          }
        }
        if (clazz == null) {
          throw new JsonParseException(e)
        }
        clazz
    }
  }

  def getKeyForType(t: Class[_]): String = {
    t.getName
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy