Updated Branches:
  refs/heads/master 65696ea3b -> cb94abfcd

CRUNCH-77. Scala PObjects should contain values of Scala types, not Java types.

Signed-off-by: Josh Wills <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/incubator-crunch/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-crunch/commit/cb94abfc
Tree: http://git-wip-us.apache.org/repos/asf/incubator-crunch/tree/cb94abfc
Diff: http://git-wip-us.apache.org/repos/asf/incubator-crunch/diff/cb94abfc

Branch: refs/heads/master
Commit: cb94abfcd9776f84849a82472cc0c831a889cc6d
Parents: 65696ea
Author: Kiyan Ahmadizadeh <[email protected]>
Authored: Sun Sep 23 22:59:45 2012 -0700
Committer: Josh Wills <[email protected]>
Committed: Tue Sep 25 16:07:51 2012 -0700

----------------------------------------------------------------------
 .../org/apache/crunch/scrunch/LengthTest.scala     |   39 ---
 .../apache/crunch/scrunch/PCollectionTest.scala    |   72 ++++++
 .../org/apache/crunch/scrunch/PTableTest.scala     |   57 +++++
 .../org/apache/crunch/scrunch/PCollection.scala    |    4 +-
 .../apache/crunch/scrunch/PCollectionLike.scala    |    6 +-
 .../org/apache/crunch/scrunch/PGroupedTable.scala  |    2 +-
 .../scala/org/apache/crunch/scrunch/PObject.scala  |  191 +++++++++++++--
 .../scala/org/apache/crunch/scrunch/PTable.scala   |    5 +
 .../org/apache/crunch/scrunch/PObjectTest.scala    |  157 ++++++++++++
 9 files changed, 474 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-crunch/blob/cb94abfc/crunch-scrunch/src/it/scala/org/apache/crunch/scrunch/LengthTest.scala
----------------------------------------------------------------------
diff --git 
a/crunch-scrunch/src/it/scala/org/apache/crunch/scrunch/LengthTest.scala 
b/crunch-scrunch/src/it/scala/org/apache/crunch/scrunch/LengthTest.scala
deleted file mode 100644
index 20fb9a6..0000000
--- a/crunch-scrunch/src/it/scala/org/apache/crunch/scrunch/LengthTest.scala
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.apache.crunch.scrunch
-
-import org.apache.crunch.io.{From => from, To => to}
-import org.apache.crunch.test.CrunchTestSupport
-
-import org.scalatest.junit.JUnitSuite
-import _root_.org.junit.Test
-
-/**
- * Tests computing the number of elements in a PCollection from the Scala api.
- */
-class LengthTest extends CrunchTestSupport with JUnitSuite {
-
-  @Test def testLength {
-    val linesInShakespeare: Long = 3667
-    val pipeline = 
Pipeline.mapReduce[LengthTest](tempDir.getDefaultConfiguration)
-    val input = tempDir.copyResourceFileName("shakes.txt")
-
-    val len = pipeline.read(from.textFile(input)).length()
-    assert(linesInShakespeare == len.value())
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-crunch/blob/cb94abfc/crunch-scrunch/src/it/scala/org/apache/crunch/scrunch/PCollectionTest.scala
----------------------------------------------------------------------
diff --git 
a/crunch-scrunch/src/it/scala/org/apache/crunch/scrunch/PCollectionTest.scala 
b/crunch-scrunch/src/it/scala/org/apache/crunch/scrunch/PCollectionTest.scala
new file mode 100644
index 0000000..4c25298
--- /dev/null
+++ 
b/crunch-scrunch/src/it/scala/org/apache/crunch/scrunch/PCollectionTest.scala
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.crunch.scrunch
+
+import org.apache.crunch.io.{From => from, To => to}
+import org.apache.crunch.test.CrunchTestSupport
+
+import org.junit.Assert._
+import org.junit.Test
+import org.scalatest.junit.JUnitSuite
+
+/**
+ * Tests functionality of Scala PCollection.
+ */
+class PCollectionTest extends CrunchTestSupport with JUnitSuite {
+
+  // Number of lines in the Shakespeare data set.
+  val linesInShakespeare: Int = 3667
+
+  // The first line in the Shakespeare data set.
+  val firstLineInShakespeare: String =
+      "***The Project Gutenberg's Etext of Shakespeare's First Folio***"
+
+  // The last line in the Shakespeare data set.
+  val lastLineInShakespeare: String =
+      "FINIS. THE TRAGEDIE OF MACBETH."
+
+  /**
+   * Gets a PCollection containing the lines from the Shakespeare input text.
+   *
+   * @return The PCollection containing the test data set.
+   */
+  private def shakespeareCollection: PCollection[String] = {
+    val pipeline = 
Pipeline.mapReduce[PCollectionTest](tempDir.getDefaultConfiguration)
+    val input = tempDir.copyResourceFileName("shakes.txt")
+    pipeline.read(from.textFile(input))
+  }
+
+  /**
+   * Tests computing the number of elements in a PCollection via 
PCollection#length.
+   */
+  @Test def testLength {
+    val len = shakespeareCollection.length().value()
+    assertEquals("Wrong number of lines in Shakespeare.", linesInShakespeare, 
len)
+  }
+
+  /**
+   * Tests retrieving the contents of a PCollection as a Seq.
+   */
+  @Test def testAsSeq {
+    val lines = shakespeareCollection.asSeq().value()
+    assertEquals("Wrong number of lines in Shakespeare.", linesInShakespeare, 
lines.length)
+    assertEquals("Wrong first line in Shakespeare.", firstLineInShakespeare, 
lines(0))
+    assertEquals("Wrong last line in Shakespeare.", lastLineInShakespeare,
+        lines(linesInShakespeare - 1))
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-crunch/blob/cb94abfc/crunch-scrunch/src/it/scala/org/apache/crunch/scrunch/PTableTest.scala
----------------------------------------------------------------------
diff --git 
a/crunch-scrunch/src/it/scala/org/apache/crunch/scrunch/PTableTest.scala 
b/crunch-scrunch/src/it/scala/org/apache/crunch/scrunch/PTableTest.scala
new file mode 100644
index 0000000..cd644b1
--- /dev/null
+++ b/crunch-scrunch/src/it/scala/org/apache/crunch/scrunch/PTableTest.scala
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.crunch.scrunch
+
+import org.apache.crunch.io.{From => from, To => to}
+import org.apache.crunch.test.CrunchTestSupport
+
+import _root_.org.junit.Assert._
+import _root_.org.junit.Test
+import org.scalatest.junit.JUnitSuite
+
+/**
+ * Tests functionality of Scala PTable.
+ */
+class PTableTest extends CrunchTestSupport with JUnitSuite {
+
+  /**
+   * Gets a PCollection containing the lines from the tens data set.
+   *
+   * @return The PCollection containing the test data set.
+   */
+  private def tensCollection: PCollection[Int] = {
+    val pipeline = 
Pipeline.mapReduce[PTableTest](tempDir.getDefaultConfiguration)
+    val input = tempDir.copyResourceFileName("tens.txt")
+    pipeline.read(from.textFile(input)).map { line =>
+      Integer.parseInt(line)
+    }
+  }
+
+  /**
+   * Tests retrieving the contents of a PTable as a Map.
+   */
+  @Test def testAsSeq {
+    val tens = tensCollection
+    val tensCounts = tens.count().asMap().value()
+    assertEquals("Wrong map size for Map[Int, Long] obtained from count of 
tens collection.",
+        1, tensCounts.size)
+    assertTrue("Map of tens counts does not contain expected key.", 
tensCounts.contains(10))
+    assertEquals("Wrong count of tens.", 100L, tensCounts(10))
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-crunch/blob/cb94abfc/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PCollection.scala
----------------------------------------------------------------------
diff --git 
a/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PCollection.scala 
b/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PCollection.scala
index 04f2a56..89959ea 100644
--- a/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PCollection.scala
+++ b/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PCollection.scala
@@ -72,9 +72,9 @@ class PCollection[S](val native: JCollection[S]) extends 
PCollectionLike[S, PCol
     count.mapValues(_.longValue())
   }
 
-  def max() = PObject(Aggregate.max(native))
+  def max()(implicit converter: Converter[S, S]) = 
PObject(Aggregate.max(native))(converter)
 
-  def min() = PObject(Aggregate.min(native))
+  def min()(implicit converter: Converter[S, S]) = 
PObject(Aggregate.min(native))(converter)
 
   def pType = native.getPType()
 }

http://git-wip-us.apache.org/repos/asf/incubator-crunch/blob/cb94abfc/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PCollectionLike.scala
----------------------------------------------------------------------
diff --git 
a/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PCollectionLike.scala 
b/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PCollectionLike.scala
index 5aee5cf..f6441ac 100644
--- 
a/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PCollectionLike.scala
+++ 
b/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PCollectionLike.scala
@@ -49,9 +49,13 @@ trait PCollectionLike[S, +FullType, +NativeType <: 
JCollection[S]] {
    *
    * @return The number of elements in this PCollection.
    */
-  def length(): PObject[java.lang.Long] = {
+  def length(): PObject[Long] = {
     PObject(native.length())
   }
 
+  def asSeq(): PObject[Seq[S]] = {
+    PObject(native.asCollection())
+  }
+
   def getTypeFamily() = Avros
 }

http://git-wip-us.apache.org/repos/asf/incubator-crunch/blob/cb94abfc/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PGroupedTable.scala
----------------------------------------------------------------------
diff --git 
a/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PGroupedTable.scala 
b/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PGroupedTable.scala
index 248e926..7d890de 100644
--- 
a/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PGroupedTable.scala
+++ 
b/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PGroupedTable.scala
@@ -47,7 +47,7 @@ class PGroupedTable[K, V](val native: JGroupedTable[K, V])
   def combineValues(fn: CombineFn[K, V]) = new PTable[K, 
V](native.combineValues(fn))
 
   def ungroup() = new PTable[K, V](native.ungroup())
-  
+
   def wrap(newNative: AnyRef): PGroupedTable[K, V] = {
     new PGroupedTable[K, V](newNative.asInstanceOf[JGroupedTable[K, V]])
   }

http://git-wip-us.apache.org/repos/asf/incubator-crunch/blob/cb94abfc/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PObject.scala
----------------------------------------------------------------------
diff --git 
a/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PObject.scala 
b/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PObject.scala
index 5dcead4..299d76f 100644
--- a/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PObject.scala
+++ b/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PObject.scala
@@ -17,38 +17,197 @@
  */
 package org.apache.crunch.scrunch
 
+import java.lang.{Boolean => JBoolean}
+import java.lang.{Byte => JByte}
+import java.lang.{Character => JCharacter}
+import java.lang.{Double => JDouble}
+import java.lang.{Float => JFloat}
+import java.lang.{Integer => JInteger}
+import java.lang.{Long => JLong}
+import java.lang.{Short => JShort}
+import java.util.{Collection => JCollection}
+import java.util.{Map => JMap}
+
 import org.apache.crunch.{PObject => JPObject}
+import collection.JavaConversions
+
+/**
+ * Acts as a type class for conversions between two types.
+ *
+ * @tparam J The input type for the conversion.
+ * @tparam T The output type for the conversion.
+ */
+trait Converter[J, T] {
+  /**
+   * Converts a value from the input type to the output type.
+   *
+   * @param j The value to convert.
+   * @return The converted value.
+   */
+  def convert(j: J): T
+}
+
+/**
+ * Companion object that encapsulates the members of the Converter type class.
+ */
+object Converter {
+
+  /**
+   * Converts Java Byte to Scala Byte.
+   */
+  implicit object ByteConverter extends Converter[JByte, Byte] {
+    def convert(j: JByte) = Byte2byte(j)
+  }
+
+  /**
+   * Converts Java Short to Scala Short.
+   */
+  implicit object ShortConverter extends Converter[JShort, Short] {
+    def convert(j: JShort) = Short2short(j)
+  }
+
+  /**
+   * Converts Java Integer to Scala Int.
+   */
+  implicit object IntegerConverter extends Converter[JInteger, Int] {
+    def convert(j: JInteger) = Integer2int(j)
+  }
+
+  /**
+   * Converts Java Long to Scala Long.
+   */
+  implicit object LongConverter extends Converter[JLong, Long] {
+    def convert(j: JLong) = Long2long(j)
+  }
+
+  /**
+   * Converts Java Float to Scala Float.
+   */
+  implicit object FloatConverter extends Converter[JFloat, Float] {
+    def convert(j: JFloat) = Float2float(j)
+  }
+
+  /**
+   * Converts Java Double to Scala Double.
+   */
+  implicit object DoubleConverter extends Converter[JDouble, Double] {
+    def convert(j: JDouble) = Double2double(j)
+  }
+
+  /**
+   * Converts Java Boolean to Scala Boolean.
+   */
+  implicit object BooleanConverter extends Converter[JBoolean, Boolean] {
+    def convert(j: JBoolean) = Boolean2boolean(j)
+  }
+
+  /**
+   * Converts Java Character to Scala Char.
+   */
+  implicit object CharacterConverter extends Converter[JCharacter, Char] {
+    def convert(j: JCharacter) = Character2char(j)
+  }
+
+  /**
+   * An implicit function that knows how to construct Converters from 
java.util.Collection[S]
+   * to Seq[S].
+   *
+   * @tparam S The type contained in the collection to be converted.
+   * @tparam T The type of collection.
+   * @return A converter from the Collection[S] to the Seq[S].
+   */
+  implicit def collectionConverter[S, T <: JCollection[S]] =
+    new Converter[JCollection[S], Seq[S]] {
+      def convert(j: JCollection[S]) = 
JavaConversions.collectionAsScalaIterable(j).toSeq
+    }
+
+  /**
+   * An implicit function that knows how to construct Converters from 
java.util.Map[K, V]
+   * to Map[K, V].
+   *
+   * @tparam K The key type of the Map to be converted.
+   * @tparam V The value type of the Map to be converted.
+   * @tparam T The type of Map to be converted.
+   * @return A converter from java.util.Map[K, V] to Map[K, V].
+   */
+  implicit def mapConverter[K, V, T <: JMap[K, V]] =
+    new Converter[JMap[K, V], Map[K, V]] {
+      def convert(j: JMap[K, V]) = JavaConversions.mapAsScalaMap(j).toMap
+    }
+
+  /**
+   * An implicit function that knows how to construct identity Converters.
+   *
+   * @tparam T The type to be converted.
+   * @return An identity converter.
+   */
+  implicit def identityConverter[T] = new Converter[T, T] {
+    def convert(t: T) = t
+  }
+}
+
+/**
+ * A trait for classes that use a Converter.
+ */
+trait Convert {
+  def convert[J, T](j: J)(implicit converter: Converter[J, T]): T = 
converter.convert(j)
+}
 
 /**
  * Represents a singleton value that results from a distributed computation.
  *
- * @param native The Java PObject that backs this Scala PObject.
  * @tparam T The type of value encapsulated by this PObject.
  */
-class PObject[T] private (private val native: JPObject[T]) {
+trait PObject[T] {
   /**
-   * Gets the value associated with this PObject.  Calling this method will 
trigger
-   * whatever computation is necessary to obtain the value and block until 
that computation
-   * succeeds.
+   * @return The value of this PObject.
    *
-   * @return The value associated with this PObject.
    */
-  def value(): T = {
-    native.getValue()
-  }
+  def value(): T
 }
 
 /**
- * The companion object for PObject that provides factory methods for creating 
PObjects.
+ * An implementation of PObject whose value is obtained by applying a 
conversion to the value
+ * obtained from a JPObject.
+ *
+ * @param native The backing Java PObject.
+ * @param converter A converter from the Java value type to the Scala value 
type.
+ * @tparam J The type of value encapsulated by the backing Java PObject.
+ * @tparam T The type of value encapsulated by this Scala PObject.
  */
-protected[scrunch] object PObject {
+private[scrunch] class
+    JPObjectWrapper[J, T](private val native: JPObject[J])(implicit val 
converter: Converter[J, T])
+    extends PObject[T] with Convert {
 
+  // Acts as a cache for the converted value.
+  private var converted: Option[T] = None
+
+  /**
+   * Gets the value of this PObject by converting the value of the backing 
Java PObject.
+   *
+   * @return The value of this PObject.
+   */
+  override final def value(): T =
+    converted.getOrElse{
+      converted = Some(convert(native.getValue())(converter))
+      converted.get
+    }
+}
+
+/**
+ * The companion object for PObject that provides factory methods for creating 
PObjects.
+ */
+private[scrunch] object PObject {
   /**
-   * Creates a new Scala PObject from a Java PObject.
+   * Creates a Scala PObject given a Java PObject.
    *
-   * @param native The Java PObject that will back this Scala PObject.
-   * @tparam T The type of value encapsulated by the PObject.
-   * @return A Scala PObject backed by the Java PObject specified.
+   * @param native The Java PObject to use when creating the Scala PObject.
+   * @param converter A converter for the value type of the Java PObject to 
the value type of the
+   *     Scala PObject.
+   * @tparam J The type of value encapsulated by the Java PObject.
+   * @tparam T The type of value encapsulated by the Scala PObject.
+   * @return The Scala PObject.
    */
-  def apply[T](native: JPObject[T]): PObject[T] = new PObject[T](native)
+  def apply[J, T](native: JPObject[J])(implicit converter: Converter[J, T]): 
PObject[T] =
+    new JPObjectWrapper[J, T](native)
 }

http://git-wip-us.apache.org/repos/asf/incubator-crunch/blob/cb94abfc/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PTable.scala
----------------------------------------------------------------------
diff --git 
a/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PTable.scala 
b/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PTable.scala
index 4b157d3..5775262 100644
--- a/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PTable.scala
+++ b/crunch-scrunch/src/main/scala/org/apache/crunch/scrunch/PTable.scala
@@ -25,6 +25,7 @@ import org.apache.crunch.{DoFn, Emitter, FilterFn, MapFn}
 import org.apache.crunch.{GroupingOptions, PTable => JTable, Pair => CPair}
 import org.apache.crunch.lib.{Join, Cartesian, Aggregate, Cogroup, PTables}
 import org.apache.crunch.scrunch.interpreter.InterpreterRunner
+import java.util
 
 class PTable[K, V](val native: JTable[K, V]) extends PCollectionLike[CPair[K, 
V], PTable[K, V], JTable[K, V]] {
   import PTable._
@@ -139,6 +140,10 @@ class PTable[K, V](val native: JTable[K, V]) extends 
PCollectionLike[CPair[K, V]
     native.materializeToMap().view.toMap
   }
 
+  def asMap(): PObject[Map[K, V]] = {
+    PObject(native.asMap())
+  }
+
   def keyType() = native.getPTableType().getKeyType()
 
   def valueType() = native.getPTableType().getValueType()

http://git-wip-us.apache.org/repos/asf/incubator-crunch/blob/cb94abfc/crunch-scrunch/src/test/scala/org/apache/crunch/scrunch/PObjectTest.scala
----------------------------------------------------------------------
diff --git 
a/crunch-scrunch/src/test/scala/org/apache/crunch/scrunch/PObjectTest.scala 
b/crunch-scrunch/src/test/scala/org/apache/crunch/scrunch/PObjectTest.scala
new file mode 100644
index 0000000..06a93f6
--- /dev/null
+++ b/crunch-scrunch/src/test/scala/org/apache/crunch/scrunch/PObjectTest.scala
@@ -0,0 +1,157 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.crunch.scrunch
+
+import java.lang.{Boolean => JBoolean}
+import java.lang.{Byte => JByte}
+import java.lang.{Character => JCharacter}
+import java.lang.{Double => JDouble}
+import java.lang.{Float => JFloat}
+import java.lang.{Integer => JInteger}
+import java.lang.{Long => JLong}
+import java.lang.{Short => JShort}
+import java.util.{ArrayList => JArrayList}
+import java.util.{HashMap => JHashMap}
+import java.util.{Collection => JCollection}
+import java.util.{Map => JMap}
+
+import org.apache.crunch.{PObject => JPObject}
+import org.junit.Assert._
+import org.junit.Test
+import org.scalatest.junit.JUnitSuite
+
+/**
+ * Provides tests for converting Java PObjects to Scala PObjects.
+ */
+class PObjectTest extends JUnitSuite {
+
+  /**
+   * Constructs a Java PObject that returns the specified value.
+   *
+   * @param value The value the Java PObject should return.
+   * @tparam T The type of the value.
+   * @return A Java PObject encapsulating the specified value.
+   */
+  private def getJPObject[T](value: T): JPObject[T] = {
+    new JPObject[T] {
+      override def getValue: T = value
+    }
+  }
+
+  /**
+   * Tests converting a JPObject containing a JBoolean to a Scala PObject 
containing a Boolean.
+   */
+  @Test def testJBoolean2Boolean() {
+    val value: Boolean = PObject[JBoolean, 
Boolean](getJPObject(JBoolean.TRUE)).value()
+    assertEquals("Wrong value for PObject of Boolean", true, value)
+  }
+
+  /**
+   * Tests converting a JPObject containing a JByte to a Scala PObject 
containing a Byte.
+   */
+  @Test def testJByte2Byte() {
+    val value: Byte = PObject[JByte, 
Byte](getJPObject(JByte.MAX_VALUE)).value()
+    assertEquals("Wrong value for PObject of Byte", Byte.MaxValue, value)
+  }
+
+  /**
+   * Tests converting a JPObject containing a JCharacter to a Scala PObject 
containing a Char.
+   */
+  @Test def testJCharacter2Char() {
+    val value: Char = PObject[JCharacter, Char](getJPObject(new 
JCharacter('c'))).value()
+    assertEquals("Wrong value for PObject of Character", 'c', value)
+  }
+
+  /**
+   * Tests converting a JPObject containing a JDouble to a Scala PObject 
containing a Double.
+   */
+  @Test def testJDouble2Double() {
+    val value: Double = PObject[JDouble, Double](getJPObject(new 
JDouble(5.0))).value()
+    assertEquals("Wrong value for PObject of Double", 5.0D, value, 0.0D)
+  }
+
+  /**
+   * Tests converting a JPObject containing a JFloat to a Scala PObject 
containing a Float.
+   */
+  @Test def testJFloat2Float() {
+    val value: Float = PObject[JFloat, Float](getJPObject(new 
JFloat(5.0))).value()
+    assertEquals("Wrong value for PObject of Float", 5.0F, value, 0.0F)
+  }
+
+  /**
+   * Tests converting a JPObject containing a JShort to a Scala PObject 
containing a Short.
+   */
+  @Test def testJShort2Short() {
+    val value: Short = PObject[JShort, 
Short](getJPObject(JShort.MAX_VALUE)).value()
+    assertEquals("Wrong value for PObject of Short", Short.MaxValue, value)
+  }
+
+  /**
+   * Tests converting a JPObject containing a JInteger to a Scala PObject 
containing a Int.
+   */
+  @Test def testJInt2Int() {
+    val value: Int = PObject[JInteger, Int](getJPObject(new 
JInteger(5))).value()
+    assertEquals("Wrong value for PObject of Integer", 5, value)
+  }
+
+  /**
+   * Tests converting a JPObject containing a JLong to a Scala PObject 
containing a Long.
+   */
+  @Test def testJLong2Long() {
+    val value: Long = PObject[JLong, Long](getJPObject(new JLong(5L))).value()
+    assertEquals("Wrong value for PObject of Long", 5L, value)
+  }
+
+  /**
+   * Tests converting a JPObject containing a JCollection to a Scala PObject 
containing a Seq.
+   */
+  @Test def testJCollection2Seq() {
+    val list = new JArrayList[Int]()
+    list.add(1)
+    list.add(2)
+    list.add(3)
+
+    val jCollect: JCollection[Int] = list
+    val value: Seq[Int] = PObject[JCollection[Int], 
Seq[Int]](getJPObject(jCollect)).value()
+    assertEquals("Wrong size for PObject of Seq", 3, value.length)
+    assertTrue("PObject of Seq contains wrong elements.", value.contains(1))
+    assertTrue("PObject of Seq contains wrong elements.", value.contains(2))
+    assertTrue("PObject of Seq contains wrong elements.", value.contains(3))
+  }
+
+  /**
+   * Tests converting a JPObject containing a JMap to a Scala PObject 
containing a Map.
+   */
+  @Test def testJMap2Map() {
+    val hashMap = new JHashMap[String, Int]()
+    hashMap.put("hello", 1)
+    hashMap.put("beautiful", 2)
+    hashMap.put("world", 3)
+
+    val jMap: JMap[String, Int] = hashMap
+    val value: Map[String, Int] =
+        PObject[JMap[String, Int], Map[String, Int]](getJPObject(jMap)).value()
+    assertEquals("Wrong size for PObject of Map", 3, value.size)
+    assertTrue("PObject of Map contains wrong keys.", value.contains("hello"))
+    assertTrue("PObject of Map contains wrong keys.", 
value.contains("beautiful"))
+    assertTrue("PObject of Map contains wrong keys.", value.contains("world"))
+    assertEquals("PObject of Map contains wrong values.", 1, value("hello"))
+    assertEquals("PObject of Map contains wrong values.", 2, 
value("beautiful"))
+    assertEquals("PObject of Map contains wrong values.", 3, value("world"))
+  }
+}

Reply via email to