diff --git a/.travis.yml b/.travis.yml index 30adc7477..a894b4cb2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: scala sudo: false scala: - - 2.10.4 - - 2.11.2 + - 2.10.5 + - 2.11.5 diff --git a/CHANGES.md b/CHANGES.md index 7b379d49e..0a444b81b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,15 @@ # Bijection # +### 0.8.1 +* Simplifies hbase injections with fastAttempt macro: https://github.com/twitter/bijection/pull/220 +* Specialize the TBinaryProtocol read path up to ~2x speedups: https://github.com/twitter/bijection/pull/221 +* Makes some of the hbase injection tests stricter: https://github.com/twitter/bijection/pull/219 +* Migrates hbase bijections to injections because they weren't actually bijections: https://github.com/twitter/bijection/pull/217 +* Removes unnecessary HBase injections: https://github.com/twitter/bijection/pull/215 +* Fixes flaky test: https://github.com/twitter/bijection/pull/214 +* Fixup unidoc: https://github.com/twitter/bijection/pull/213 +* Update travis & sbt scala versions to 2.10.5 and 2.11.5: https://github.com/twitter/bijection/pull/212 + ### 0.8.0 * add twitter util Buf <-> Array[Byte] bijection https://github.com/twitter/bijection/pull/208 * upgrade testing libraries https://github.com/twitter/bijection/pull/207 diff --git a/README.md b/README.md index 9dfc35ac8..c8a0337e3 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ Discussion occurs primarily on the [Bijection mailing list](https://groups.googl ## Maven -Bijection modules are available on maven central. The current groupid and version for all modules is, respectively, `"com.twitter"` and `0.8.0`. +Bijection modules are available on maven central. The current groupid and version for all modules is, respectively, `"com.twitter"` and `0.8.1`. Current published artifacts are diff --git a/bijection-finagle-mysql/src/test/scala/com/twitter/bijection/finagle_mysql/MySqlConversionLaws.scala b/bijection-finagle-mysql/src/test/scala/com/twitter/bijection/finagle_mysql/MySqlConversionLaws.scala index 0199f7344..3b484b37d 100644 --- a/bijection-finagle-mysql/src/test/scala/com/twitter/bijection/finagle_mysql/MySqlConversionLaws.scala +++ b/bijection-finagle-mysql/src/test/scala/com/twitter/bijection/finagle_mysql/MySqlConversionLaws.scala @@ -97,10 +97,11 @@ class MySqlConversionLaws extends CheckProperties with BaseProperties { isInjection[NullValue.type, Option[String]] } property("Timestamp") { - /** Custom equivalence typeclass for RawValue - * This is here to compare two RawValues generated from Timestamps. - * Because they contain byte arrays, just =='ing them does not work as expected. - */ + /** + * Custom equivalence typeclass for RawValue + * This is here to compare two RawValues generated from Timestamps. + * Because they contain byte arrays, just =='ing them does not work as expected. + */ implicit val valueEquiv = new scala.math.Equiv[Value] { override def equiv(a: Value, b: Value) = (a, b) match { case (RawValue(Type.Timestamp, Charset.Binary, true, bytes1), diff --git a/bijection-hbase/src/main/scala/com/twitter/bijection/hbase/HBaseBijections.scala b/bijection-hbase/src/main/scala/com/twitter/bijection/hbase/HBaseBijections.scala deleted file mode 100644 index e3c52f1eb..000000000 --- a/bijection-hbase/src/main/scala/com/twitter/bijection/hbase/HBaseBijections.scala +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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 com.twitter.bijection.hbase - -import com.twitter.bijection._ -import org.apache.hadoop.hbase.util.Bytes -import org.apache.hadoop.hbase.io.ImmutableBytesWritable -import scala.annotation.implicitNotFound - -/** - * Provides various HBase specific Bijections by wrapping org.apache.hadoop.hbase.util.Bytes - * @author Muhammad Ashraf - * @since 7/9/13 - */ -object HBaseBijections { - /** Byte Representation of a String value */ - type StringBytes = Array[Byte] @@ Rep[String] - - /** Byte Representation of a Long value */ - type LongBytes = Array[Byte] @@ Rep[Long] - - /** Byte Representation of a Boolean value */ - type BooleanBytes = Array[Byte] @@ Rep[Boolean] - - /** Byte Representation of a Int value */ - type IntBytes = Array[Byte] @@ Rep[Int] - - /** Byte Representation of a Double value */ - type DoubleBytes = Array[Byte] @@ Rep[Double] - - /** Byte Representation of a Float value */ - type FloatBytes = Array[Byte] @@ Rep[Float] - - /** Byte Representation of a Short value */ - type ShortBytes = Array[Byte] @@ Rep[Short] - - /** Byte Representation of a BigDecimal value */ - type BigDecimalBytes = Array[Byte] @@ Rep[BigDecimal] - - implicit lazy val string2Bytes: Bijection[String, StringBytes] = - new AbstractBijection[String, StringBytes] { - def apply(str: String) = Tag[Array[Byte], Rep[String]](Bytes.toBytes(str)) - - override def invert(bytes: StringBytes) = Bytes.toString(bytes) - } - - implicit lazy val long2Bytes: Bijection[Long, LongBytes] = - new AbstractBijection[Long, LongBytes] { - def apply(input: Long) = Tag[Array[Byte], Rep[Long]](Bytes.toBytes(input)) - - override def invert(bytes: LongBytes) = Bytes.toLong(bytes) - } - - implicit lazy val boolean2Bytes: Bijection[Boolean, BooleanBytes] = - new AbstractBijection[Boolean, BooleanBytes] { - def apply(input: Boolean) = Tag[Array[Byte], Rep[Boolean]](Bytes.toBytes(input)) - - override def invert(bytes: BooleanBytes) = Bytes.toBoolean(bytes) - } - - implicit lazy val int2Bytes: Bijection[Int, IntBytes] = - new AbstractBijection[Int, IntBytes] { - def apply(input: Int) = Tag[Array[Byte], Rep[Int]](Bytes.toBytes(input)) - - override def invert(bytes: IntBytes) = Bytes.toInt(bytes) - } - - implicit lazy val float2Bytes: Bijection[Float, FloatBytes] = - new AbstractBijection[Float, FloatBytes] { - def apply(input: Float) = Tag[Array[Byte], Rep[Float]](Bytes.toBytes(input)) - - override def invert(bytes: FloatBytes) = Bytes.toFloat(bytes) - } - - implicit lazy val short2Bytes: Bijection[Short, ShortBytes] = - new AbstractBijection[Short, ShortBytes] { - def apply(input: Short) = Tag[Array[Byte], Rep[Short]](Bytes.toBytes(input)) - - override def invert(bytes: ShortBytes) = Bytes.toShort(bytes) - } - - implicit lazy val double2Bytes: Bijection[Double, DoubleBytes] = - new AbstractBijection[Double, DoubleBytes] { - def apply(input: Double) = Tag[Array[Byte], Rep[Double]](Bytes.toBytes(input)) - - override def invert(bytes: DoubleBytes) = Bytes.toDouble(bytes) - } - - implicit lazy val bigdecimal2Bytes: Bijection[BigDecimal, BigDecimalBytes] = - new AbstractBijection[BigDecimal, BigDecimalBytes] { - def apply(input: BigDecimal) = Tag[Array[Byte], Rep[BigDecimal]](Bytes.toBytes(input.underlying())) - - override def invert(bytes: BigDecimalBytes) = Bytes.toBigDecimal(bytes) - } - - implicit lazy val string2BytesWritable = ImmutableBytesWritableBijection[String] - implicit lazy val int2BytesWritable = ImmutableBytesWritableBijection[Int] - implicit lazy val long2BytesWritable = ImmutableBytesWritableBijection[Long] - implicit lazy val double2BytesWritable = ImmutableBytesWritableBijection[Double] - implicit lazy val float2BytesWritable = ImmutableBytesWritableBijection[Float] - implicit lazy val short2BytesWritable = ImmutableBytesWritableBijection[Short] - implicit lazy val boolean2BytesWritable = ImmutableBytesWritableBijection[Boolean] - implicit lazy val bigDecimal2BytesWritable = ImmutableBytesWritableBijection[BigDecimal] - implicit lazy val bytes2BytesWritable = new AbstractBijection[Array[Byte], ImmutableBytesWritable] { - override def apply(a: Array[Byte]): ImmutableBytesWritable = new ImmutableBytesWritable(a) - - override def invert(b: ImmutableBytesWritable): Array[Byte] = b.get() - } - - object ImmutableBytesWritableBijection { - def apply[T](implicit bijection: Bijection[T, Array[Byte] @@ Rep[T]]) = new ImmutableBytesWritableBijection[T](bijection) - } - - class ImmutableBytesWritableBijection[@specialized T](bijection: Bijection[T, Array[Byte] @@ Rep[T]]) extends Bijection[T, ImmutableBytesWritable] { - def apply(a: T): ImmutableBytesWritable = new ImmutableBytesWritable(bijection(a)) - - override def invert(b: ImmutableBytesWritable): T = bijection.invert(Tag[Array[Byte], Rep[T]](b.get())) - } - -} diff --git a/bijection-hbase/src/main/scala/com/twitter/bijection/hbase/HBaseInjections.scala b/bijection-hbase/src/main/scala/com/twitter/bijection/hbase/HBaseInjections.scala index 7a1001314..e872f8099 100644 --- a/bijection-hbase/src/main/scala/com/twitter/bijection/hbase/HBaseInjections.scala +++ b/bijection-hbase/src/main/scala/com/twitter/bijection/hbase/HBaseInjections.scala @@ -14,31 +14,98 @@ package com.twitter.bijection.hbase -import HBaseBijections._ -import com.twitter.bijection._ -import Injection._ +import com.twitter.bijection.AbstractInjection +import com.twitter.bijection.Injection +import com.twitter.bijection.macros.Macros.fastAttempt +import com.twitter.bijection.Tag import org.apache.hadoop.hbase.io.ImmutableBytesWritable +import org.apache.hadoop.hbase.util.Bytes +import scala.util.Try +import scala.util.Success /** + * Provides various HBase specific Injections by wrapping org.apache.hadoop.hbase.util.Bytes * @author Mansur Ashraf * @since 9/10/13 */ object HBaseInjections { + import Injection.buildCatchInvert - implicit lazy val string2BytesInj: Injection[String, StringBytes] = fromBijectionRep[String, StringBytes] - implicit lazy val long2BytesInj: Injection[Long, LongBytes] = fromBijectionRep[Long, LongBytes] - implicit lazy val boolean2BytesInj: Injection[Boolean, BooleanBytes] = fromBijectionRep[Boolean, BooleanBytes] - implicit lazy val int2BytesInj: Injection[Int, IntBytes] = fromBijectionRep[Int, IntBytes] - implicit lazy val float2BytesInj: Injection[Float, FloatBytes] = fromBijectionRep[Float, FloatBytes] - implicit lazy val short2BytesInj: Injection[Short, ShortBytes] = fromBijectionRep[Short, ShortBytes] - implicit lazy val double2BytesInj: Injection[Double, DoubleBytes] = fromBijectionRep[Double, DoubleBytes] - implicit lazy val bigdecimal2BytesInj: Injection[BigDecimal, BigDecimalBytes] = fromBijectionRep[BigDecimal, BigDecimalBytes] - implicit lazy val string2BytesWritableInj: Injection[String, ImmutableBytesWritable] = fromBijectionRep[String, ImmutableBytesWritable] - implicit lazy val int2BytesWritableInj: Injection[Int, ImmutableBytesWritable] = fromBijectionRep[Int, ImmutableBytesWritable] - implicit lazy val long2BytesWritableInj: Injection[Long, ImmutableBytesWritable] = fromBijectionRep[Long, ImmutableBytesWritable] - implicit lazy val double2BytesWritableInj: Injection[Double, ImmutableBytesWritable] = fromBijectionRep[Double, ImmutableBytesWritable] - implicit lazy val float2BytesWritableInj: Injection[Float, ImmutableBytesWritable] = fromBijectionRep[Float, ImmutableBytesWritable] - implicit lazy val short2BytesWritableInj: Injection[Short, ImmutableBytesWritable] = fromBijectionRep[Short, ImmutableBytesWritable] - implicit lazy val boolean2BytesWritableInj: Injection[Boolean, ImmutableBytesWritable] = fromBijectionRep[Boolean, ImmutableBytesWritable] - implicit lazy val bigDecimal2BytesWritableInj: Injection[BigDecimal, ImmutableBytesWritable] = fromBijectionRep[BigDecimal, ImmutableBytesWritable] + // Array[Byte] injections + implicit lazy val string2BytesInj: Injection[String, Array[Byte]] = + buildCatchInvert[String, Array[Byte]](Bytes.toBytes)(Bytes.toString) + implicit lazy val long2BytesInj: Injection[Long, Array[Byte]] = + buildCatchInvert[Long, Array[Byte]](Bytes.toBytes)(Bytes.toLong) + implicit lazy val boolean2BytesInj: Injection[Boolean, Array[Byte]] = + buildCatchInvert[Boolean, Array[Byte]](Bytes.toBytes)(Bytes.toBoolean) + implicit lazy val int2BytesInj: Injection[Int, Array[Byte]] = + buildCatchInvert[Int, Array[Byte]](Bytes.toBytes)(Bytes.toInt) + implicit lazy val float2BytesInj: Injection[Float, Array[Byte]] = + buildCatchInvert[Float, Array[Byte]](Bytes.toBytes)(Bytes.toFloat) + implicit lazy val short2BytesInj: Injection[Short, Array[Byte]] = + buildCatchInvert[Short, Array[Byte]](Bytes.toBytes)(Bytes.toShort) + implicit lazy val double2BytesInj: Injection[Double, Array[Byte]] = + buildCatchInvert[Double, Array[Byte]](Bytes.toBytes)(Bytes.toDouble) + implicit lazy val bigDecimal2BytesInj: Injection[BigDecimal, Array[Byte]] = + new AbstractInjection[BigDecimal, Array[Byte]] { + override def apply(a: BigDecimal) = Bytes.toBytes(a.underlying) + override def invert(b: Array[Byte]) = Try(Bytes.toBigDecimal(b)).map(BigDecimal(_)) + } + + /** + * ImmutableBytesWritable injections avoid copying when possible and use the + * slice (offset and length) of the underlying byte array. + */ + implicit lazy val string2BytesWritableInj = + new ImmutableBytesWritableInjection[String] { + override def invert(b: ImmutableBytesWritable) = + fastAttempt(b)(Bytes.toString(b.get, b.getOffset, b.getLength) match { + case null => sys.error(s"$b decoded to null, which is disallowed.") + case str => str + }) + } + implicit lazy val int2BytesWritableInj = + new ImmutableBytesWritableInjection[Int] { + override def invert(b: ImmutableBytesWritable) = + fastAttempt(b)(Bytes.toInt(b.get, b.getOffset, b.getLength)) + } + implicit lazy val long2BytesWritableInj = + new ImmutableBytesWritableInjection[Long] { + override def invert(b: ImmutableBytesWritable) = + fastAttempt(b)(Bytes.toLong(b.get, b.getOffset, b.getLength)) + } + implicit lazy val double2BytesWritableInj = + new ImmutableBytesWritableInjection[Double] { + override def invert(b: ImmutableBytesWritable) = + fastAttempt(b)(Bytes.toDouble(b.get, b.getOffset)) + } + implicit lazy val float2BytesWritableInj = + new ImmutableBytesWritableInjection[Float] { + override def invert(b: ImmutableBytesWritable) = + fastAttempt(b)(Bytes.toFloat(b.get, b.getOffset)) + } + implicit lazy val short2BytesWritableInj = + new ImmutableBytesWritableInjection[Short] { + override def invert(b: ImmutableBytesWritable) = + fastAttempt(b)(Bytes.toShort(b.get, b.getOffset, b.getLength)) + } + implicit lazy val boolean2BytesWritableInj = + new ImmutableBytesWritableInjection[Boolean] { + override def invert(b: ImmutableBytesWritable) = + fastAttempt(b)(Bytes.toBoolean(b.copyBytes)) + } + implicit lazy val bigDecimal2BytesWritableInj = + new ImmutableBytesWritableInjection[BigDecimal] { + override def invert(b: ImmutableBytesWritable) = + fastAttempt(b)(Bytes.toBigDecimal(b.get, b.getOffset, b.getLength)) + } + implicit lazy val bytes2BytesWritableInj: Injection[Array[Byte], ImmutableBytesWritable] = + new AbstractInjection[Array[Byte], ImmutableBytesWritable] { + override def apply(a: Array[Byte]) = new ImmutableBytesWritable(a) + override def invert(b: ImmutableBytesWritable) = Try(b.copyBytes) + } + + abstract class ImmutableBytesWritableInjection[T](implicit inj: Injection[T, Array[Byte]]) extends AbstractInjection[T, ImmutableBytesWritable] { + override def apply(a: T): ImmutableBytesWritable = new ImmutableBytesWritable(inj(a)) + } } diff --git a/bijection-hbase/src/test/scala/com/twitter/bijection/hbase/HBaseBijectionsLaws.scala b/bijection-hbase/src/test/scala/com/twitter/bijection/hbase/HBaseBijectionsLaws.scala deleted file mode 100644 index a1f7c8a13..000000000 --- a/bijection-hbase/src/test/scala/com/twitter/bijection/hbase/HBaseBijectionsLaws.scala +++ /dev/null @@ -1,99 +0,0 @@ -package com.twitter.bijection.hbase - -import org.scalatest.{ PropSpec, MustMatchers } -import org.scalatest.prop.PropertyChecks - -import com.twitter.bijection.{ CheckProperties, BaseProperties } -import HBaseBijections._ -import org.apache.hadoop.hbase.io.ImmutableBytesWritable -import org.apache.hadoop.hbase.util.Bytes - -/** - * @author Muhammad Ashraf - * @since 7/10/13 - */ -class HBaseBijectionsLaws extends CheckProperties with BaseProperties { - - property("String <=> StringBytes") { - isInjective[String, StringBytes] - } - - property("Int <=> IntBytes") { - isInjective[Int, IntBytes] - } - - property("Long <=> LongBytes") { - isInjective[Long, LongBytes] - } - - property("Double <=> DoubleBytes") { - isInjective[Double, DoubleBytes] - } - - property("Float <=> FloatBytes") { - isInjective[Float, FloatBytes] - } - - property("Boolean <=> BooleanBytes") { - isInjective[Boolean, BooleanBytes] - } - - property("Short <=> ShortBytes") { - isInjective[Short, ShortBytes] - } - - property("BigDecimal <=> BigDecimalBytes") { - isInjective[BigDecimal, BigDecimalBytes] - } - - property("BigDecimal <=> ImmutableBytesWritable") { - implicit val arbBD = arbitraryViaFn { - bd: BigDecimal => new ImmutableBytesWritable(Bytes.toBytes(bd.underlying())) - } - isBijection[BigDecimal, ImmutableBytesWritable] - } - - property("String <=> ImmutableBytesWritable") { - implicit val arbString = arbitraryViaFn { - input: String => new ImmutableBytesWritable(Bytes.toBytes(input)) - } - isBijection[String, ImmutableBytesWritable] - } - property("Long <=> ImmutableBytesWritable") { - implicit val arbLong = arbitraryViaFn { - input: Long => new ImmutableBytesWritable(Bytes.toBytes(input)) - } - isBijection[Long, ImmutableBytesWritable] - } - property("Int <=> ImmutableBytesWritable") { - implicit val arbInt = arbitraryViaFn { - input: Int => new ImmutableBytesWritable(Bytes.toBytes(input)) - } - isBijection[Int, ImmutableBytesWritable] - } - property("Double <=> ImmutableBytesWritable") { - implicit val arbDouble = arbitraryViaFn { - input: Double => new ImmutableBytesWritable(Bytes.toBytes(input)) - } - isBijection[Double, ImmutableBytesWritable] - } - property("Float <=> ImmutableBytesWritable") { - implicit val arbFloat = arbitraryViaFn { - input: Float => new ImmutableBytesWritable(Bytes.toBytes(input)) - } - isBijection[Float, ImmutableBytesWritable] - } - property("Short <=> ImmutableBytesWritable") { - implicit val arbShort = arbitraryViaFn { - input: Short => new ImmutableBytesWritable(Bytes.toBytes(input)) - } - isBijection[Short, ImmutableBytesWritable] - } - property("Boolean <=> ImmutableBytesWritable") { - implicit val arbBoolean = arbitraryViaFn { - input: Boolean => new ImmutableBytesWritable(Bytes.toBytes(input)) - } - isBijection[Boolean, ImmutableBytesWritable] - } - -} diff --git a/bijection-hbase/src/test/scala/com/twitter/bijection/hbase/HBaseBijectionsSpecifications.scala b/bijection-hbase/src/test/scala/com/twitter/bijection/hbase/HBaseBijectionsSpecifications.scala deleted file mode 100644 index 93e2ed38c..000000000 --- a/bijection-hbase/src/test/scala/com/twitter/bijection/hbase/HBaseBijectionsSpecifications.scala +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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 com.twitter.bijection.hbase - -import org.scalatest._ -import com.twitter.bijection.{ Bijection, BaseProperties } -import HBaseBijections._ -import org.apache.hadoop.hbase.io.ImmutableBytesWritable - -/** - * @author Muhammad Ashraf - * @since 7/10/13 - */ -class HBaseBijectionsSpecifications extends WordSpec with Matchers with BaseProperties { - - "HBaseBijections" should { - "round trip String -> Array[Byte]" in { - val expected = "Bonjour le monde" - val bytes = Bijection[String, StringBytes](expected) - val result = Bijection.invert[String, StringBytes](bytes) - assert(result == expected) - } - - "round trip Long -> Array[Byte]" in { - val expected = 42L - val bytes = Bijection[Long, LongBytes](expected) - val result = Bijection.invert[Long, LongBytes](bytes) - assert(result == expected) - } - - "round trip Int -> Array[Byte]" in { - val expected = 42 - val bytes = Bijection[Int, IntBytes](expected) - val result = Bijection.invert[Int, IntBytes](bytes) - assert(result == expected) - } - - "round trip Double -> Array[Byte]" in { - val expected = 42.0 - val bytes = Bijection[Double, DoubleBytes](expected) - val result = Bijection.invert[Double, DoubleBytes](bytes) - assert(result == expected) - } - - "round trip Float -> Array[Byte]" in { - val expected = 42.0F - val bytes = Bijection[Float, FloatBytes](expected) - val result = Bijection.invert[Float, FloatBytes](bytes) - assert(result == expected) - } - - "round trip Short -> Array[Byte]" in { - val expected = 1.toShort - val bytes = Bijection[Short, ShortBytes](expected) - val result = Bijection.invert[Short, ShortBytes](bytes) - assert(result == expected) - } - - "round trip BigDecimal -> Array[Byte]" in { - val expected = BigDecimal(1) - val bytes = Bijection[BigDecimal, BigDecimalBytes](expected) - val result = Bijection.invert[BigDecimal, BigDecimalBytes](bytes) - assert(result == expected) - } - - "round trip Boolean -> Array[Byte]" in { - val expected = true - val bytes = Bijection[Boolean, BooleanBytes](expected) - val result = Bijection.invert[Boolean, BooleanBytes](bytes) - assert(result == expected) - } - - "round trip String -> ImmutableBytesWritable" in { - val expected = "Bonjour le monde" - val bytes = Bijection[String, ImmutableBytesWritable](expected) - val result = Bijection.invert[String, ImmutableBytesWritable](bytes) - assert(result == expected) - } - - "round trip Long -> ImmutableBytesWritable" in { - val expected = 1L - val bytes = Bijection[Long, ImmutableBytesWritable](expected) - val result = Bijection.invert[Long, ImmutableBytesWritable](bytes) - assert(result == expected) - } - - "round trip Int -> ImmutableBytesWritable" in { - val expected = 42 - val bytes = Bijection[Int, ImmutableBytesWritable](expected) - val result = Bijection.invert[Int, ImmutableBytesWritable](bytes) - assert(result == expected) - } - - "round trip Double -> ImmutableBytesWritable" in { - val expected = 42.0 - val bytes = Bijection[Double, ImmutableBytesWritable](expected) - val result = Bijection.invert[Double, ImmutableBytesWritable](bytes) - assert(result == expected) - } - - "round trip Float -> ImmutableBytesWritable" in { - val expected = 42.0F - val bytes = Bijection[Float, ImmutableBytesWritable](expected) - val result = Bijection.invert[Float, ImmutableBytesWritable](bytes) - assert(result == expected) - } - - "round trip Short -> ImmutableBytesWritable" in { - val expected = 1.toShort - val bytes = Bijection[Short, ImmutableBytesWritable](expected) - val result = Bijection.invert[Short, ImmutableBytesWritable](bytes) - assert(result == expected) - } - - "round trip BigDecimal -> ImmutableBytesWritable" in { - val expected = BigDecimal(1) - val bytes = Bijection[BigDecimal, ImmutableBytesWritable](expected) - val result = Bijection.invert[BigDecimal, ImmutableBytesWritable](bytes) - assert(result == expected) - } - } - -} diff --git a/bijection-hbase/src/test/scala/com/twitter/bijection/hbase/HBaseInjectionsLaws.scala b/bijection-hbase/src/test/scala/com/twitter/bijection/hbase/HBaseInjectionsLaws.scala new file mode 100644 index 000000000..88cdf1511 --- /dev/null +++ b/bijection-hbase/src/test/scala/com/twitter/bijection/hbase/HBaseInjectionsLaws.scala @@ -0,0 +1,115 @@ +/* + * 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 com.twitter.bijection.hbase + +import org.scalatest.{ PropSpec, MustMatchers } +import org.scalatest.prop.PropertyChecks +import org.scalacheck.Arbitrary +import org.scalacheck.Gen + +import com.twitter.bijection.{ CheckProperties, BaseProperties, Injection } +import org.apache.hadoop.hbase.io.ImmutableBytesWritable + +object HBaseInjectionsLaws { + implicit val arbitaryImmutableBytesWritable: Arbitrary[ImmutableBytesWritable] = + Arbitrary(for { + bytes <- Arbitrary.arbitrary[Array[Byte]] + offset <- Gen.choose(0, bytes.length - 1) + len <- Gen.choose(0, bytes.length - offset) + } yield new ImmutableBytesWritable(bytes, offset, len)) +} + +/** + * @author Muhammad Ashraf + * @since 7/10/13 + */ +class HBaseInjectionsLaws extends CheckProperties with BaseProperties { + import HBaseInjections._ + import HBaseInjectionsLaws.arbitaryImmutableBytesWritable + + property("String -> Array[Byte]") { + isLooseInjection[String, Array[Byte]] + } + + property("Int -> Array[Byte]") { + isInjection[Int, Array[Byte]] + } + + property("Long -> Array[Byte]") { + isInjection[Long, Array[Byte]] + } + + property("Double -> Array[Byte]") { + isInjection[Double, Array[Byte]] + } + + property("Float -> Array[Byte]") { + isInjection[Float, Array[Byte]] + } + + property("Boolean -> Array[Byte]") { + isLooseInjection[Boolean, Array[Byte]] + } + + property("Short -> Array[Byte]") { + isInjection[Short, Array[Byte]] + } + + property("String -> ImmutableBytesWritable") { + isLooseInjection[String, ImmutableBytesWritable] + } + + property("Int -> ImmutableBytesWritable") { + isInjection[Int, ImmutableBytesWritable] + } + + property("Long -> ImmutableBytesWritable") { + isInjection[Long, ImmutableBytesWritable] + } + + // This injection will invert a ImmutableBytesWritable whose length is less + // or greater than the size of a Bytes.toDouble because it incorrectly assumes + // that you give it the correct number of bytes. + // + // i.e. If the ImmutableBytesWritable is a slice of the first byte of an + // underlying 8 byte array, this injection will use all the bytes when + // inverting. + property("Double -> ImmutableBytesWritable") { + isLooseInjection[Double, ImmutableBytesWritable] + } + + // This injection will invert a ImmutableBytesWritable whose length is less + // or greater than the size of a Bytes.toFloat because it incorrectly assumes + // that you give it the correct number of bytes. + // + // i.e. If the ImmutableBytesWritable is a slice of the first byte of an + // underlying 4 byte array, this injection will use all the bytes when + // inverting. + property("Float -> ImmutableBytesWritable") { + isLooseInjection[Float, ImmutableBytesWritable] + } + + property("Boolean -> ImmutableBytesWritable") { + isLooseInjection[Boolean, ImmutableBytesWritable] + } + + property("Short -> ImmutableBytesWritable") { + isInjection[Short, ImmutableBytesWritable] + } + + property("Array[Byte] -> ImmutableBytesWritable") { + isInjection[Array[Byte], ImmutableBytesWritable] + } +} diff --git a/bijection-hbase/src/test/scala/com/twitter/bijection/hbase/HBaseInjectionsSpecifications.scala b/bijection-hbase/src/test/scala/com/twitter/bijection/hbase/HBaseInjectionsSpecifications.scala new file mode 100644 index 000000000..a82d2221e --- /dev/null +++ b/bijection-hbase/src/test/scala/com/twitter/bijection/hbase/HBaseInjectionsSpecifications.scala @@ -0,0 +1,161 @@ +/* + * 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 com.twitter.bijection.hbase + +import scala.util.Success +import com.twitter.bijection.Injection +import com.twitter.bijection.hbase.HBaseInjections._ +import org.apache.hadoop.hbase.io.ImmutableBytesWritable +import org.scalatest.WordSpec + +/** + * @author Muhammad Ashraf + * @since 7/10/13 + */ +class HBaseInjectionsSpecifications extends WordSpec { + "HBaseInjections" should { + "respect ImmutableBytesWritable offset and length" in { + val long: Long = 1 + val double: Double = 2 + val int: Int = 3 + + val longIBW = long2BytesWritableInj(long) + val doubleIBW = double2BytesWritableInj(double) + val intIBW = int2BytesWritableInj(int) + + val allBytes = longIBW.copyBytes ++ doubleIBW.copyBytes ++ intIBW.copyBytes + + val sharedLongIBW = new ImmutableBytesWritable(allBytes, 0, 8) + val sharedDoubleIBW = new ImmutableBytesWritable(allBytes, 8, 8) + val sharedIntIBW = new ImmutableBytesWritable(allBytes, 16, 4) + + assert(Success(long) == long2BytesWritableInj.invert(sharedLongIBW)) + assert(Success(double) == double2BytesWritableInj.invert(sharedDoubleIBW)) + assert(Success(int) == int2BytesWritableInj.invert(sharedIntIBW)) + } + + "round trip String -> Array[Byte]" in { + val expected = "Bonjour le monde" + val bytes = Injection[String, Array[Byte]](expected) + val result = Injection.invert[String, Array[Byte]](bytes) + assert(Success(expected) == result) + } + + "round trip Long -> Array[Byte]" in { + val expected = 42L + val bytes = Injection[Long, Array[Byte]](expected) + val result = Injection.invert[Long, Array[Byte]](bytes) + assert(Success(expected) == result) + } + + "round trip Int -> Array[Byte]" in { + val expected = 42 + val bytes = Injection[Int, Array[Byte]](expected) + val result = Injection.invert[Int, Array[Byte]](bytes) + assert(Success(expected) == result) + } + + "round trip Double -> Array[Byte]" in { + val expected = 42.0 + val bytes = Injection[Double, Array[Byte]](expected) + val result = Injection.invert[Double, Array[Byte]](bytes) + assert(Success(expected) == result) + } + + "round trip Float -> Array[Byte]" in { + val expected = 42.0F + val bytes = Injection[Float, Array[Byte]](expected) + val result = Injection.invert[Float, Array[Byte]](bytes) + assert(Success(expected) == result) + } + + "round trip Short -> Array[Byte]" in { + val expected = 1.toShort + val bytes = Injection[Short, Array[Byte]](expected) + val result = Injection.invert[Short, Array[Byte]](bytes) + assert(Success(expected) == result) + } + + "round trip BigDecimal -> Array[Byte]" in { + val expected = BigDecimal(1) + val bytes = Injection[BigDecimal, Array[Byte]](expected) + val result = Injection.invert[BigDecimal, Array[Byte]](bytes) + assert(Success(expected) == result) + } + + "round trip Boolean -> Array[Byte]" in { + val expected = true + val bytes = Injection[Boolean, Array[Byte]](expected) + val result = Injection.invert[Boolean, Array[Byte]](bytes) + assert(Success(expected) == result) + } + + "round trip String -> ImmutableBytesWritable" in { + val expected = "Bonjour le monde" + val bytes = Injection[String, ImmutableBytesWritable](expected) + val result = Injection.invert[String, ImmutableBytesWritable](bytes) + assert(Success(expected) == result) + } + + "round trip Long -> ImmutableBytesWritable" in { + val expected = 1L + val bytes = Injection[Long, ImmutableBytesWritable](expected) + val result = Injection.invert[Long, ImmutableBytesWritable](bytes) + assert(Success(expected) == result) + } + + "round trip Int -> ImmutableBytesWritable" in { + val expected = 42 + val bytes = Injection[Int, ImmutableBytesWritable](expected) + val result = Injection.invert[Int, ImmutableBytesWritable](bytes) + assert(Success(expected) == result) + } + + "round trip Double -> ImmutableBytesWritable" in { + val expected = 42.0 + val bytes = Injection[Double, ImmutableBytesWritable](expected) + val result = Injection.invert[Double, ImmutableBytesWritable](bytes) + assert(Success(expected) == result) + } + + "round trip Float -> ImmutableBytesWritable" in { + val expected = 42.0F + val bytes = Injection[Float, ImmutableBytesWritable](expected) + val result = Injection.invert[Float, ImmutableBytesWritable](bytes) + assert(Success(expected) == result) + } + + "round trip Short -> ImmutableBytesWritable" in { + val expected = 1.toShort + val bytes = Injection[Short, ImmutableBytesWritable](expected) + val result = Injection.invert[Short, ImmutableBytesWritable](bytes) + assert(Success(expected) == result) + } + + "round trip BigDecimal -> ImmutableBytesWritable" in { + val expected = BigDecimal(1) + val bytes = Injection[BigDecimal, ImmutableBytesWritable](expected) + val result = Injection.invert[BigDecimal, ImmutableBytesWritable](bytes) + assert(Success(expected) == result) + } + + "round trip Boolean -> ImmutableBytesWritable" in { + val expected = true + val bytes = Injection[Boolean, ImmutableBytesWritable](expected) + val result = Injection.invert[Boolean, ImmutableBytesWritable](bytes) + assert(Success(expected) == result) + } + } +} diff --git a/bijection-scrooge/src/main/scala/com/twitter/bijection/scrooge/ScroogeCodecs.scala b/bijection-scrooge/src/main/scala/com/twitter/bijection/scrooge/ScroogeCodecs.scala index 6cff75ebc..c2441e60b 100644 --- a/bijection-scrooge/src/main/scala/com/twitter/bijection/scrooge/ScroogeCodecs.scala +++ b/bijection-scrooge/src/main/scala/com/twitter/bijection/scrooge/ScroogeCodecs.scala @@ -18,6 +18,7 @@ package com.twitter.bijection.scrooge import com.twitter.bijection.{ Bijection, Injection } import com.twitter.bijection.Inversion.attempt +import com.twitter.bijection.macros.Macros import com.twitter.scrooge._ import org.apache.thrift.protocol.TJSONProtocol @@ -35,10 +36,19 @@ object BinaryScalaCodec { } class BinaryScalaCodec[T <: ThriftStruct](c: ThriftStructCodec[T]) - extends ScalaCodec(new ThriftStructSerializer[T] { + extends Injection[T, Array[Byte]] { + import com.twitter.bijection.thrift.{ TArrayByteTransport, TArrayBinaryProtocol } + + lazy val thriftStructSerializer = new ThriftStructSerializer[T] { override def codec = c val protocolFactory = new TBinaryProtocol.Factory - }) + } + + override def apply(item: T) = thriftStructSerializer.toBytes(item) + override def invert(bytes: Array[Byte]) = Macros.fastAttempt(bytes){ + c.decode(TArrayBinaryProtocol(TArrayByteTransport(bytes))) + } +} object CompactScalaCodec { def apply[T <: ThriftStruct](c: ThriftStructCodec[T]) = diff --git a/bijection-scrooge/src/test/scala/com/twitter/bijection/scrooge/ScroogeCodecLaws.scala b/bijection-scrooge/src/test/scala/com/twitter/bijection/scrooge/ScroogeCodecLaws.scala index ed803f540..cbf492724 100644 --- a/bijection-scrooge/src/test/scala/com/twitter/bijection/scrooge/ScroogeCodecLaws.scala +++ b/bijection-scrooge/src/test/scala/com/twitter/bijection/scrooge/ScroogeCodecLaws.scala @@ -21,13 +21,17 @@ import com.twitter.bijection.{ CheckProperties, BaseProperties, Bijection, Injec import org.scalatest.{ PropSpec, MustMatchers } import org.scalatest.prop.PropertyChecks -import org.scalacheck.Arbitrary +import org.scalacheck.{ Gen, Arbitrary } class ScroogeCodecLaws extends CheckProperties with BaseProperties { - def buildScrooge(i: (Int, String)) = - TestStruct(i._1, Some(i._2)) - - implicit val testScrooge = arbitraryViaFn { is: (Int, String) => buildScrooge(is) } + implicit val testScrooge: Arbitrary[TestStruct] = Arbitrary { + for { + l <- Gen.oneOf('a' to 'z') + u <- Gen.oneOf('A' to 'Z') + s <- Gen.listOf(Gen.oneOf(l, u, Gen.numChar)).map(_.mkString) + i <- Arbitrary.arbitrary[Int] + } yield TestStruct(i, Some(s)) + } // Code generator for thrift instances. def roundTripsScrooge[B](bijection: Injection[TestStruct, B]) = { diff --git a/bijection-thrift/src/main/scala/com/twitter/bijection/thrift/TArrayBinaryProtocol.scala b/bijection-thrift/src/main/scala/com/twitter/bijection/thrift/TArrayBinaryProtocol.scala new file mode 100644 index 000000000..03973ca56 --- /dev/null +++ b/bijection-thrift/src/main/scala/com/twitter/bijection/thrift/TArrayBinaryProtocol.scala @@ -0,0 +1,158 @@ +/* + * 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 com.twitter.bijection.thrift + +import java.io.UnsupportedEncodingException +import java.nio.ByteBuffer + +import org.apache.thrift.protocol._ +import org.apache.thrift.TException +import org.apache.thrift.transport.TTransport + +/** + * Binary protocol implementation for thrift. + * + */ +object TArrayBinaryProtocol { + private val ANONYMOUS_STRUCT: TStruct = new TStruct() +} + +case class TArrayBinaryProtocol(transport: TArrayByteTransport) extends TProtocol(transport) { + import TArrayBinaryProtocol._ + + def readMessageBegin(): TMessage = { + sys.error("Protocol for serialized structures only") + } + + def writeBinary(x$1: java.nio.ByteBuffer): Unit = ??? + def writeBool(x$1: Boolean): Unit = ??? + def writeByte(x$1: Byte): Unit = ??? + def writeDouble(x$1: Double): Unit = ??? + def writeFieldBegin(x$1: org.apache.thrift.protocol.TField): Unit = ??? + def writeFieldEnd(): Unit = ??? + def writeFieldStop(): Unit = ??? + def writeI16(x$1: Short): Unit = ??? + def writeI32(x$1: Int): Unit = ??? + def writeI64(x$1: Long): Unit = ??? + def writeListBegin(x$1: org.apache.thrift.protocol.TList): Unit = ??? + def writeListEnd(): Unit = ??? + def writeMapBegin(x$1: org.apache.thrift.protocol.TMap): Unit = ??? + def writeMapEnd(): Unit = ??? + def writeMessageBegin(x$1: org.apache.thrift.protocol.TMessage): Unit = ??? + def writeMessageEnd(): Unit = ??? + def writeSetBegin(x$1: org.apache.thrift.protocol.TSet): Unit = ??? + def writeSetEnd(): Unit = ??? + def writeString(x$1: String): Unit = ??? + def writeStructBegin(x$1: org.apache.thrift.protocol.TStruct): Unit = ??? + def writeStructEnd(): Unit = ??? + + def readMessageEnd() {} + + override final def readStructBegin: TStruct = ANONYMOUS_STRUCT + + override final def readStructEnd: Unit = {} + + override final def readFieldBegin: TField = { + val tpe: Byte = readByte + val id: Short = if (tpe == TType.STOP) 0 else readI16 + new TField("", tpe, id) + } + + override final def readFieldEnd(): Unit = {} + + override final def readMapBegin: TMap = new TMap(readByte, readByte, readI32) + + override final def readMapEnd(): Unit = {} + + override final def readListBegin: TList = new TList(readByte, readI32) + + override final def readListEnd(): Unit = {} + + override final def readSetBegin: TSet = new TSet(readByte, readI32) + + override final def readSetEnd(): Unit = {} + + override final def readBool: Boolean = readByte == 1 + + @inline + private[this] final def advance(by: Int) { + transport.bufferPos = transport.bufferPos + by + } + + @inline + def readByte: Byte = { + val r: Byte = transport.buf(transport.bufferPos) + advance(1) + r + } + + @inline + def readI32: Int = { + val off = transport.bufferPos + advance(4) + ((transport.buf(off) & 0xff) << 24) | + ((transport.buf(off + 1) & 0xff) << 16) | + ((transport.buf(off + 2) & 0xff) << 8) | + ((transport.buf(off + 3) & 0xff)) + } + + @inline + def readI16: Short = { + val off = transport.bufferPos + advance(2) + (((transport.buf(off) & 0xff) << 8) | ((transport.buf(off + 1) & 0xff))).toShort + } + + @inline + def readI64: Long = { + val off = transport.bufferPos + advance(8) + ((transport.buf(off) & 0xffL) << 56) | + ((transport.buf(off + 1) & 0xffL) << 48) | + ((transport.buf(off + 2) & 0xffL) << 40) | + ((transport.buf(off + 3) & 0xffL) << 32) | + ((transport.buf(off + 4) & 0xffL) << 24) | + ((transport.buf(off + 5) & 0xffL) << 16) | + ((transport.buf(off + 6) & 0xffL) << 8) | + ((transport.buf(off + 7) & 0xffL)) + } + + def readDouble: Double = + java.lang.Double.longBitsToDouble(readI64) + + def readString: String = + try { + val size = readI32 + val s = new String(transport.buf, transport.bufferPos, size, "UTF-8") + advance(size) + s + } catch { + case e: UnsupportedEncodingException => + throw new TException("JVM DOES NOT SUPPORT UTF-8") + } + + def readBinary: ByteBuffer = { + val size = readI32 + val bb = ByteBuffer.wrap(transport.buf, transport.bufferPos, size) + advance(size) + bb + } + +} \ No newline at end of file diff --git a/bijection-thrift/src/main/scala/com/twitter/bijection/thrift/TArrayByteTransport.scala b/bijection-thrift/src/main/scala/com/twitter/bijection/thrift/TArrayByteTransport.scala new file mode 100644 index 000000000..5bd404668 --- /dev/null +++ b/bijection-thrift/src/main/scala/com/twitter/bijection/thrift/TArrayByteTransport.scala @@ -0,0 +1,40 @@ +package com.twitter.bijection.thrift + +import org.apache.thrift.protocol._ +import org.apache.thrift.TException +import org.apache.thrift.transport.TTransport + +case class TArrayByteTransport(buf: Array[Byte]) extends TTransport { + private[thrift] final var bufferPos = 0 + private[this] final val bufferSiz_ = buf.size + + @inline + final def bufferSiz = bufferSiz_ + + override final def isOpen: Boolean = bufferPos < bufferSiz_ + + override final def open() {} + + override final def close() {} + + override final def readAll(destBuf: Array[Byte], off: Int, len: Int): Int = + read(destBuf, off, len) + + override final def read(destBuf: Array[Byte], destOffset: Int, len: Int): Int = { + System.arraycopy(buf, bufferPos, destBuf, destOffset, len) + bufferPos = bufferPos + len + len + } + + override final def getBufferPosition: Int = bufferPos + override final def getBytesRemainingInBuffer: Int = bufferSiz_ - bufferPos + override final def getBuffer: Array[Byte] = buf + + override final def write(buf: Array[Byte], off: Int, len: Int): Unit = { + sys.error("not implemented") + } + + override final def consumeBuffer(len: Int): Unit = { + bufferPos = bufferPos + len + } +} \ No newline at end of file diff --git a/bijection-thrift/src/main/scala/com/twitter/bijection/thrift/ThriftCodecs.scala b/bijection-thrift/src/main/scala/com/twitter/bijection/thrift/ThriftCodecs.scala index 4ecfe5b68..79daa450b 100644 --- a/bijection-thrift/src/main/scala/com/twitter/bijection/thrift/ThriftCodecs.scala +++ b/bijection-thrift/src/main/scala/com/twitter/bijection/thrift/ThriftCodecs.scala @@ -2,6 +2,7 @@ package com.twitter.bijection.thrift import com.twitter.bijection.{ Bijection, Conversion, Injection, InversionFailure, StringCodec } import com.twitter.bijection.Inversion.attempt +import com.twitter.bijection.macros.Macros import java.io.{ ByteArrayInputStream, ByteArrayOutputStream } import org.apache.thrift.{ TBase, TEnum } import org.apache.thrift.protocol.{ @@ -63,7 +64,23 @@ object BinaryThriftCodec { } class BinaryThriftCodec[T <: TBase[_, _]](klass: Class[T]) - extends ThriftCodec[T, TBinaryProtocol.Factory](klass, new TBinaryProtocol.Factory) + extends Injection[T, Array[Byte]] { + + private[this] val factory = new TBinaryProtocol.Factory + + protected lazy val prototype = klass.newInstance + + override def apply(item: T) = { + val baos = new ByteArrayOutputStream + item.write(factory.getProtocol(new TIOStreamTransport(baos))) + baos.toByteArray + } + override def invert(bytes: Array[Byte]) = Macros.fastAttempt(bytes){ + val obj = prototype.deepCopy + obj.read(TArrayBinaryProtocol(TArrayByteTransport(bytes))) + obj.asInstanceOf[T] + } +} object CompactThriftCodec { def apply[T <: TBase[_, _]: ClassTag]: Injection[T, Array[Byte]] = fromClass(classTag[T].runtimeClass.asInstanceOf[Class[T]]) diff --git a/project/Build.scala b/project/Build.scala index 7bfee62b3..bf3abc12a 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -197,7 +197,7 @@ object BijectionBuild extends Build { "org.apache.thrift" % "libthrift" % "0.6.1" exclude("junit", "junit"), jsonParser ) - ).dependsOn(bijectionCore % "test->test;compile->compile") + ).dependsOn(bijectionCore % "test->test;compile->compile", bijectionMacros) lazy val bijectionGuava = module("guava").settings( osgiExportAll("com.twitter.bijection.guava"), @@ -215,9 +215,10 @@ object BijectionBuild extends Build { libraryDependencies ++= Seq( "org.apache.thrift" % "libthrift" % "0.6.1" exclude("junit", "junit"), "com.twitter" %% "scrooge-serializer" % "3.17.0", - "com.twitter" %% "finagle-core" % "6.24.0" % "test" + "com.twitter" %% "util-core" % "6.24.0", + "com.twitter" %% "finagle-core" % "6.25.0" % "test" ) - ).dependsOn(bijectionCore % "test->test;compile->compile") + ).dependsOn(bijectionCore % "test->test;compile->compile", bijectionMacros, bijectionThrift) lazy val bijectionJson = module("json").settings( osgiExportAll("com.twitter.bijection.json"), @@ -226,12 +227,15 @@ object BijectionBuild extends Build { lazy val bijectionUtil = module("util").settings( osgiExportAll("com.twitter.bijection.twitter_util"), - libraryDependencies += "com.twitter" %% "util-core" % "6.23.0" + libraryDependencies += "com.twitter" %% "util-core" % "6.24.0" ).dependsOn(bijectionCore % "test->test;compile->compile") lazy val bijectionFinagleMySql = module("finagle-mysql").settings( osgiExportAll("com.twitter.bijection.finagle_mysql"), - libraryDependencies += "com.twitter" %% "finagle-mysql" % "6.24.0" + libraryDependencies ++= Seq( + "com.twitter" %% "finagle-mysql" % "6.25.0", + "com.twitter" %% "util-core" % "6.24.0" + ) ).dependsOn(bijectionCore % "test->test;compile->compile") lazy val bijectionClojure = module("clojure").settings( @@ -254,16 +258,17 @@ object BijectionBuild extends Build { lazy val bijectionHbase = module("hbase").settings( osgiExportAll("com.twitter.bijection.hbase"), libraryDependencies ++= Seq( - "org.apache.hbase" % "hbase" % "0.94.4" % "provided->default", + "org.apache.hbase" % "hbase" % "0.94.4" % "provided->default" exclude("org.jruby", "jruby-complete"), "org.apache.hadoop" % "hadoop-core" % "1.0.4" % "provided->default" ) ).dependsOn(bijectionCore % "test->test;compile->compile") + .dependsOn(bijectionMacros % "compile->compile") lazy val bijectionJodaTime = module("jodatime").settings( osgiExportAll("com.twitter.bijection.jodatime"), libraryDependencies ++= Seq( - "joda-time" % "joda-time" % "2.2", - "org.joda" % "joda-convert" % "1.3.1" + "joda-time" % "joda-time" % "2.3", + "org.joda" % "joda-convert" % "1.6" ) ).dependsOn(bijectionCore % "test->test;compile->compile") diff --git a/sbt b/sbt index 040ce8012..bd5ffec4c 100755 --- a/sbt +++ b/sbt @@ -126,8 +126,8 @@ declare -r default_jvm_opts="-Dfile.encoding=UTF8 -XX:MaxPermSize=384m -Xms512m declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy" declare -r latest_28="2.8.2" declare -r latest_29="2.9.3" -declare -r latest_210="2.10.3" -declare -r latest_211="2.11.0-M5" +declare -r latest_210="2.10.5" +declare -r latest_211="2.11.5" declare -r script_path=$(get_script_path "$BASH_SOURCE") declare -r script_dir="$(dirname $script_path)" diff --git a/version.sbt b/version.sbt index 014e7f4a2..a599a5caa 100644 --- a/version.sbt +++ b/version.sbt @@ -1,2 +1,2 @@ -version in ThisBuild := "0.8.0" +version in ThisBuild := "0.8.1"