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

org.beangle.commons.conversion.impl.AbstractGenericConversion.scala Maven / Gradle / Ivy

/*
 * Copyright (C) 2005, The Beangle Software.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 */

package org.beangle.commons.conversion.impl

import org.beangle.commons.conversion.{Conversion, Converter, ConverterRegistry}
import org.beangle.commons.lang.{Objects, Primitives}

import java.lang.reflect.{Array, Modifier}
import scala.collection.{concurrent, mutable}
import scala.language.existentials

/** Generic Conversion Super class
  * It provider converter registry and converter search machanism.
  *
  * @author chaostone
  * @since 3.2.0
  */
abstract class AbstractGenericConversion extends Conversion with ConverterRegistry {

  val converters = new mutable.HashMap[Class[_], Map[Class[_], GenericConverter]]

  val cache = new concurrent.TrieMap[Tuple2[Class[_], Class[_]], GenericConverter]

  /** Convert to target type.
    */
  override def convert[T](source: Any, target: Class[T]): T = {
    if (null == source) return Objects.default(target)
    val sourceClazz = Primitives.wrap(source.getClass)
    val targetClazz = Primitives.wrap(target)

    if (targetClazz.isAssignableFrom(sourceClazz)) return source.asInstanceOf[T]

    if (sourceClazz.isArray && targetClazz.isArray) {
      val sourceObjType = Primitives.wrap(sourceClazz.getComponentType)
      val targetObjClazz = targetClazz.getComponentType
      val targetObjType = Primitives.wrap(targetObjClazz)
      val converter = findConverter(sourceObjType, targetObjType)
      if null == converter then Array.newInstance(targetObjClazz, 0).asInstanceOf[T]
      else
        val length = Array.getLength(source)
        val result = Array.newInstance(targetObjClazz, length).asInstanceOf[T]
        for (i <- 0 until length) Array.set(result, i, converter.convert(Array.get(source, i), targetObjType))
        result
    } else {
      val converter = findConverter(sourceClazz, targetClazz)
      val rs = converter.convert(source, targetClazz).asInstanceOf[T]
      if (null == rs && target.isPrimitive) Objects.default(target) else rs
    }
  }

  override def addConverter(converter: Converter[_, _]): Unit = {
    var key: (Class[_], Class[_]) = null
    for (m <- converter.getClass.getMethods if m.getName == "apply" && Modifier.isPublic(m.getModifiers) && !m.isBridge())
      key = (m.getParameterTypes()(0), m.getReturnType)
    if (null == key) throw new IllegalArgumentException("Cannot find convert type pair " + converter.getClass)
    val sourceType = key._1
    val adapter = new ConverterAdapter(converter, key)
    converters.get(sourceType) match {
      case Some(existed) => converters += (sourceType -> (existed + (key._2 -> adapter)))
      case _ => converters += (sourceType -> Map((key._2 -> adapter)))
    }
    cache.clear()
  }

  protected def addConverter(converter: GenericConverter): Unit = {
    val key = converter.getTypeinfo
    val sourceType = key._1
    converters.get(sourceType) match {
      case Some(existed) =>
        converters += (key._1 -> (existed + (key._2 -> converter)))
      case _ => converters += (key._1 -> Map((key._2 -> converter)))
    }
    cache.clear()
  }

  protected def findConverter(sourceType: Class[_], targetType: Class[_]): GenericConverter = {
    val key = (sourceType, targetType)
    var converter = cache.get(key).orNull
    if (null == converter) converter = searchConverter(sourceType, targetType)
    if (null == converter) converter = NoneConverter
    else cache.put(key, converter)
    converter
  }

  protected def searchConverter(sourceType: Class[_], targetType: Class[_]): GenericConverter = {
    val interfaces = new mutable.LinkedHashSet[Class[_]]
    val classQueue = new mutable.Queue[Class[_]]
    classQueue += sourceType
    while (classQueue.nonEmpty) {
      val currentClass = classQueue.dequeue()
      val converter = getConverter(targetType, getConverters(currentClass))
      if (converter != null) return converter
      val superClass = currentClass.getSuperclass
      if (superClass != null && superClass != classOf[AnyRef]) classQueue += superClass
      for (interfaceType <- currentClass.getInterfaces) addInterfaces(interfaceType, interfaces)
    }
    val iter = interfaces.iterator
    while (iter.hasNext) {
      val interfaceType = iter.next()
      val converter = getConverter(targetType, getConverters(interfaceType))
      if (converter != null) return converter
    }
    getConverter(targetType, getConverters(classOf[AnyRef]))
  }

  private def getConverters(sourceType: Class[_]) = converters.get(sourceType).getOrElse(Map.empty)

  private def getConverter(targetType: Class[_], converters: Map[Class[_], GenericConverter]): GenericConverter = {
    val interfaces = new mutable.LinkedHashSet[Class[_]]
    val queue = new mutable.Queue[Class[_]]()
    queue += targetType
    while (queue.nonEmpty) {
      val cur = queue.dequeue()
      val converter = converters.get(cur).orNull
      if (converter != null) return converter
      val superClass = cur.getSuperclass
      if (superClass != null && superClass != classOf[AnyRef]) queue += superClass
      for (interfaceType <- cur.getInterfaces) addInterfaces(interfaceType, interfaces)
    }
    val iter = interfaces.iterator
    while (iter.hasNext) {
      val interfaceType = iter.next()
      val converter = converters.get(interfaceType).orNull
      if (converter != null) return converter
    }
    null
  }

  private def addInterfaces(interfaceType: Class[_], interfaces: mutable.Set[Class[_]]): Unit = {
    interfaces.add(interfaceType)
    for (inheritedInterface <- interfaceType.getInterfaces) addInterfaces(inheritedInterface, interfaces)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy