summaryrefslogtreecommitdiff
path: root/src/compiler/scala/reflect/runtime/ScalaToJava.scala
blob: b1e4d6224cc96dbcbd13e27d27405573be6598b3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package scala.reflect
package runtime

import java.lang.{Class => jClass, Package => jPackage}
import java.lang.reflect.{
  Method => jMethod, Constructor => jConstructor, Modifier => jModifier, Field => jField,
  Member => jMember, Type => jType, Array => jArray, GenericDeclaration}

trait ScalaToJava extends ConversionUtil { self: SymbolTable =>

  import definitions._

  /** Optionally, the Java package corresponding to a given Scala package, or None if no such Java package exists.
   *  @param   pkg The Scala package
   */
  def packageToJava(pkg: Symbol): Option[jPackage] = packageCache.toJavaOption(pkg) {
    Option(jPackage.getPackage(pkg.fullName.toString))
  }

  /** The Java class corresponding to given Scala class.
   *  Note: This only works for
   *   - top-level classes
   *   - Scala classes that were generated via jclassToScala
   *   - classes that have a class owner that has a corresponding Java class
   *  @throws A `ClassNotFoundException` for all Scala classes not in one of these categories.
   */
  @throws(classOf[ClassNotFoundException])
  def classToJava(clazz: Symbol): jClass[_] = classCache.toJava(clazz) {
    def noClass = throw new ClassNotFoundException("no Java class corresponding to "+clazz+" found")
    //println("classToJava "+clazz+" "+clazz.owner+" "+clazz.owner.isPackageClass)//debug
    if (clazz.isValueClass)
      clazz match {
        case UnitClass => java.lang.Void.TYPE
        case ByteClass => java.lang.Byte.TYPE
        case CharClass => java.lang.Character.TYPE
        case ShortClass => java.lang.Short.TYPE
        case IntClass => java.lang.Integer.TYPE
        case LongClass => java.lang.Long.TYPE
        case FloatClass => java.lang.Float.TYPE
        case DoubleClass => java.lang.Double.TYPE
        case BooleanClass => java.lang.Boolean.TYPE
      }
    else if (clazz == ArrayClass)
      noClass
    else if (clazz.owner.isPackageClass)
      javaClass(clazz.javaClassName)
    else if (clazz.owner.isClass)
      classToJava(clazz.owner)
        .getDeclaredClasses
        .find(_.getSimpleName == clazz.name.toString)
        .getOrElse(noClass)
    else
      noClass
  }

  private def expandedName(sym: Symbol): String =
    if (sym.isPrivate) nme.expandedName(sym.name, sym.owner).toString
    else sym.name.toString

  def fieldToJava(fld: Symbol): jField = fieldCache.toJava(fld) {
    val jclazz = classToJava(fld.owner)
    try jclazz getDeclaredField fld.name.toString
    catch {
      case ex: NoSuchFieldException => jclazz getDeclaredField expandedName(fld)
    }
  }

  def methodToJava(meth: Symbol): jMethod = methodCache.toJava(meth) {
    val jclazz = classToJava(meth.owner)
    val paramClasses = transformedType(meth).paramTypes map typeToJavaClass
    try jclazz getDeclaredMethod (meth.name.toString, paramClasses: _*)
    catch {
      case ex: NoSuchMethodException =>
        jclazz getDeclaredMethod (expandedName(meth), paramClasses: _*)
    }
  }

  def constrToJava(constr: Symbol): jConstructor[_] = constructorCache.toJava(constr) {
    val jclazz = classToJava(constr.owner)
    val paramClasses = transformedType(constr).paramTypes map typeToJavaClass
    jclazz getConstructor (paramClasses: _*)
  }

  private def jArrayClass(elemClazz: jClass[_]): jClass[_] = {
    jArray.newInstance(elemClazz, 0).getClass
  }

  /** The Java class that corresponds to given Scala type.
   *  Pre: Scala type is already transformed to Java level.
   */
  def typeToJavaClass(tpe: Type): jClass[_] = tpe match {
    case ExistentialType(_, rtpe) => typeToJavaClass(rtpe)
    case TypeRef(_, ArrayClass, List(elemtpe)) => jArrayClass(typeToJavaClass(elemtpe))
    case TypeRef(_, sym, _) => classToJava(sym)
    case _ => throw new NoClassDefFoundError("no Java class corresponding to "+tpe+" found")
  }
}