![JAR search and dependency download from the Maven repository](/logo.png)
org.beangle.commons.bean.Properties.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of beangle-commons Show documentation
Show all versions of beangle-commons Show documentation
The Beangle Commons Library
The newest version!
/*
* 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.bean
import org.beangle.commons.collection.Collections
import org.beangle.commons.conversion.Conversion
import org.beangle.commons.conversion.impl.DefaultConversion
import org.beangle.commons.lang.Strings
import org.beangle.commons.lang.reflect.TypeInfo.OptionType
import org.beangle.commons.lang.reflect.{BeanInfo, BeanInfos, TypeInfo}
import org.beangle.commons.logging.Logging
import java.lang.reflect.Array as Jarray
import scala.reflect.ClassTag
object Properties {
private val Default = new Properties(DefaultConversion.Instance)
def set(bean: AnyRef, propertyName: String, value: Any): Any = Default.set(bean, propertyName, value)
def get[T: ClassTag](inputBean: Any, propertyName: String): T = Default.get[T](inputBean, propertyName)
def copy(bean: AnyRef, propertyName: String, value: Any): Any = Default.copy(bean, propertyName, value)
def copy(bean: AnyRef, beanInfo: BeanInfo, propertyName: String, value: Any): Any = {
Default.copy(bean, beanInfo, propertyName, value)
}
def isWriteable(bean: AnyRef, name: String): Boolean = Default.isWriteable(bean, name)
def getType(clazz: Class[_], name: String): Class[_] = Default.getType(clazz, name)
def writables(clazz: Class[_]): Set[String] = Default.writables(clazz)
}
class Properties(conversion: Conversion) extends Logging {
private val resolver = new PropertyNameResolver()
@throws(classOf[NoSuchMethodException])
def set(bean: AnyRef, propertyName: String, value: Any): Any = {
if isMapType(bean) then
copy(bean, null, propertyName, value, null)
else
copy(bean, BeanInfos.get(bean.getClass), propertyName, value, null)
}
def get[T: ClassTag](inputBean: Any, propertyName: String): T = {
var result = inputBean
var name = propertyName
while (resolver.hasNested(name)) {
val next = resolver.next(name)
result =
if (isMapType(result)) getPropertyOfMap(result, next)
else if (resolver.isMapped(next)) getMappedProperty(result, next)
else if (resolver.isIndexed(next)) getIndexedProperty(result, next)
else getSimpleProperty(result, next)
if (null != result && result.isInstanceOf[Option[_]])
result = result.asInstanceOf[Option[_]].orNull
if (null == result) return null.asInstanceOf[T]
name = resolver.remove(name)
}
result =
if (isMapType(result)) getPropertyOfMap(result, name)
else if (resolver.isMapped(name)) getMappedProperty(result, name)
else if (resolver.isIndexed(name)) getIndexedProperty(result, name)
else getSimpleProperty(result, name)
result.asInstanceOf[T]
}
def copy(bean: AnyRef, propertyName: String, value: Any): Any =
copy(bean, BeanInfos.get(bean.getClass), propertyName, value, this.conversion)
def copy(bean: AnyRef, beanInfo: BeanInfo, propertyName: String, value: Any): Any =
copy(bean, beanInfo, propertyName, value, this.conversion)
def isWriteable(bean: AnyRef, name: String): Boolean =
BeanInfos.get(bean.getClass).getSetter(name).isDefined
def getType(clazz: Class[_], name: String): Class[_] =
BeanInfos.get(clazz).getPropertyType(name).orNull
def writables(clazz: Class[_]): Set[String] =
BeanInfos.get(clazz).writables.keySet
private def copy(bean: AnyRef, beanInfo: BeanInfo, propertyName: String, value: Any, conversion: Conversion): Any = {
var result: Any = bean
var name = propertyName
var currentBeanInfo = beanInfo
while (resolver.hasNested(name)) {
val next = resolver.next(name)
result = getDirectProperty(result, next)
if (null != result && result.isInstanceOf[Option[_]])
result = result.asInstanceOf[Option[_]].orNull
if (result == null) throw new RuntimeException("Null property value for '" + name + "' on bean class '" + bean.getClass + "'")
val nextTypeInfo = currentBeanInfo.getPropertyTypeInfo(next).get
val nextClazz = nextTypeInfo match {
case OptionType(elementType) => elementType.clazz
case _ => nextTypeInfo.clazz
}
currentBeanInfo = BeanInfos.get(nextClazz)
name = resolver.remove(name)
}
if (isMapType(result)) {
setPropertyOfMapBean(result, name, value)
value
} else if (resolver.isMapped(name)) {
copyMappedProperty(result, currentBeanInfo, name, value)
value
} else if (resolver.isIndexed(name)) {
copyIndexedProperty(result, currentBeanInfo, name, value, conversion)
} else
copySimpleProperty(result, currentBeanInfo, name, value, conversion)
}
private def getDirectProperty(result: Any, name: String): Any = {
if (isMapType(result)) getPropertyOfMap(result, name)
else if (resolver.isMapped(name)) getMappedProperty(result, name)
else if (resolver.isIndexed(name)) getIndexedProperty(result, name)
else getSimpleProperty(result, name)
}
private def getSimpleProperty(bean: Any, name: String): Any =
BeanInfos.get(bean.getClass).getGetter(name) match {
case Some(method) => method.invoke(bean)
case _ =>
logger.error("Cannot find " + Strings.capitalize(name) + " Getter in " + bean.getClass)
null
}
private def getPropertyOfMap(bean: Any, propertyName: String): Any = {
var name = resolver.getProperty(propertyName)
if name == null || name.isEmpty then name = resolver.getKey(propertyName)
else name = propertyName
getMapped(bean, name)
}
private def getMappedProperty(bean: Any, name: String): Any = {
val key = resolver.getKey(name)
if (key == null)
throw new IllegalArgumentException("Invalid mapped property '" + name + "'")
val value = getSimpleProperty(bean, resolver.getProperty(name))
if (null == value) null else getMapped(value, key)
}
private def getIndexedProperty(bean: Any, name: String): Any = {
val index = resolver.getIndex(name)
if (index < 0)
throw new IllegalArgumentException("Invalid indexed property '" + name + "'")
val value = getSimpleProperty(bean, resolver.getProperty(name))
if (null == value) return null
if (value.getClass.isArray) Jarray.get(value, index) else getIndexed(value, index)
}
private def copySimpleProperty(bean: Any, beanInfo: BeanInfo, name: String, value: Any, conversion: Conversion): Any = {
beanInfo.getSetter(name) match {
case Some(method) =>
val p = beanInfo.properties(name)
val converted = convert(value, p.clazz, p.typeinfo, conversion)
method.invoke(bean, converted.asInstanceOf[Object])
converted
case _ => null
}
}
private def copyIndexedProperty(bean: Any, beanInfo: BeanInfo, name: String, value: Any, conversion: Conversion): Any = {
var index = -1
try
index = resolver.getIndex(name)
catch {
case e: IllegalArgumentException =>
throw new IllegalArgumentException("Invalid indexed property '" + name + "' on bean class '" + bean.getClass + "'")
}
if (index < 0) throw new IllegalArgumentException("Invalid indexed property '" + name
+ "' on bean class '" + bean.getClass + "'")
// Isolate the name
val resolvedName = resolver.getProperty(name)
val rs = if (resolvedName != null && resolvedName.length() >= 0) getSimpleProperty(bean, resolvedName) else bean
var converted = value
if (rs.getClass.isArray) {
converted = convert(value, rs.getClass.getComponentType, null, conversion)
Jarray.set(rs, index, value)
} else
setIndexed(rs, index, value)
converted
}
private def getMappedKey(name: String, bean: Any): String = {
var key: String = null
try
key = resolver.getKey(name)
catch {
case e: IllegalArgumentException =>
throw new IllegalArgumentException("Invalid mapped property '" + name + "' on bean class '" + bean.getClass + "'")
}
if (key == null) throw new IllegalArgumentException("Invalid mapped property '" + name
+ "' on bean class '" + bean.getClass + "'")
key
}
private def convert(value: Any, clazz: Class[_], typeInfo: TypeInfo, conversion: Conversion): Any =
if (typeInfo.isOptional) {
if null == value then None
else if value.isInstanceOf[Option[_]] then value
else if null != typeInfo then
if (null == conversion) Option(value) else Option(conversion.convert(value, typeInfo.args.head.clazz))
else Option(value)
} else if (null == conversion) {
value
} else {
conversion.convert(value, clazz)
}
private def copyMappedProperty(bean: Any, beanInfo: BeanInfo, name: String, value: Any): Unit = {
val key = getMappedKey(name, bean)
val resolvedName = resolver.getProperty(name)
val rs = if (resolvedName != null && resolvedName.length() >= 0) getSimpleProperty(bean, resolvedName) else bean
val typeInfo = beanInfo.getPropertyTypeInfo(resolvedName).get
val key1 = conversion.convert(key, typeInfo.args.head.clazz)
val value1 = conversion.convert(value, typeInfo.args.tail.head.clazz)
setMapped(rs, key1, value1)
}
private def setPropertyOfMapBean(bean: Any, propertyName: String, value: Any): Unit = {
var pname = propertyName
if (resolver.isMapped(propertyName)) {
val name = resolver.getProperty(propertyName)
if (name == null || name.length() == 0)
pname = resolver.getKey(propertyName)
}
if (resolver.isIndexed(pname) || resolver.isMapped(pname)) throw new IllegalArgumentException(
"Indexed or mapped properties are not supported on" + " objects of type Map: " + pname)
setMapped(bean, pname, value)
}
private def getIndexed(bean: Any, index: Int): Any =
bean match {
case null => null
case s: collection.Seq[_] => s(index)
case x: java.util.List[_] => x.get(index)
case _ => throw new RuntimeException("Don't support getIndexed on " + bean.getClass)
}
private def setIndexed(bean: Any, index: Int, value: Any): Unit =
bean match {
case null =>
case s: collection.mutable.Seq[_] => s.asInstanceOf[collection.mutable.Seq[Any]].update(index, value)
case x: java.util.List[_] => x.asInstanceOf[java.util.List[Any]].set(index, value)
case _ => throw new RuntimeException("Don't support setIndexed on " + bean.getClass)
}
private def setMapped(bean: Any, key: Any, value: Any): Unit =
bean match {
case null =>
case s: collection.mutable.Map[_, _] => s.asInstanceOf[collection.mutable.Map[Any, Any]].put(key, value)
case x: java.util.Map[_, _] => x.asInstanceOf[java.util.Map[Any, Any]].put(key, value)
case _ => throw new RuntimeException("Don't support setMapped on " + bean.getClass)
}
private def getMapped(bean: Any, key: Any): Any =
bean match {
case null => null
case s: collection.Map[_, _] =>
if s.isEmpty then null
else s.get(conversion.convert(key, s.head._1.getClass)).orNull
case x: java.util.Map[_, _] =>
if x.isEmpty then null
else x.get(conversion.convert(key, x.keySet().iterator().next().getClass))
case i: Iterable[Any] =>
var sep = ","
var ekey = key.toString
val sepIdx = ekey.indexOf('#')
if (sepIdx > 0) {
sep = ekey.substring(sepIdx + 1)
ekey = ekey.substring(0, sepIdx)
}
val nested = Collections.newBuffer[String]
i foreach { e =>
val v = this.get[Any](e, ekey)
if (null != v) nested.addOne(String.valueOf(v))
}
nested.mkString(sep)
case _ => throw new RuntimeException("Don't support getMapped on " + bean.getClass)
}
private def isMapType(obj: Any): Boolean =
obj.isInstanceOf[collection.mutable.Map[_, _]] || obj.isInstanceOf[java.util.Map[_, _]]
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy