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

org.msgpack.template.builder.ScalaPropertyFinder.scala Maven / Gradle / Ivy

The newest version!
//
// MessagePack for Scala
//
// Copyright (C) 2009-2011 FURUHASHI Sadayuki
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
//
package org.msgpack.template.builder

import org.msgpack.template.FieldOption
import collection.immutable.ListMap
import org.msgpack.annotation.{NotNullable, Optional, Index, Ignore}
import java.lang.annotation.{ Annotation => JAnnotation}
import tools.scalap.scalax.rules.scalasig._
import java.lang.reflect.{Modifier, Field, Method, Type => JType, ParameterizedType}
import org.msgpack.scalautil.ScalaSigUtil

/**
 * Combination with java reflection and scalap.ScalaSigParser
 * User: takeshita
 * Create: 11/10/13 11:53
 */

trait ScalaPropertyFinder{

  self : AbstractTemplateBuilder =>

  type Property = (Method,Method,Field,MethodSymbol)
  type PropertySet = (String,Property)
  val SetterSuffix = "_$eq"

  override def toFieldEntries(targetClass: Class[_], from: FieldOption) : Array[FieldEntry] = {


    /*val sig = ScalaSigParser.parse(targetClass)
    
    val (setters,getters) = sig.get.symbols.collect({
      case m : MethodSymbol => {
        m.name -> m
      }
    }).partition(v => v._1.endsWith(SetterSuffix))

    val getterMap = getters.toMap

    val props = setters.map(s => s._1.substring(0,s._1.length - 4)).
      filter(fieldName => getterMap.contains(fieldName)).map(fieldName => {
      fieldName -> getterMap(fieldName)
    })*/

    val props = ScalaSigUtil.getAllPropGetters(targetClass)

    val propertySetSeq = toPropertySetSeq(targetClass,props)
    val indexed = indexing(propertySetSeq)

    indexed.map(convertToScalaFieldEntry(_))
  }


  def toPropertySetSeq(targetClass: Class[_],props : Seq[(String,MethodSymbol)]) : Seq[PropertySet] = {
    val methodMap = targetClass.getMethods().filter(isGetterOrSetter _).groupBy(_.getName)
    val fieldMap = targetClass.getDeclaredFields.map(f => f.getName -> f).toMap


    val propSets = props.map( p => {
      val getters = methodMap.get(p._1).map(_.toList).getOrElse(Nil)
      val setters = methodMap.get(p._1 + SetterSuffix).map(_.toList).getOrElse(Nil)
      if(getters.size < 1 || setters.size < 1){
        None
      }else if(getters.size == 1 && setters.size == 1){
        val getter = getters(0)
        val setter = setters(0)
        if(sameType_?(getter ,setter)){
          Some( p._1 -> (getter,setter,fieldMap.getOrElse(p._1,null),p._2))
        }else{
          None
        }
      }else {
        val validPairs = for(getter <- getters;
             setter <- setters if sameType_?(getter ,setter))
          yield p._1 -> (getter,setter,fieldMap.getOrElse(p._1,null),p._2)
        validPairs.headOption
      }
    }).collect({
      case Some(p) => p
    })

    propSets.filter( ps => {
      !hasAnnotation(ps,classOf[Ignore])
    })

  }

  def sameType_?(getter: Method, setter: Method) = {
    getter.getReturnType == setter.getParameterTypes()(0)
  }

  def isGetterOrSetter( method : Method) = {
    Modifier.isPublic(method.getModifiers) && !method.getName.startsWith("_") &&
    ( (
        method.getReturnType.getName == "void" &&
        method.getName.endsWith(SetterSuffix) &&
        method.getParameterTypes.length == 1
      ) || (
        method.getReturnType.getName != "void" &&
        method.getParameterTypes.length == 0
      ) )
  }


  def indexing(props: Seq[PropertySet]): Array[PropertySet] = {
    val indexed = new Array[PropertySet](props.size)

    var notIndexed: List[PropertySet] = Nil

    for (s <- props) {
      val i = getAnnotation(s, classOf[Index])
      if (i == null) {
        notIndexed = notIndexed :+ s
      } else {
        val index = i.value
        if (indexed(index) != null) {
          throw new TemplateBuildException("duplicated index: " + index);
        } else {
          try {
            indexed(index) = s
          } catch {
            case e: Exception => {
              throw new TemplateBuildException("invalid index: %s index must be 0 <= x < %s".format(index, indexed.length));
            }
          }
        }
      }
    }
    for (i <- 0 until indexed.length) {
      if (indexed(i) == null) {
        indexed(i) = notIndexed.head
        notIndexed = notIndexed.drop(1)
      }
    }


    indexed
  }

  def hasAnnotation[T <: JAnnotation](prop: PropertySet, classOfAnno: Class[T]): Boolean = {
    val getter = prop._2._1
    val setter = prop._2._2
    val field = prop._2._3
    getter.getAnnotation(classOfAnno) != null ||
      setter.getAnnotation(classOfAnno) != null || {
      if (field != null) field.getAnnotation(classOfAnno) != null
      else false
    }
  }

  def getAnnotation[T <: JAnnotation](prop: PropertySet, classOfAnno: Class[T]): T = {
    val getter = prop._2._1
    val setter = prop._2._2
    val field = prop._2._3



    val a = getter.getAnnotation(classOfAnno)
    if (a != null) {
      a
    } else {
      val b = setter.getAnnotation(classOfAnno)
      if (b != null) {
        b
      } else if (field != null) {
        field.getAnnotation(classOfAnno)
      } else {
        null.asInstanceOf[T]
      }
    }
  }

  def convertToScalaFieldEntry(propInfo: PropertySet) = {
    val getter = propInfo._2._1
    getter.getGenericReturnType match{
      case pt : ParameterizedType => {
        new ScalaFieldEntry(propInfo._1,
          readFieldOption(propInfo, FieldOption.DEFAULT),
          getter.getReturnType,
          ScalaSigUtil.getReturnType(propInfo._2._4).get,
          propInfo._2._1,
          propInfo._2._2
        )
      }
      case t if t.asInstanceOf[Class[_]].getName == "scala.Enumeration$Value" => {
        new ScalaFieldEntry(propInfo._1,
          readFieldOption(propInfo, FieldOption.DEFAULT),
          getter.getReturnType,
          ScalaSigUtil.getCompanionObjectClass(
            ScalaSigUtil.getReturnType(propInfo._2._4).get.asInstanceOf[Class[_]]).get,
          propInfo._2._1,
          propInfo._2._2
        )
      }
      case t => {
        new ScalaFieldEntry(propInfo._1,
          readFieldOption(propInfo, FieldOption.DEFAULT),
          getter.getReturnType,
          t,
          propInfo._2._1,
          propInfo._2._2
        )
      }
    }
  }

  def readValueType(prop: PropertySet) = {
    prop._2._1.getReturnType
  }

  def readFieldOption(prop: PropertySet, implicitOption: FieldOption) = {
    if (hasAnnotation(prop, classOf[Optional])) {
      FieldOption.OPTIONAL
    } else if (hasAnnotation(prop, classOf[NotNullable])) {
      FieldOption.NOTNULLABLE
    } else if (hasAnnotation(prop, classOf[Ignore])) {
      FieldOption.IGNORE
    } else {
      if (readValueType(prop).isPrimitive) {
        FieldOption.NOTNULLABLE
      } else {
        implicitOption
      }
    }

  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy