PageRenderTime 30ms CodeModel.GetById 19ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/scalate-util/src/main/scala/org/fusesource/scalate/util/Objects.scala

http://github.com/scalate/scalate
Scala | 89 lines | 44 code | 10 blank | 35 comment | 9 complexity | 5d258514aa80fc3797b8153f45f36196 MD5 | raw file
 1/**
 2 * Copyright (C) 2009-2011 the original author or authors.
 3 * See the notice.md file distributed with this work for additional
 4 * information regarding copyright ownership.
 5 *
 6 * Licensed under the Apache License, Version 2.0 (the "License");
 7 * you may not use this file except in compliance with the License.
 8 * You may obtain a copy of the License at
 9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18package org.fusesource.scalate.util
19
20import java.lang.reflect.Constructor
21import scala.reflect.ClassTag
22
23/**
24 * Helper object for working with objects using reflection
25 */
26object Objects {
27  val log = Log(getClass); import log._
28
29  /**
30   * A helper method to return a non null value or the default value if it is null
31   */
32  def getOrElse[T](value: T, defaultValue: => T) = if (value != null) value else defaultValue
33
34  /**
35   * Asserts that the given value is not null with a descriptive message
36   */
37  def notNull[T <: AnyRef](value: T, message: => String): T = {
38    if (value == null) {
39      throw new IllegalArgumentException(message)
40    }
41    value
42  }
43
44  def assertInjected[T <: AnyRef](value: T)(implicit m: ClassTag[T]): T = notNull(value, "Value of type " + m.runtimeClass.getName + " has not been injected!")
45
46  /**
47   * Instantiates the given object class using the possible list of values to be injected.
48   *
49   * Implements a really simple IoC mechanism. Ideally we'd improve this to support JSR330 style
50   * better injection with annotated injection points or such like
51   */
52  def instantiate[T](clazz: Class[T], injectionValues: List[AnyRef] = Nil): T =
53    tryInstantiate[T](clazz, injectionValues) match {
54      case Some(v) => v
55      case _ => throw new IllegalArgumentException("No valid constructor could be found for " + clazz.getName +
56        " and values: " + injectionValues)
57    }
58
59  /**
60   * Attempts to inject the given class if a constructor can be found
61   */
62  def tryInstantiate[T](clazz: Class[T], injectionValues: List[AnyRef] = Nil): Option[T] = {
63    def argumentValue(paramType: Class[_]): Option[AnyRef] =
64      injectionValues.find(paramType.isInstance(_))
65
66    def create(c: Constructor[_], args: Array[AnyRef]): T = {
67      val answer = if (args.isEmpty) {
68        clazz.getConstructor().newInstance()
69      } else {
70        debug("About to call constructor: %S on %s with args: %s", c, clazz.getName, args.toList)
71        c.newInstance(args: _*)
72      }
73      answer.asInstanceOf[T]
74    }
75
76    def tryCreate(c: Constructor[_]): Option[T] = {
77      val options = c.getParameterTypes.map(argumentValue(_))
78      if (options.forall(_.isDefined)) {
79        val args = options.map(_.get)
80        Some(create(c, args))
81      } else {
82        None
83      }
84    }
85
86    val constructors = clazz.getConstructors.sortBy(_.getParameterTypes.size * -1)
87    constructors.view.map(c => tryCreate(c)).find(_.isDefined).flatten
88  }
89}