diff --git a/akka-http-caching/src/main/mima-filters/10.1.7.backwards.excludes b/akka-http-caching/src/main/mima-filters/10.1.7.backwards.excludes new file mode 100644 index 00000000000..165090fbb23 --- /dev/null +++ b/akka-http-caching/src/main/mima-filters/10.1.7.backwards.excludes @@ -0,0 +1,2 @@ +# Scala 2.13.0-M5 +ProblemFilters.exclude[MissingTypesProblem]("akka.http.caching.scaladsl.CachingSettings$") diff --git a/akka-http-caching/src/main/scala/akka/http/caching/LfuCache.scala b/akka-http-caching/src/main/scala/akka/http/caching/LfuCache.scala index 192f3455912..e9c5f6fc669 100755 --- a/akka-http-caching/src/main/scala/akka/http/caching/LfuCache.scala +++ b/akka-http-caching/src/main/scala/akka/http/caching/LfuCache.scala @@ -38,7 +38,7 @@ object LfuCache { require(settings.maxCapacity >= 0, "maxCapacity must not be negative") require(settings.initialCapacity <= settings.maxCapacity, "initialCapacity must be <= maxCapacity") - if (settings.timeToLive.isFinite() || settings.timeToIdle.isFinite()) expiringLfuCache(settings.maxCapacity, settings.initialCapacity, settings.timeToLive, settings.timeToIdle) + if (settings.timeToLive.isFinite || settings.timeToIdle.isFinite) expiringLfuCache(settings.maxCapacity, settings.initialCapacity, settings.timeToLive, settings.timeToIdle) else simpleLfuCache(settings.maxCapacity, settings.initialCapacity) } diff --git a/akka-http-caching/src/main/scala/akka/http/caching/scaladsl/CachingSettings.scala b/akka-http-caching/src/main/scala/akka/http/caching/scaladsl/CachingSettings.scala index d5bedf0fd61..9a3a0935233 100644 --- a/akka-http-caching/src/main/scala/akka/http/caching/scaladsl/CachingSettings.scala +++ b/akka-http-caching/src/main/scala/akka/http/caching/scaladsl/CachingSettings.scala @@ -6,7 +6,7 @@ package akka.http.caching.scaladsl import akka.annotation.{ DoNotInherit, InternalApi } import akka.http.caching.javadsl -import akka.http.impl.util.SettingsCompanion +import akka.http.impl.util.SettingsCompanionImpl import com.typesafe.config.Config import scala.concurrent.duration.Duration @@ -62,7 +62,7 @@ private[http] final case class LfuCacheSettingsImpl( override def productPrefix = "LfuCacheSettings" } -object CachingSettings extends SettingsCompanion[CachingSettings]("akka.http.caching") { +object CachingSettings extends SettingsCompanionImpl[CachingSettings]("akka.http.caching") { def fromSubConfig(root: Config, c: Config): CachingSettingsImpl = { val lfuConfig = c.getConfig("lfu-cache") CachingSettingsImpl( diff --git a/akka-http-core/src/main/java/akka/http/impl/util/Util.java b/akka-http-core/src/main/java/akka/http/impl/util/Util.java index a9f02379259..ddb15101373 100644 --- a/akka-http-core/src/main/java/akka/http/impl/util/Util.java +++ b/akka-http-core/src/main/java/akka/http/impl/util/Util.java @@ -9,6 +9,7 @@ import scala.collection.immutable.Map$; import scala.collection.immutable.Seq; import akka.stream.scaladsl.Source; +import akka.http.ccompat.MapHelpers; import java.util.Arrays; import java.util.Map; @@ -35,7 +36,7 @@ public static Source upcastSource(Source)(Object) p; } public static scala.collection.immutable.Map convertMapToScala(Map map) { - return emptyMap.$plus$plus(scala.collection.JavaConverters.mapAsScalaMapConverter(map).asScala()); + return MapHelpers.convertMapToScala(map); } @SuppressWarnings("unchecked") // contains an upcast public static scala.Option convertOptionalToScala(Optional o) { diff --git a/akka-http-core/src/main/java/akka/http/javadsl/model/Multiparts.java b/akka-http-core/src/main/java/akka/http/javadsl/model/Multiparts.java index 46af4e66a32..4ef1a059960 100644 --- a/akka-http-core/src/main/java/akka/http/javadsl/model/Multiparts.java +++ b/akka-http-core/src/main/java/akka/http/javadsl/model/Multiparts.java @@ -12,9 +12,10 @@ import java.util.Collections; import java.util.Map; +import akka.http.ccompat.MapHelpers; + import static akka.http.impl.util.Util.convertArray; import static akka.http.impl.util.Util.convertMapToScala; -import static akka.http.impl.util.Util.emptyMap; /** * Constructors for Multipart instances @@ -140,7 +141,7 @@ public static Multipart.FormData.BodyPart.Strict createFormDataBodyPartStrict(St } private static scala.collection.immutable.Map toScalaMap(Map map) { - return emptyMap.$plus$plus(scala.collection.JavaConverters.mapAsScalaMapConverter(map).asScala()); + return MapHelpers.convertMapToScala(map); } private static scala.collection.Iterable toScalaSeq(java.util.List _headers) { diff --git a/akka-http-core/src/main/mima-filters/10.1.7.backwards.excludes b/akka-http-core/src/main/mima-filters/10.1.7.backwards.excludes new file mode 100644 index 00000000000..a597a4869eb --- /dev/null +++ b/akka-http-core/src/main/mima-filters/10.1.7.backwards.excludes @@ -0,0 +1,10 @@ +# 2.13.0-M5 support: +ProblemFilters.exclude[MissingClassProblem]("akka.http.impl.util.SettingsCompanion") +ProblemFilters.exclude[MissingClassProblem]("akka.http.impl.util.SettingsCompanion$") +ProblemFilters.exclude[MissingTypesProblem]("akka.http.impl.settings.ConnectionPoolSettingsImpl$") +ProblemFilters.exclude[MissingTypesProblem]("akka.http.impl.settings.HttpsProxySettingsImpl$") +ProblemFilters.exclude[MissingTypesProblem]("akka.http.impl.settings.ParserSettingsImpl$") +ProblemFilters.exclude[MissingTypesProblem]("akka.http.impl.settings.ServerSettingsImpl$") +ProblemFilters.exclude[MissingTypesProblem]("akka.http.impl.settings.PreviewServerSettingsImpl$") +ProblemFilters.exclude[MissingTypesProblem]("akka.http.impl.settings.ClientConnectionSettingsImpl$") +ProblemFilters.exclude[MissingTypesProblem]("akka.http.scaladsl.settings.Http2ServerSettings$Http2ServerSettingsImpl$") diff --git a/akka-http-core/src/main/scala-2.13+/akka/http/ccompat/MapHelpers.scala b/akka-http-core/src/main/scala-2.13+/akka/http/ccompat/MapHelpers.scala new file mode 100644 index 00000000000..357d1fdc76e --- /dev/null +++ b/akka-http-core/src/main/scala-2.13+/akka/http/ccompat/MapHelpers.scala @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2018-2019 Lightbend Inc. + */ + +package akka.http.ccompat + +object MapHelpers { + def convertMapToScala[K, V](jmap: java.util.Map[K, V]): scala.collection.immutable.Map[K, V] = { + import scala.collection.JavaConverters._ + Map.empty.concat(jmap.asScala) + } +} diff --git a/akka-http-core/src/main/scala-2.13+/akka/http/ccompat/imm/package.scala b/akka-http-core/src/main/scala-2.13+/akka/http/ccompat/imm/package.scala new file mode 100644 index 00000000000..7537674d621 --- /dev/null +++ b/akka-http-core/src/main/scala-2.13+/akka/http/ccompat/imm/package.scala @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2018-2019 Lightbend Inc. + */ + +package akka.http.ccompat + +import scala.collection.immutable + +/** + * INTERNAL API + */ +package object imm { + // Nothing yet, but present to be source-compatible with 2.13- +} diff --git a/akka-http-core/src/main/scala-2.13+/akka/http/ccompat/package.scala b/akka-http-core/src/main/scala-2.13+/akka/http/ccompat/package.scala new file mode 100644 index 00000000000..96a9f2ed925 --- /dev/null +++ b/akka-http-core/src/main/scala-2.13+/akka/http/ccompat/package.scala @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2018-2019 Lightbend Inc. + */ + +package akka.http + +/** + * INTERNAL API + */ +package object ccompat { + + type Builder[-A, +To] = scala.collection.mutable.Builder[A, To] +} + +/** + * INTERNAL API + */ +package ccompat { + import akka.http.scaladsl.model.Uri.Query + trait QuerySeqOptimized extends scala.collection.immutable.LinearSeq[(String, String)] with scala.collection.StrictOptimizedLinearSeqOps[(String, String), scala.collection.immutable.LinearSeq, Query] { + override protected def fromSpecific(coll: IterableOnce[(String, String)]): Query = + Query(coll.iterator.to(Seq): _*) + + def newBuilder: Any = akka.http.scaladsl.model.Uri.Query.newBuilder + } +} diff --git a/akka-http-core/src/main/scala-2.13+/akka/http/scaladsl/util/FastFuture.scala b/akka-http-core/src/main/scala-2.13+/akka/http/scaladsl/util/FastFuture.scala new file mode 100644 index 00000000000..b1d90a306fb --- /dev/null +++ b/akka-http-core/src/main/scala-2.13+/akka/http/scaladsl/util/FastFuture.scala @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2009-2019 Lightbend Inc. + */ + +package akka.http.scaladsl.util + +import scala.language.higherKinds +import scala.util.control.NonFatal +import scala.util.{ Failure, Success, Try } +import scala.collection.BuildFrom +import scala.concurrent.duration.Duration +import scala.concurrent._ + +/** + * Provides alternative implementations of the basic transformation operations defined on [[scala.concurrent.Future]], + * which try to avoid scheduling to an [[scala.concurrent.ExecutionContext]] if possible, i.e. if the given future + * value is already present. + */ +class FastFuture[A](val future: Future[A]) extends AnyVal { + import FastFuture._ + + def map[B](f: A ⇒ B)(implicit ec: ExecutionContext): Future[B] = + transformWith(a ⇒ FastFuture.successful(f(a)), FastFuture.failed) + + def flatMap[B](f: A ⇒ Future[B])(implicit ec: ExecutionContext): Future[B] = + transformWith(f, FastFuture.failed) + + def filter(pred: A ⇒ Boolean)(implicit executor: ExecutionContext): Future[A] = + flatMap { r ⇒ + if (pred(r)) future + else throw new NoSuchElementException("Future.filter predicate is not satisfied") + } + + def foreach(f: A ⇒ Unit)(implicit ec: ExecutionContext): Unit = map(f) + + def transformWith[B](f: Try[A] ⇒ Future[B])(implicit executor: ExecutionContext): Future[B] = + transformWith(a ⇒ f(Success(a)), e ⇒ f(Failure(e))) + + def transformWith[B](s: A ⇒ Future[B], f: Throwable ⇒ Future[B])(implicit executor: ExecutionContext): Future[B] = { + def strictTransform[T](x: T, f: T ⇒ Future[B]) = + try f(x) + catch { case NonFatal(e) ⇒ ErrorFuture(e) } + + future match { + case FulfilledFuture(a) ⇒ strictTransform(a, s) + case ErrorFuture(e) ⇒ strictTransform(e, f) + case _ ⇒ future.value match { + case None ⇒ + val p = Promise[B]() + future.onComplete { + case Success(a) ⇒ p completeWith strictTransform(a, s) + case Failure(e) ⇒ p completeWith strictTransform(e, f) + } + p.future + case Some(Success(a)) ⇒ strictTransform(a, s) + case Some(Failure(e)) ⇒ strictTransform(e, f) + } + } + } + + def recover[B >: A](pf: PartialFunction[Throwable, B])(implicit ec: ExecutionContext): Future[B] = + transformWith(FastFuture.successful, t ⇒ if (pf isDefinedAt t) FastFuture.successful(pf(t)) else future) + + def recoverWith[B >: A](pf: PartialFunction[Throwable, Future[B]])(implicit ec: ExecutionContext): Future[B] = + transformWith(FastFuture.successful, t ⇒ pf.applyOrElse(t, (_: Throwable) ⇒ future)) +} + +object FastFuture { + def apply[T](value: Try[T]): Future[T] = value match { + case Success(t) ⇒ FulfilledFuture(t) + case Failure(e) ⇒ ErrorFuture(e) + } + private[this] val _successful: Any ⇒ Future[Any] = FulfilledFuture.apply + def successful[T]: T ⇒ Future[T] = _successful.asInstanceOf[T ⇒ Future[T]] + val failed: Throwable ⇒ Future[Nothing] = ErrorFuture.apply + + private case class FulfilledFuture[+A](a: A) extends Future[A] { + def value = Some(Success(a)) + def onComplete[U](f: Try[A] ⇒ U)(implicit executor: ExecutionContext) = Future.successful(a).onComplete(f) + def isCompleted = true + def result(atMost: Duration)(implicit permit: CanAwait) = a + def ready(atMost: Duration)(implicit permit: CanAwait) = this + def transform[S](f: scala.util.Try[A] ⇒ scala.util.Try[S])(implicit executor: scala.concurrent.ExecutionContext): scala.concurrent.Future[S] = + FastFuture(f(Success(a))) + def transformWith[S](f: scala.util.Try[A] ⇒ scala.concurrent.Future[S])(implicit executor: scala.concurrent.ExecutionContext): scala.concurrent.Future[S] = + new FastFuture(this).transformWith(f) + } + private case class ErrorFuture(error: Throwable) extends Future[Nothing] { + def value = Some(Failure(error)) + def onComplete[U](f: Try[Nothing] ⇒ U)(implicit executor: ExecutionContext) = Future.failed(error).onComplete(f) + def isCompleted = true + def result(atMost: Duration)(implicit permit: CanAwait) = throw error + def ready(atMost: Duration)(implicit permit: CanAwait) = this + def transform[S](f: scala.util.Try[Nothing] ⇒ scala.util.Try[S])(implicit executor: scala.concurrent.ExecutionContext): scala.concurrent.Future[S] = + FastFuture(f(Failure(error))) + def transformWith[S](f: scala.util.Try[Nothing] ⇒ scala.concurrent.Future[S])(implicit executor: scala.concurrent.ExecutionContext): scala.concurrent.Future[S] = + new FastFuture(this).transformWith(f) + } + + implicit class EnhancedFuture[T](val future: Future[T]) extends AnyVal { + def fast: FastFuture[T] = new FastFuture[T](future) + } + + def sequence[T, M[_] <: IterableOnce[_]](in: M[Future[T]])(implicit cbf: BuildFrom[M[Future[T]], T, M[T]], executor: ExecutionContext): Future[M[T]] = + in.iterator.foldLeft(successful(cbf.newBuilder(in))) { + (fr, fa) ⇒ for (r ← fr.fast; a ← fa.asInstanceOf[Future[T]].fast) yield r += a + }.fast.map(_.result()) + + /* FIXME + def fold[T, R](futures: IterableOnce[Future[T]])(zero: R)(f: (R, T) ⇒ R)(implicit executor: ExecutionContext): Future[R] = + if (futures.isEmpty) successful(zero) + else sequence(futures).fast.map(_.foldLeft(zero)(f)) + + def reduce[T, R >: T](futures: IterableOnce[Future[T]])(op: (R, T) ⇒ R)(implicit executor: ExecutionContext): Future[R] = + if (futures.isEmpty) failed(new NoSuchElementException("reduce attempted on empty collection")) + else sequence(futures).fast.map(_ reduceLeft op) +*/ + + def traverse[A, B, M[_] <: IterableOnce[_]](in: M[A])(fn: A ⇒ Future[B])(implicit cbf: BuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] = + in.iterator.foldLeft(successful(cbf.newBuilder(in))) { (fr, a) ⇒ + val fb = fn(a.asInstanceOf[A]) + for (r ← fr.fast; b ← fb.fast) yield r += b + }.fast.map(_.result()) +} diff --git a/akka-http-core/src/main/scala-2.13-/akka/http/ccompat/CompatImpl.scala b/akka-http-core/src/main/scala-2.13-/akka/http/ccompat/CompatImpl.scala new file mode 100644 index 00000000000..a61034dd6ca --- /dev/null +++ b/akka-http-core/src/main/scala-2.13-/akka/http/ccompat/CompatImpl.scala @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2019 Lightbend Inc. + */ + +package akka.http.ccompat + +import scala.collection.generic.CanBuildFrom +import scala.collection.mutable + +/** + * INTERNAL API + * + * Based on https://github.com/scala/scala-collection-compat/blob/master/compat/src/main/scala-2.11_2.12/scala/collection/compat/CompatImpl.scala + * but reproduced here so we don't need to add a dependency on this library. It contains much more than we need right now, and is + * not promising binary compatibility yet at the time of writing. + */ +private[ccompat] object CompatImpl { + def simpleCBF[A, C](f: ⇒ mutable.Builder[A, C]): CanBuildFrom[Any, A, C] = new CanBuildFrom[Any, A, C] { + def apply(from: Any): mutable.Builder[A, C] = apply() + def apply(): mutable.Builder[A, C] = f + } +} diff --git a/akka-http-core/src/main/scala-2.13-/akka/http/ccompat/MapHelpers.scala b/akka-http-core/src/main/scala-2.13-/akka/http/ccompat/MapHelpers.scala new file mode 100644 index 00000000000..9fd6c66201d --- /dev/null +++ b/akka-http-core/src/main/scala-2.13-/akka/http/ccompat/MapHelpers.scala @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2018-2019 Lightbend Inc. + */ + +package akka.http.ccompat + +/** + * INTERNAL API + */ +object MapHelpers { + def convertMapToScala[K, V](jmap: java.util.Map[K, V]): scala.collection.immutable.Map[K, V] = { + import scala.collection.JavaConverters._ + Map.empty ++ jmap.asScala + } +} diff --git a/akka-http-core/src/main/scala-2.13-/akka/http/ccompat/imm/package.scala b/akka-http-core/src/main/scala-2.13-/akka/http/ccompat/imm/package.scala new file mode 100644 index 00000000000..2d2f66776c3 --- /dev/null +++ b/akka-http-core/src/main/scala-2.13-/akka/http/ccompat/imm/package.scala @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018-2019 Lightbend Inc. + */ + +package akka.http.ccompat + +import scala.collection.immutable + +/** + * INTERNAL API + */ +package object imm { + implicit class SortedSetOps[A](val real: immutable.SortedSet[A]) extends AnyVal { + def unsorted: immutable.Set[A] = real + } + + implicit class StreamOps[A](val underlying: immutable.Stream[A]) extends AnyVal { + // renamed in 2.13 + def lazyAppendedAll[B >: A](rest: ⇒ TraversableOnce[B]): Stream[B] = underlying.append(rest) + } +} diff --git a/akka-http-core/src/main/scala-2.13-/akka/http/ccompat/package.scala b/akka-http-core/src/main/scala-2.13-/akka/http/ccompat/package.scala new file mode 100644 index 00000000000..d84eab27639 --- /dev/null +++ b/akka-http-core/src/main/scala-2.13-/akka/http/ccompat/package.scala @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018-2019 Lightbend Inc. + */ + +package akka.http + +import scala.collection.generic.{ CanBuildFrom, GenericCompanion } +import scala.collection.{ GenTraversable, mutable } +import scala.{ collection ⇒ c } + +/** + * INTERNAL API + * + * Partly based on https://github.com/scala/scala-collection-compat/blob/master/compat/src/main/scala-2.11_2.12/scala/collection/compat/PackageShared.scala + * but reproduced here so we don't need to add a dependency on this library. It contains much more than we need right now, and is + * not promising binary compatibility yet at the time of writing. + */ +package object ccompat { + import CompatImpl._ + + implicit def genericCompanionToCBF[A, CC[X] <: GenTraversable[X]]( + fact: GenericCompanion[CC]): CanBuildFrom[Any, A, CC[A]] = + simpleCBF(fact.newBuilder[A]) + + // This really belongs into scala.collection but there's already a package object + // in scala-library so we can't add to it + type IterableOnce[+X] = c.TraversableOnce[X] + val IterableOnce = c.TraversableOnce +} + +/** + * INTERNAL API + */ +package ccompat { + trait Builder[-Elem, +To] extends mutable.Builder[Elem, To] { self ⇒ + // This became final in 2.13 so cannot be overridden there anymore + final override def +=(elem: Elem): this.type = addOne(elem) + def addOne(elem: Elem): this.type = self.+=(elem) + } + + trait QuerySeqOptimized extends scala.collection.immutable.LinearSeq[(String, String)] with scala.collection.LinearSeqOptimized[(String, String), akka.http.scaladsl.model.Uri.Query] { + self: akka.http.scaladsl.model.Uri.Query ⇒ + override def newBuilder: mutable.Builder[(String, String), akka.http.scaladsl.model.Uri.Query] = akka.http.scaladsl.model.Uri.Query.newBuilder + } +} diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/util/FastFuture.scala b/akka-http-core/src/main/scala-2.13-/akka/http/scaladsl/util/FastFuture.scala similarity index 100% rename from akka-http-core/src/main/scala/akka/http/scaladsl/util/FastFuture.scala rename to akka-http-core/src/main/scala-2.13-/akka/http/scaladsl/util/FastFuture.scala diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpHeaderParser.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpHeaderParser.scala index 1795c48e448..30e17c5e536 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpHeaderParser.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpHeaderParser.scala @@ -17,8 +17,9 @@ import akka.http.scaladsl.settings.ParserSettings import scala.annotation.tailrec import akka.parboiled2.CharUtils import akka.util.ByteString +import akka.http.ccompat._ import akka.http.impl.util._ -import akka.http.scaladsl.model._ +import akka.http.scaladsl.model.{ ErrorInfo, HttpHeader, MediaTypes, StatusCode, StatusCodes } import akka.http.scaladsl.model.headers.{ EmptyHeader, RawHeader } import akka.http.impl.model.parser.HeaderParser import akka.http.impl.model.parser.CharacterClasses._ @@ -476,10 +477,10 @@ private[http] object HttpHeaderParser { val valueParsers: Seq[HeaderValueParser] = HeaderParser.ruleNames - .filter(headerParserFilter) + .filter(headerParserFilter).iterator .map { name ⇒ new ModeledHeaderValueParser(name, parser.settings.maxHeaderValueLength, parser.settings.headerValueCacheLimit(name), parser.log, parser.settings) - }(collection.breakOut) + }.to(scala.collection.immutable.IndexedSeq) def insertInGoodOrder(items: Seq[Any])(startIx: Int = 0, endIx: Int = items.size): Unit = if (endIx - startIx > 0) { diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpMessageParser.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpMessageParser.scala index 37840574b8e..2365ab1383b 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpMessageParser.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpMessageParser.scala @@ -14,7 +14,7 @@ import akka.parboiled2.CharUtils import akka.util.ByteString import akka.http.impl.model.parser.CharacterClasses import akka.http.scaladsl.settings.ParserSettings -import akka.http.scaladsl.model._ +import akka.http.scaladsl.model.{ ParsingException ⇒ _, _ } import headers._ import HttpProtocols._ import ParserOutput._ diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpRequestParser.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpRequestParser.scala index 37bfd60fff8..6073d615bb8 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpRequestParser.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpRequestParser.scala @@ -11,7 +11,7 @@ import akka.http.scaladsl.settings.ParserSettings import akka.util.{ ByteString, OptionVal } import akka.http.impl.engine.ws.Handshake import akka.http.impl.model.parser.CharacterClasses -import akka.http.scaladsl.model._ +import akka.http.scaladsl.model.{ ParsingException ⇒ _, _ } import headers._ import StatusCodes._ import ParserOutput._ diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpResponseParser.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpResponseParser.scala index a5393aa9448..17b032184a8 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpResponseParser.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpResponseParser.scala @@ -10,7 +10,7 @@ import scala.util.control.NoStackTrace import akka.http.scaladsl.settings.ParserSettings import akka.http.impl.model.parser.CharacterClasses import akka.util.ByteString -import akka.http.scaladsl.model._ +import akka.http.scaladsl.model.{ ParsingException ⇒ MParsingException, _ } import headers._ import ParserOutput._ import akka.annotation.InternalApi diff --git a/akka-http-core/src/main/scala/akka/http/impl/model/parser/CacheControlHeader.scala b/akka-http-core/src/main/scala/akka/http/impl/model/parser/CacheControlHeader.scala index 8dc8f603535..51c85b164bb 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/model/parser/CacheControlHeader.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/model/parser/CacheControlHeader.scala @@ -23,15 +23,15 @@ private[parser] trait CacheControlHeader { this: Parser with CommonRules with Co | "min-fresh=" ~ `delta-seconds` ~> (`min-fresh`(_)) | "only-if-cached" ~ push(`only-if-cached`) | "public" ~ push(`public`) - | "private" ~ (ws('=') ~ `field-names` ~> (`private`(_: _*)) | push(`private`())) - | "no-cache" ~ (ws('=') ~ `field-names` ~> (`no-cache`(_: _*)) | push(`no-cache`)) + | "private" ~ (ws('=') ~ `field-names` ~> (`private`(_)) | push(`private`())) + | "no-cache" ~ (ws('=') ~ `field-names` ~> (`no-cache`(_)) | push(`no-cache`)) | "must-revalidate" ~ push(`must-revalidate`) | "proxy-revalidate" ~ push(`proxy-revalidate`) | "s-maxage=" ~ `delta-seconds` ~> (`s-maxage`(_)) | "immutable" ~ push(immutableDirective) | token ~ optional(ws('=') ~ word) ~> (CacheDirective.custom(_, _))) - def `field-names` = rule { `quoted-tokens` | token ~> (Seq(_)) } + def `field-names` = rule { `quoted-tokens` | token ~> (List(_)) } def `quoted-tokens` = rule { '"' ~ zeroOrMore(`quoted-tokens-elem`).separatedBy(listSep) ~ '"' } diff --git a/akka-http-core/src/main/scala/akka/http/impl/model/parser/CommonRules.scala b/akka-http-core/src/main/scala/akka/http/impl/model/parser/CommonRules.scala index d45dcd5d182..68c3cf4b56b 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/model/parser/CommonRules.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/model/parser/CommonRules.scala @@ -156,7 +156,7 @@ private[parser] trait CommonRules { this: Parser with StringBuilding ⇒ // http://tools.ietf.org/html/rfc4647#section-2.1 // ****************************************************************************************** def language = rule { - `primary-tag` ~ zeroOrMore('-' ~ `sub-tag`) ~> (Language(_, _: _*)) + `primary-tag` ~ zeroOrMore('-' ~ `sub-tag`) ~> (Language(_, _)) } def `primary-tag` = rule { capture(oneOrMore(ALPHA)) ~ OWS } diff --git a/akka-http-core/src/main/scala/akka/http/impl/model/parser/LinkHeader.scala b/akka-http-core/src/main/scala/akka/http/impl/model/parser/LinkHeader.scala index 1610f4ec6f8..4fd0f09eca6 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/model/parser/LinkHeader.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/model/parser/LinkHeader.scala @@ -5,6 +5,7 @@ package akka.http.impl.model.parser import scala.annotation.tailrec +import scala.collection.immutable import scala.collection.immutable.TreeMap import akka.parboiled2.Parser @@ -20,7 +21,7 @@ private[parser] trait LinkHeader { this: Parser with CommonRules with CommonActi } def `link-value` = rule { - ws('<') ~ UriReference('>') ~ ws('>') ~ oneOrMore(ws(';') ~ `link-param`) ~> (sanitize(_)) ~> (LinkValue(_, _: _*)) + ws('<') ~ UriReference('>') ~ ws('>') ~ oneOrMore(ws(';') ~ `link-param`) ~> (sanitize(_)) ~> (LinkValue(_, _)) } def `link-param` = rule( @@ -67,9 +68,9 @@ private[parser] trait LinkHeader { this: Parser with CommonRules with CommonActi def `link-media-type` = rule { `media-type` ~> ((mt, st, pm) ⇒ getMediaType(mt, st, pm contains "charset", TreeMap(pm: _*))) } // filter out subsequent `rel`, `media`, `title`, `type` and `type*` params - @tailrec private def sanitize(params: Seq[LinkParam], result: Seq[LinkParam] = Nil, seenRel: Boolean = false, + @tailrec private def sanitize(params: Seq[LinkParam], result: immutable.Seq[LinkParam] = Nil, seenRel: Boolean = false, seenMedia: Boolean = false, seenTitle: Boolean = false, seenTitleS: Boolean = false, - seenType: Boolean = false): Seq[LinkParam] = + seenType: Boolean = false): immutable.Seq[LinkParam] = params match { case Seq((x: LinkParams.rel), tail @ _*) ⇒ sanitize(tail, if (seenRel) result else result :+ x, seenRel = true, seenMedia, seenTitle, seenTitleS, seenType) case Seq((x: LinkParams.media), tail @ _*) ⇒ sanitize(tail, if (seenMedia) result else result :+ x, seenRel, seenMedia = true, seenTitle, seenTitleS, seenType) diff --git a/akka-http-core/src/main/scala/akka/http/impl/settings/ClientConnectionSettingsImpl.scala b/akka-http-core/src/main/scala/akka/http/impl/settings/ClientConnectionSettingsImpl.scala index 44d94bd440a..0fbfa7136ec 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/settings/ClientConnectionSettingsImpl.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/settings/ClientConnectionSettingsImpl.scala @@ -44,7 +44,7 @@ private[akka] final case class ClientConnectionSettingsImpl( /** INTERNAL API */ @InternalApi -private[akka] object ClientConnectionSettingsImpl extends SettingsCompanion[ClientConnectionSettingsImpl]("akka.http.client") { +private[akka] object ClientConnectionSettingsImpl extends SettingsCompanionImpl[ClientConnectionSettingsImpl]("akka.http.client") { def fromSubConfig(root: Config, inner: Config): ClientConnectionSettingsImpl = { val c = inner.withFallback(root.getConfig(prefix)) new ClientConnectionSettingsImpl( diff --git a/akka-http-core/src/main/scala/akka/http/impl/settings/ConnectionPoolSettingsImpl.scala b/akka-http-core/src/main/scala/akka/http/impl/settings/ConnectionPoolSettingsImpl.scala index 43f8fe79f22..07659755fc6 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/settings/ConnectionPoolSettingsImpl.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/settings/ConnectionPoolSettingsImpl.scala @@ -5,7 +5,7 @@ package akka.http.impl.settings import akka.annotation.InternalApi -import akka.http.impl.util.{ SettingsCompanion, _ } +import akka.http.impl.util._ import akka.http.scaladsl.settings.{ ClientConnectionSettings, ConnectionPoolSettings, PoolImplementation } import com.typesafe.config.Config @@ -58,7 +58,7 @@ private[akka] final case class ConnectionPoolSettingsImpl( /** INTERNAL API */ @InternalApi -private[akka] object ConnectionPoolSettingsImpl extends SettingsCompanion[ConnectionPoolSettingsImpl]("akka.http.host-connection-pool") { +private[akka] object ConnectionPoolSettingsImpl extends SettingsCompanionImpl[ConnectionPoolSettingsImpl]("akka.http.host-connection-pool") { def fromSubConfig(root: Config, c: Config): ConnectionPoolSettingsImpl = { new ConnectionPoolSettingsImpl( c.getInt("max-connections"), diff --git a/akka-http-core/src/main/scala/akka/http/impl/settings/HttpsProxySettingsImpl.scala b/akka-http-core/src/main/scala/akka/http/impl/settings/HttpsProxySettingsImpl.scala index 19d83d0e62e..3da5b75caf2 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/settings/HttpsProxySettingsImpl.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/settings/HttpsProxySettingsImpl.scala @@ -5,7 +5,7 @@ package akka.http.impl.settings import akka.annotation.InternalApi -import akka.http.impl.util.SettingsCompanion +import akka.http.impl.util.SettingsCompanionImpl import com.typesafe.config.Config /** INTERNAL API */ @@ -20,7 +20,7 @@ private[http] final case class HttpsProxySettingsImpl( override def productPrefix = "HttpsProxySettings" } -object HttpsProxySettingsImpl extends SettingsCompanion[HttpsProxySettingsImpl]("akka.http.client.proxy.https") { +object HttpsProxySettingsImpl extends SettingsCompanionImpl[HttpsProxySettingsImpl]("akka.http.client.proxy.https") { override def fromSubConfig(root: Config, c: Config): HttpsProxySettingsImpl = { new HttpsProxySettingsImpl( c.getString("host"), diff --git a/akka-http-core/src/main/scala/akka/http/impl/settings/ParserSettingsImpl.scala b/akka-http-core/src/main/scala/akka/http/impl/settings/ParserSettingsImpl.scala index 805797d7b32..00af4cceec8 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/settings/ParserSettingsImpl.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/settings/ParserSettingsImpl.scala @@ -58,7 +58,7 @@ private[akka] final case class ParserSettingsImpl( override def productPrefix = "ParserSettings" } -object ParserSettingsImpl extends SettingsCompanion[ParserSettingsImpl]("akka.http.parsing") { +object ParserSettingsImpl extends SettingsCompanionImpl[ParserSettingsImpl]("akka.http.parsing") { private[this] val noCustomMethods: String ⇒ Option[HttpMethod] = ConstantFun.scalaAnyToNone private[this] val noCustomStatusCodes: Int ⇒ Option[StatusCode] = ConstantFun.scalaAnyToNone @@ -85,7 +85,7 @@ object ParserSettingsImpl extends SettingsCompanion[ParserSettingsImpl]("akka.ht c.getStringList("ignore-illegal-header-for").asScala.map(_.toLowerCase).toSet, ErrorLoggingVerbosity(c.getString("error-logging-verbosity")), IllegalResponseHeaderValueProcessingMode(c.getString("illegal-response-header-value-processing-mode")), - cacheConfig.entrySet.asScala.map(kvp ⇒ kvp.getKey → cacheConfig.getInt(kvp.getKey))(collection.breakOut), + cacheConfig.entrySet.asScala.iterator.map(kvp ⇒ kvp.getKey → cacheConfig.getInt(kvp.getKey)).toMap, c.getBoolean("tls-session-info-header"), c.getBoolean("modeled-header-parsing"), noCustomMethods, diff --git a/akka-http-core/src/main/scala/akka/http/impl/settings/PreviewServerSettingsImpl.scala b/akka-http-core/src/main/scala/akka/http/impl/settings/PreviewServerSettingsImpl.scala index 533ccab98d1..d640190e1b3 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/settings/PreviewServerSettingsImpl.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/settings/PreviewServerSettingsImpl.scala @@ -5,7 +5,7 @@ package akka.http.impl.settings import akka.annotation.InternalApi -import akka.http.impl.util.SettingsCompanion +import akka.http.impl.util.SettingsCompanionImpl import com.typesafe.config.Config @InternalApi @@ -16,7 +16,7 @@ private[http] final case class PreviewServerSettingsImpl( override def productPrefix: String = "PreviewServerSettings" } -object PreviewServerSettingsImpl extends SettingsCompanion[PreviewServerSettingsImpl]("akka.http.server.preview") { +object PreviewServerSettingsImpl extends SettingsCompanionImpl[PreviewServerSettingsImpl]("akka.http.server.preview") { def fromSubConfig(root: Config, c: Config) = PreviewServerSettingsImpl( c.getBoolean("enable-http2") ) diff --git a/akka-http-core/src/main/scala/akka/http/impl/settings/ServerSettingsImpl.scala b/akka-http-core/src/main/scala/akka/http/impl/settings/ServerSettingsImpl.scala index b26e6c37f61..18d20d69697 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/settings/ServerSettingsImpl.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/settings/ServerSettingsImpl.scala @@ -58,7 +58,7 @@ private[akka] final case class ServerSettingsImpl( /** INTERNAL API */ @InternalApi -private[http] object ServerSettingsImpl extends SettingsCompanion[ServerSettingsImpl]("akka.http.server") { +private[http] object ServerSettingsImpl extends SettingsCompanionImpl[ServerSettingsImpl]("akka.http.server") { implicit def timeoutsShortcut(s: js.ServerSettings): js.ServerSettings.Timeouts = s.getTimeouts final case class Timeouts( diff --git a/akka-http-core/src/main/scala/akka/http/impl/util/EnhancedByteStringTraversableOnce.scala b/akka-http-core/src/main/scala/akka/http/impl/util/EnhancedByteStringTraversableOnce.scala index 353b5ea965f..5ee4542c430 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/util/EnhancedByteStringTraversableOnce.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/util/EnhancedByteStringTraversableOnce.scala @@ -5,12 +5,13 @@ package akka.http.impl.util import akka.annotation.InternalApi +import akka.http.ccompat._ import akka.util.ByteString /** * INTERNAL API */ @InternalApi -private[http] class EnhancedByteStringTraversableOnce(val byteStrings: TraversableOnce[ByteString]) extends AnyVal { +private[http] class EnhancedByteStringTraversableOnce(val byteStrings: IterableOnce[ByteString]) extends AnyVal { def join: ByteString = byteStrings.foldLeft(ByteString.empty)(_ ++ _) } diff --git a/akka-http-core/src/main/scala/akka/http/impl/util/Rendering.scala b/akka-http-core/src/main/scala/akka/http/impl/util/Rendering.scala index b1705c36b1b..c3426bfb0fc 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/util/Rendering.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/util/Rendering.scala @@ -118,9 +118,9 @@ private[http] object Renderer { def defaultSeqRenderer[T: Renderer] = genericSeqRenderer[Renderable, T](Rendering.`, `, Rendering.Empty) def seqRenderer[T: Renderer](separator: String = ", ", empty: String = "") = genericSeqRenderer[String, T](separator, empty) - def genericSeqRenderer[S, T](separator: S, empty: S)(implicit sRenderer: Renderer[S], tRenderer: Renderer[T]): Renderer[immutable.Seq[T]] = - new Renderer[immutable.Seq[T]] { - def render[R <: Rendering](r: R, value: immutable.Seq[T]): r.type = { + def genericSeqRenderer[S, T](separator: S, empty: S)(implicit sRenderer: Renderer[S], tRenderer: Renderer[T]): Renderer[immutable.Iterable[T]] = + new Renderer[immutable.Iterable[T]] { + def render[R <: Rendering](r: R, value: immutable.Iterable[T]): r.type = { @tailrec def recI(values: IndexedSeq[T], ix: Int = 0): r.type = if (ix < values.size) { if (ix > 0) sRenderer.render(r, separator) diff --git a/akka-http-core/src/main/scala/akka/http/impl/util/SettingsCompanion.scala b/akka-http-core/src/main/scala/akka/http/impl/util/SettingsCompanionImpl.scala similarity index 91% rename from akka-http-core/src/main/scala/akka/http/impl/util/SettingsCompanion.scala rename to akka-http-core/src/main/scala/akka/http/impl/util/SettingsCompanionImpl.scala index e685fc79de9..7f81650bbe7 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/util/SettingsCompanion.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/util/SettingsCompanionImpl.scala @@ -19,7 +19,7 @@ import akka.annotation.InternalApi * INTERNAL API */ @InternalApi -private[http] abstract class SettingsCompanion[T](protected val prefix: String) { +private[http] abstract class SettingsCompanionImpl[T](protected val prefix: String) { private final val MaxCached = 8 private[this] var cache = ListMap.empty[ActorSystem, T] @@ -44,7 +44,7 @@ private[http] abstract class SettingsCompanion[T](protected val prefix: String) def apply(configOverrides: String): T = apply(parseString(configOverrides) - .withFallback(SettingsCompanion.configAdditions) + .withFallback(SettingsCompanionImpl.configAdditions) .withFallback(defaultReference(getClass.getClassLoader))) def apply(config: Config): T = @@ -53,7 +53,7 @@ private[http] abstract class SettingsCompanion[T](protected val prefix: String) def fromSubConfig(root: Config, c: Config): T } -private[http] object SettingsCompanion { +private[http] object SettingsCompanionImpl { lazy val configAdditions: Config = { val localHostName = try new InetSocketAddress(InetAddress.getLocalHost, 80).getHostString diff --git a/akka-http-core/src/main/scala/akka/http/impl/util/Timestamp.scala b/akka-http-core/src/main/scala/akka/http/impl/util/Timestamp.scala index 911b8830c7b..7ad22acf71f 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/util/Timestamp.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/util/Timestamp.scala @@ -19,7 +19,7 @@ private[http] class Timestamp private (val timestampNanos: Long) extends AnyVal def +(period: Duration): Timestamp = if (isNever) this - else if (!period.isFinite()) Timestamp.never + else if (!period.isFinite) Timestamp.never else new Timestamp(timestampNanos + period.toNanos) def -(other: Timestamp): Duration = diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/HttpMessage.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/HttpMessage.scala index 0f285e94797..04bd9bcafa9 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/HttpMessage.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/HttpMessage.scala @@ -21,6 +21,7 @@ import akka.Done import akka.parboiled2.CharUtils import akka.stream.Materializer import akka.util.{ ByteString, HashCode, OptionVal } +import akka.http.ccompat.{ pre213, since213 } import akka.http.impl.util._ import akka.http.javadsl.{ model ⇒ jm } import akka.http.scaladsl.util.FastFuture._ @@ -67,15 +68,22 @@ sealed trait HttpMessage extends jm.HttpMessage { def discardEntityBytes(mat: Materializer): HttpMessage.DiscardedEntity = entity.discardBytes()(mat) /** Returns a copy of this message with the list of headers set to the given ones. */ + @pre213 def withHeaders(headers: HttpHeader*): Self = withHeaders(headers.toList) /** Returns a copy of this message with the list of headers set to the given ones. */ def withHeaders(headers: immutable.Seq[HttpHeader]): Self + /** Returns a copy of this message with the list of headers set to the given ones. */ + @since213 + def withHeaders(firstHeader: HttpHeader, otherHeaders: HttpHeader*): Self = + withHeaders(firstHeader +: otherHeaders.toList) + /** * Returns a new message that contains all of the given default headers which didn't already * exist (by case-insensitive header name) in this message. */ + @pre213 def withDefaultHeaders(defaultHeaders: HttpHeader*): Self = withDefaultHeaders(defaultHeaders.toList) /** @@ -88,6 +96,10 @@ sealed trait HttpMessage extends jm.HttpMessage { else defaultHeaders.foldLeft(headers) { (acc, h) ⇒ if (headers.exists(_ is h.lowercaseName)) acc else h +: acc } } + @since213 + def withDefaultHeaders(firstHeader: HttpHeader, otherHeaders: HttpHeader*): Self = + withDefaultHeaders(firstHeader +: otherHeaders.toList) + /** Returns a copy of this message with the entity set to the given one. */ def withEntity(entity: MessageEntity): Self diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/Multipart.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/Multipart.scala index 7fb94765a58..624fc1c0c5e 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/Multipart.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/Multipart.scala @@ -19,6 +19,7 @@ import akka.util.ConstantFun import akka.stream.Materializer import akka.stream.javadsl.{ Source ⇒ JSource } import akka.stream.scaladsl._ +import akka.http.ccompat._ import akka.http.scaladsl.util.FastFuture import akka.http.scaladsl.model.headers._ import akka.http.impl.engine.rendering.BodyPartRenderer @@ -357,7 +358,7 @@ object Multipart { /** INTERNAL API */ @InternalApi private[akka] def createStrict(fields: Map[String, akka.http.javadsl.model.HttpEntity.Strict]): Multipart.FormData.Strict = Multipart.FormData.Strict { - fields.map { case (name, entity: akka.http.scaladsl.model.HttpEntity.Strict) ⇒ Multipart.FormData.BodyPart.Strict(name, entity) }(collection.breakOut) + fields.iterator.map { case (name, entity: akka.http.scaladsl.model.HttpEntity.Strict) ⇒ Multipart.FormData.BodyPart.Strict(name, entity) }.to(scala.collection.immutable.IndexedSeq) } /** INTERNAL API */ @InternalApi @@ -366,7 +367,7 @@ object Multipart { } def apply(fields: Map[String, HttpEntity.Strict]): Multipart.FormData.Strict = Multipart.FormData.Strict { - fields.map { case (name, entity) ⇒ Multipart.FormData.BodyPart.Strict(name, entity) }(collection.breakOut) + fields.iterator.map { case (name, entity) ⇒ Multipart.FormData.BodyPart.Strict(name, entity) }.to(scala.collection.immutable.IndexedSeq) } def apply(_parts: Source[Multipart.FormData.BodyPart, Any]): Multipart.FormData = @@ -508,7 +509,7 @@ object Multipart { def create(_name: String, _entity: BodyPartEntity, _additionalDispositionParams: Map[String, String], _additionalHeaders: Iterable[akka.http.javadsl.model.HttpHeader]): Multipart.FormData.BodyPart = { - val _headers = _additionalHeaders.to[immutable.Seq] map { case h: akka.http.scaladsl.model.HttpHeader ⇒ h } + val _headers = _additionalHeaders.to(immutable.Seq) map { case h: akka.http.scaladsl.model.HttpHeader ⇒ h } apply(_name, _entity, _additionalDispositionParams, _headers) } } @@ -519,7 +520,7 @@ object Multipart { def createStrict(_name: String, _entity: HttpEntity.Strict, _additionalDispositionParams: Map[String, String], _additionalHeaders: Iterable[akka.http.javadsl.model.HttpHeader]): Multipart.FormData.BodyPart.Strict = { - val _headers = _additionalHeaders.to[immutable.Seq] map { case h: akka.http.scaladsl.model.HttpHeader ⇒ h } + val _headers = _additionalHeaders.to(immutable.Seq) map { case h: akka.http.scaladsl.model.HttpHeader ⇒ h } Strict(_name, _entity, _additionalDispositionParams, _headers) } } diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/Uri.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/Uri.scala index 4bfdef94b07..049351199ff 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/Uri.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/Uri.scala @@ -10,9 +10,10 @@ import java.lang.{ Iterable, StringBuilder ⇒ JStringBuilder } import java.nio.charset.Charset import scala.annotation.tailrec -import scala.collection.{ LinearSeqOptimized, immutable, mutable } +import scala.collection.{ immutable, mutable } import scala.collection.immutable.LinearSeq import akka.parboiled2.{ CharPredicate, CharUtils, ParserInput } +import akka.http.ccompat.{ QuerySeqOptimized, Builder } import akka.http.javadsl.{ model ⇒ jm } import akka.http.impl.model.parser.UriParser import akka.http.impl.model.parser.CharacterClasses._ @@ -580,7 +581,7 @@ object Uri { } } - sealed abstract class Query extends LinearSeq[(String, String)] with LinearSeqOptimized[(String, String), Query] { + sealed abstract class Query extends QuerySeqOptimized { def key: String def value: String def +:(kvp: (String, String)) = Query.Cons(kvp._1, kvp._2, this) @@ -623,7 +624,6 @@ object Uri { if (q.isEmpty) map else append(map.updated(q.key, map.getOrElse(q.key, Nil) :+ q.value), q.tail) append(Map.empty, this) } - override def newBuilder: mutable.Builder[(String, String), Query] = Query.newBuilder override def toString = UriRendering.QueryRenderer.render(new StringRendering, this).get } object Query { @@ -648,11 +648,13 @@ object Uri { params.foldRight(Query.Empty: Query) { case ((key, value), acc) ⇒ Cons(key, value, acc) } def apply(params: Map[String, String]): Query = apply(params.toSeq: _*) - def newBuilder: mutable.Builder[(String, String), Query] = new mutable.Builder[(String, String), Query] { + def newBuilder: mutable.Builder[(String, String), Query] = new Builder[(String, String), Query] { val b = mutable.ArrayBuffer.newBuilder[(String, String)] - def +=(elem: (String, String)): this.type = { b += elem; this } + override def addOne(elem: (String, String)): this.type = { b += elem; this } def clear() = b.clear() - def result() = apply(b.result(): _*) + def result() = { + apply(b.result().toSeq: _*) + } } case object Empty extends Query { diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/CacheDirective.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/CacheDirective.scala index 6832257794b..525819ae23a 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/CacheDirective.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/CacheDirective.scala @@ -10,6 +10,7 @@ import scala.annotation.{ tailrec, varargs } import scala.collection.immutable import akka.http.impl.util._ import akka.http.javadsl.{ model ⇒ jm } +import akka.http.ccompat.{ pre213, since213 } sealed trait CacheDirective extends Renderable with jm.headers.CacheDirective { def value: String @@ -82,7 +83,12 @@ object CacheDirectives { * http://tools.ietf.org/html/rfc7234#section-5.2.1.4 */ case object `no-cache` extends SingletonValueRenderable with RequestDirective with ResponseDirective { - def apply(fieldNames: String*): `no-cache` = new `no-cache`(immutable.Seq(fieldNames: _*)) + @pre213 + def apply(fieldNames: String*): `no-cache` = + new `no-cache`(immutable.Seq(fieldNames: _*)) + @since213 + def apply(firstFieldName: String, otherFieldNames: String*): `no-cache` = + new `no-cache`(firstFieldName +: otherFieldNames.toList) } /** @@ -132,7 +138,12 @@ object CacheDirectives { */ final case class `private`(fieldNames: immutable.Seq[String]) extends FieldNamesDirective with ResponseDirective object `private` { + @pre213 def apply(fieldNames: String*): `private` = new `private`(immutable.Seq(fieldNames: _*)) + @since213 + def apply(): `private` = new `private`(immutable.Seq.empty) + @since213 + def apply(firstFieldName: String, otherFieldNames: String*): `private` = new `private`(firstFieldName +: otherFieldNames) } /** Java API */ diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/HttpOrigin.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/HttpOrigin.scala index 9909da88916..194da6ddb43 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/HttpOrigin.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/HttpOrigin.scala @@ -7,6 +7,7 @@ package akka.http.scaladsl.model.headers import language.implicitConversions import scala.collection.immutable import akka.parboiled2.UTF8 +import akka.http.ccompat import akka.http.impl.model.parser.UriParser import akka.http.impl.util._ import akka.http.javadsl.{ model ⇒ jm } diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/LanguageRange.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/LanguageRange.scala index 568f5f9ace4..f0ae38963d7 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/LanguageRange.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/LanguageRange.scala @@ -10,6 +10,7 @@ import akka.http.impl.util._ import akka.http.scaladsl.model.WithQValue import akka.http.javadsl.{ model ⇒ jm } import akka.http.impl.util.JavaMapping.Implicits._ +import akka.http.ccompat.{ pre213, since213 } sealed trait LanguageRange extends jm.headers.LanguageRange with ValueRenderable with WithQValue[LanguageRange] { def qValue: Float @@ -71,5 +72,11 @@ object Language { val tags = compoundTag.split('-') new Language(tags.head, immutable.Seq(tags.tail: _*)) } else new Language(compoundTag, immutable.Seq.empty) - def apply(primaryTag: String, subTags: String*): Language = new Language(primaryTag, immutable.Seq(subTags: _*)) + @pre213 + def apply(primaryTag: String, subTags: String*): Language = + new Language(primaryTag, immutable.Seq(subTags: _*)) + @since213 + def apply(primaryTag: String, firstSubTag: String, otherSubTags: String*): Language = + new Language(primaryTag, firstSubTag +: otherSubTags) + } diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/LinkValue.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/LinkValue.scala index 7ec6cea071a..4d9c21a20c8 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/LinkValue.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/LinkValue.scala @@ -11,6 +11,7 @@ import akka.http.scaladsl.model._ import akka.http.javadsl.{ model ⇒ jm } import akka.http.impl.util.JavaMapping.Implicits._ import UriRendering.UriRenderer +import akka.http.ccompat.{ pre213, since213 } final case class LinkValue(uri: Uri, params: immutable.Seq[LinkParam]) extends jm.headers.LinkValue with ValueRenderable { def render[R <: Rendering](r: R): r.type = { @@ -24,7 +25,10 @@ final case class LinkValue(uri: Uri, params: immutable.Seq[LinkParam]) extends j } object LinkValue { + @pre213 def apply(uri: Uri, params: LinkParam*): LinkValue = apply(uri, immutable.Seq(params: _*)) + @since213 + def apply(uri: Uri, firstParam: LinkParam, otherParams: LinkParam*): LinkValue = apply(uri, firstParam +: otherParams) } sealed abstract class LinkParam extends jm.headers.LinkParam with ToStringRenderable { diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/headers.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/headers.scala index ae5d6940db8..a7ced18ba64 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/headers.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/headers.scala @@ -8,8 +8,8 @@ import java.lang.Iterable import java.net.InetSocketAddress import java.security.MessageDigest import java.util -import javax.net.ssl.SSLSession +import javax.net.ssl.SSLSession import akka.annotation.{ ApiMayChange, InternalApi } import akka.stream.scaladsl.ScalaSessionAPI @@ -19,6 +19,7 @@ import scala.annotation.tailrec import scala.collection.immutable import akka.parboiled2.util.Base64 import akka.event.Logging +import akka.http.ccompat.{ pre213, since213 } import akka.http.impl.util._ import akka.http.javadsl.{ model ⇒ jm } import akka.http.scaladsl.model._ @@ -125,7 +126,12 @@ import akka.http.impl.util.JavaMapping.Implicits._ // http://tools.ietf.org/html/rfc7231#section-5.3.2 object Accept extends ModeledCompanion[Accept] { - def apply(mediaRanges: MediaRange*): Accept = apply(immutable.Seq(mediaRanges: _*)) + @pre213 + def apply(mediaRanges: MediaRange*): Accept = + apply(immutable.Seq(mediaRanges: _*)) + @since213 + def apply(firstMediaRange: MediaRange, otherMediaRanges: MediaRange*): Accept = + apply(firstMediaRange +: otherMediaRanges) implicit val mediaRangesRenderer = Renderer.defaultSeqRenderer[MediaRange] // cache } final case class Accept(mediaRanges: immutable.Seq[MediaRange]) extends jm.headers.Accept with RequestHeader { @@ -156,7 +162,15 @@ final case class `Accept-Charset`(charsetRanges: immutable.Seq[HttpCharsetRange] // http://tools.ietf.org/html/rfc7231#section-5.3.4 object `Accept-Encoding` extends ModeledCompanion[`Accept-Encoding`] { - def apply(encodings: HttpEncodingRange*): `Accept-Encoding` = apply(immutable.Seq(encodings: _*)) + @pre213 + def apply(encodings: HttpEncodingRange*): `Accept-Encoding` = + apply(immutable.Seq(encodings: _*)) + @since213 + def apply(): `Accept-Encoding` = + apply(immutable.Seq.empty) + @since213 + def apply(firstEncoding: HttpEncodingRange, otherEncodings: HttpEncodingRange*): `Accept-Encoding` = + apply(firstEncoding +: otherEncodings) implicit val encodingsRenderer = Renderer.defaultSeqRenderer[HttpEncodingRange] // cache } final case class `Accept-Encoding`(encodings: immutable.Seq[HttpEncodingRange]) extends jm.headers.AcceptEncoding @@ -187,7 +201,15 @@ final case class `Accept-Language`(languages: immutable.Seq[LanguageRange]) exte // http://tools.ietf.org/html/rfc7233#section-2.3 object `Accept-Ranges` extends ModeledCompanion[`Accept-Ranges`] { - def apply(rangeUnits: RangeUnit*): `Accept-Ranges` = apply(immutable.Seq(rangeUnits: _*)) + @pre213 + def apply(rangeUnits: RangeUnit*): `Accept-Ranges` = + apply(immutable.Seq(rangeUnits: _*)) + @since213 + def apply(): `Accept-Ranges` = + apply(immutable.Seq.empty) + @since213 + def apply(firstRangeUnit: RangeUnit, otherRangeUnits: RangeUnit*): `Accept-Ranges` = + apply(firstRangeUnit +: otherRangeUnits) implicit val rangeUnitsRenderer = Renderer.defaultSeqRenderer[RangeUnit] // cache } final case class `Accept-Ranges`(rangeUnits: immutable.Seq[RangeUnit]) extends jm.headers.AcceptRanges @@ -210,7 +232,12 @@ final case class `Access-Control-Allow-Credentials`(allow: Boolean) // http://www.w3.org/TR/cors/#access-control-allow-headers-response-header object `Access-Control-Allow-Headers` extends ModeledCompanion[`Access-Control-Allow-Headers`] { - def apply(headers: String*): `Access-Control-Allow-Headers` = apply(immutable.Seq(headers: _*)) + @pre213 + def apply(headers: String*): `Access-Control-Allow-Headers` = + apply(immutable.Seq(headers: _*)) + @since213 + def apply(firstHeader: String, otherHeaders: String*): `Access-Control-Allow-Headers` = + apply(firstHeader +: otherHeaders) implicit val headersRenderer = Renderer.defaultSeqRenderer[String] // cache } final case class `Access-Control-Allow-Headers`(headers: immutable.Seq[String]) @@ -225,7 +252,12 @@ final case class `Access-Control-Allow-Headers`(headers: immutable.Seq[String]) // http://www.w3.org/TR/cors/#access-control-allow-methods-response-header object `Access-Control-Allow-Methods` extends ModeledCompanion[`Access-Control-Allow-Methods`] { - def apply(methods: HttpMethod*): `Access-Control-Allow-Methods` = apply(immutable.Seq(methods: _*)) + @pre213 + def apply(methods: HttpMethod*): `Access-Control-Allow-Methods` = + apply(immutable.Seq(methods: _*)) + @since213 + def apply(firstMethod: HttpMethod, otherMethods: HttpMethod*): `Access-Control-Allow-Methods` = + apply(firstMethod +: otherMethods) implicit val methodsRenderer = Renderer.defaultSeqRenderer[HttpMethod] // cache } final case class `Access-Control-Allow-Methods`(methods: immutable.Seq[HttpMethod]) @@ -261,7 +293,12 @@ final case class `Access-Control-Allow-Origin` private (range: HttpOriginRange) // http://www.w3.org/TR/cors/#access-control-expose-headers-response-header object `Access-Control-Expose-Headers` extends ModeledCompanion[`Access-Control-Expose-Headers`] { - def apply(headers: String*): `Access-Control-Expose-Headers` = apply(immutable.Seq(headers: _*)) + @pre213 + def apply(headers: String*): `Access-Control-Expose-Headers` = + apply(immutable.Seq(headers: _*)) + @since213 + def apply(firstHeader: String, otherHeaders: String*): `Access-Control-Expose-Headers` = + apply(firstHeader +: otherHeaders) implicit val headersRenderer = Renderer.defaultSeqRenderer[String] // cache } final case class `Access-Control-Expose-Headers`(headers: immutable.Seq[String]) @@ -284,7 +321,12 @@ final case class `Access-Control-Max-Age`(deltaSeconds: Long) extends jm.headers // http://www.w3.org/TR/cors/#access-control-request-headers-request-header object `Access-Control-Request-Headers` extends ModeledCompanion[`Access-Control-Request-Headers`] { - def apply(headers: String*): `Access-Control-Request-Headers` = apply(immutable.Seq(headers: _*)) + @pre213 + def apply(headers: String*): `Access-Control-Request-Headers` = + apply(immutable.Seq(headers: _*)) + @since213 + def apply(firstHeader: String, otherHeaders: String*): `Access-Control-Request-Headers` = + apply(firstHeader +: otherHeaders) implicit val headersRenderer = Renderer.defaultSeqRenderer[String] // cache } final case class `Access-Control-Request-Headers`(headers: immutable.Seq[String]) @@ -314,7 +356,15 @@ final case class Age(deltaSeconds: Long) extends jm.headers.Age with ResponseHea // http://tools.ietf.org/html/rfc7231#section-7.4.1 object Allow extends ModeledCompanion[Allow] { - def apply(methods: HttpMethod*): Allow = apply(immutable.Seq(methods: _*)) + @pre213 + def apply(methods: HttpMethod*): Allow = + apply(immutable.Seq(methods: _*)) + @since213 + def apply(): `Allow` = + apply(immutable.Seq.empty) + @since213 + def apply(firstMethod: HttpMethod, otherMethods: HttpMethod*): Allow = + apply(firstMethod +: otherMethods) implicit val methodsRenderer = Renderer.defaultSeqRenderer[HttpMethod] // cache } final case class Allow(methods: immutable.Seq[HttpMethod]) extends jm.headers.Allow with ResponseHeader { @@ -448,7 +498,10 @@ final case class `Content-Type` private[http] (contentType: ContentType) extends object Cookie extends ModeledCompanion[Cookie] { def apply(first: HttpCookiePair, more: HttpCookiePair*): Cookie = apply(immutable.Seq(first +: more: _*)) def apply(name: String, value: String): Cookie = apply(HttpCookiePair(name, value)) + @pre213 def apply(values: (String, String)*): Cookie = apply(values.map(HttpCookiePair(_)).toList) + @since213 + def apply(first: (String, String), more: (String, String)*): Cookie = apply((first +: more).map(HttpCookiePair(_))) implicit val cookiePairsRenderer = Renderer.seqRenderer[HttpCookiePair](separator = "; ") // cache } final case class Cookie(cookies: immutable.Seq[HttpCookiePair]) extends jm.headers.Cookie with RequestHeader { @@ -591,8 +644,12 @@ final case class `Last-Modified`(date: DateTime) extends jm.headers.LastModified // http://tools.ietf.org/html/rfc5988#section-5 object Link extends ModeledCompanion[Link] { - def apply(uri: Uri, first: LinkParam, more: LinkParam*): Link = apply(immutable.Seq(LinkValue(uri, first +: more: _*))) + def apply(uri: Uri, first: LinkParam, more: LinkParam*): Link = apply(immutable.Seq(LinkValue(uri, first +: more.toList))) + @pre213 def apply(values: LinkValue*): Link = apply(immutable.Seq(values: _*)) + @since213 + def apply(firstValue: LinkValue, otherValues: LinkValue*): Link = apply(firstValue +: otherValues) + implicit val valuesRenderer = Renderer.defaultSeqRenderer[LinkValue] // cache } final case class Link(values: immutable.Seq[LinkValue]) extends jm.headers.Link with RequestResponseHeader { @@ -616,7 +673,10 @@ final case class Location(uri: Uri) extends jm.headers.Location with ResponseHea // http://tools.ietf.org/html/rfc6454#section-7 object Origin extends ModeledCompanion[Origin] { + @pre213 def apply(origins: HttpOrigin*): Origin = apply(immutable.Seq(origins: _*)) + @since213 + def apply(firstOrigin: HttpOrigin, otherOrigins: HttpOrigin*): Origin = apply(firstOrigin +: otherOrigins) } final case class Origin(origins: immutable.Seq[HttpOrigin]) extends jm.headers.Origin with RequestHeader { def renderValue[R <: Rendering](r: R): r.type = if (origins.isEmpty) r ~~ "null" else r ~~ origins diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/settings/Http2ServerSettings.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/settings/Http2ServerSettings.scala index c67914fab76..13804224d5d 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/settings/Http2ServerSettings.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/settings/Http2ServerSettings.scala @@ -56,7 +56,7 @@ object Http2ServerSettings extends SettingsCompanion[Http2ServerSettings] { require(incomingStreamLevelBufferSize > 0, "incoming-stream-level-buffer-size must be > 0") } - private[http] object Http2ServerSettingsImpl extends akka.http.impl.util.SettingsCompanion[Http2ServerSettingsImpl]("akka.http.server.http2") { + private[http] object Http2ServerSettingsImpl extends akka.http.impl.util.SettingsCompanionImpl[Http2ServerSettingsImpl]("akka.http.server.http2") { def fromSubConfig(root: Config, c: Config): Http2ServerSettingsImpl = Http2ServerSettingsImpl( maxConcurrentStreams = c.getInt("max-concurrent-streams"), requestEntityChunkSize = c.getIntBytes("request-entity-chunk-size"), diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/settings/ServerSettings.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/settings/ServerSettings.scala index 85fa4344fe8..2069d75c634 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/settings/ServerSettings.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/settings/ServerSettings.scala @@ -8,8 +8,8 @@ import java.util.Random import java.util.function.Supplier import akka.annotation.DoNotInherit -import akka.http.impl.util._ import akka.http.impl.settings.ServerSettingsImpl +import akka.http.impl.util._ import akka.http.impl.util.JavaMapping.Implicits._ import akka.http.javadsl.{ settings ⇒ js } import akka.http.scaladsl.model.HttpResponse diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/parsing/HttpHeaderParserSpec.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/parsing/HttpHeaderParserSpec.scala index b42b27f14aa..62e756419f4 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/engine/parsing/HttpHeaderParserSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/parsing/HttpHeaderParserSpec.scala @@ -202,7 +202,7 @@ abstract class HttpHeaderParserSpec(mode: String, newLine: String) extends WordS "continue parsing raw headers even if the overall cache value capacity is reached" in new TestSetup() { val randomHeaders = Stream.continually { val name = nextRandomString(nextRandomAlphaNumChar _, nextRandomInt(4, 16)) - val value = nextRandomString(nextRandomPrintableChar, nextRandomInt(4, 16)) + val value = nextRandomString(() ⇒ nextRandomPrintableChar, nextRandomInt(4, 16)) RawHeader(name, value) } randomHeaders.take(300).foldLeft(0) { @@ -234,7 +234,7 @@ abstract class HttpHeaderParserSpec(mode: String, newLine: String) extends WordS "continue parsing raw headers even if the header-specific cache capacity is reached" in new TestSetup() { val randomHeaders = Stream.continually { - val value = nextRandomString(nextRandomPrintableChar, nextRandomInt(4, 16)) + val value = nextRandomString(() ⇒ nextRandomPrintableChar, nextRandomInt(4, 16)) RawHeader("Fancy", value) } randomHeaders.take(20).foldLeft(0) { diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/server/HttpServerSpec.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/server/HttpServerSpec.scala index aa7c3ac6044..46a5bb715fb 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/engine/server/HttpServerSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/server/HttpServerSpec.scala @@ -1061,7 +1061,7 @@ class HttpServerSpec extends AkkaSpec( "have a programmatically set timeout handler" in assertAllStagesStopped(new RequestTimeoutTestSetup(400.millis) { send("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") val timeoutResponse = HttpResponse(StatusCodes.InternalServerError, entity = "OOPS!") - expectRequest().header[`Timeout-Access`].foreach(_.timeoutAccess.updateHandler(_ ⇒ timeoutResponse)) + expectRequest().header[`Timeout-Access`].foreach(_.timeoutAccess.updateHandler((_: HttpRequest) ⇒ timeoutResponse)) scheduler.timePasses(500.millis) expectResponseWithWipedDate( diff --git a/akka-http-core/src/test/scala/akka/http/javadsl/model/JavaApiSpec.scala b/akka-http-core/src/test/scala/akka/http/javadsl/model/JavaApiSpec.scala index cab54eaca0d..907191d9a3a 100644 --- a/akka-http-core/src/test/scala/akka/http/javadsl/model/JavaApiSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/javadsl/model/JavaApiSpec.scala @@ -11,6 +11,7 @@ import akka.japi.Pair import org.scalatest.{ FreeSpec, MustMatchers } import scala.collection.JavaConverters._ +import scala.collection.mutable class JavaApiSpec extends FreeSpec with MustMatchers { "The Java API should work for" - { @@ -49,7 +50,7 @@ class JavaApiSpec extends FreeSpec with MustMatchers { .query().toMap.asScala must contain allOf ("name" → "blub", "age" → "28") } "access parameters" in { - val Seq(param1, param2, param3) = + val mutable.Seq(param1, param2, param3) = Uri.create("/abc?name=blub&age=28&name=blub2") .query().toList.asScala.map(_.toScala) diff --git a/akka-http-core/src/test/scala/io/akka/integrationtest/http/HttpModelIntegrationSpec.scala b/akka-http-core/src/test/scala/io/akka/integrationtest/http/HttpModelIntegrationSpec.scala index 62f8d47ba9a..a99fe4e3b40 100644 --- a/akka-http-core/src/test/scala/io/akka/integrationtest/http/HttpModelIntegrationSpec.scala +++ b/akka-http-core/src/test/scala/io/akka/integrationtest/http/HttpModelIntegrationSpec.scala @@ -11,6 +11,7 @@ import scala.concurrent.duration._ import org.scalatest.{ BeforeAndAfterAll, Matchers, WordSpec } import akka.util.ByteString import akka.actor.ActorSystem +import akka.http.ccompat._ import akka.http.scaladsl.model._ import akka.stream.ActorMaterializer import akka.stream.scaladsl._ @@ -89,7 +90,7 @@ class HttpModelIntegrationSpec extends WordSpec with Matchers with BeforeAndAfte // Finally convert the body into an Array[Byte]. val entityBytes: Array[Byte] = Await.result(request.entity.toStrict(1.second.dilated), 2.seconds.dilated).data.toArray - entityBytes.to[Seq] shouldEqual ByteString("hello").to[Seq] + entityBytes.to(Seq) shouldEqual ByteString("hello").to(Seq) } "be able to build an HttpResponse from String headers and Array[Byte] body" in { diff --git a/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/WSTestRequestBuilding.scala b/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/WSTestRequestBuilding.scala index 5043160bc50..31367c2097c 100644 --- a/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/WSTestRequestBuilding.scala +++ b/akka-http-testkit/src/main/scala/akka/http/javadsl/testkit/WSTestRequestBuilding.scala @@ -28,7 +28,7 @@ trait WSTestRequestBuilding { subprotocols: java.util.List[String]): HttpRequest = { val handler = scaladsl.Flow[sm.ws.Message].map(_.asJava).via(clientSideHandler).map(_.asScala) - st.WSTestRequestBuilding.WS(uri.asScala, handler, subprotocols.asScala)(materializer) + st.WSTestRequestBuilding.WS(uri.asScala, handler, subprotocols.asScala.toSeq)(materializer) } } diff --git a/akka-http-testkit/src/main/scala/akka/http/scaladsl/testkit/MarshallingTestUtils.scala b/akka-http-testkit/src/main/scala/akka/http/scaladsl/testkit/MarshallingTestUtils.scala index 791a47137ca..b1b6193e4ec 100644 --- a/akka-http-testkit/src/main/scala/akka/http/scaladsl/testkit/MarshallingTestUtils.scala +++ b/akka-http-testkit/src/main/scala/akka/http/scaladsl/testkit/MarshallingTestUtils.scala @@ -26,7 +26,7 @@ trait MarshallingTestUtils { Await.result(Marshal(value).to[HttpEntity].flatMap(_.toStrict(marshallingTimeout)), 2 * marshallingTimeout) def marshalToResponseForRequestAccepting[T: ToResponseMarshaller](value: T, mediaRanges: MediaRange*)(implicit ec: ExecutionContext): HttpResponse = - marshalToResponse(value, HttpRequest(headers = Accept(mediaRanges: _*) :: Nil)) + marshalToResponse(value, HttpRequest(headers = Accept(mediaRanges.toList) :: Nil)) def marshalToResponse[T: ToResponseMarshaller](value: T, request: HttpRequest = HttpRequest())(implicit ec: ExecutionContext): HttpResponse = Await.result(Marshal(value).toResponseFor(request), marshallingTimeout) diff --git a/akka-http-tests/src/multi-jvm/scala/akka/remote/testkit/MultiNodeConfig.scala b/akka-http-tests/src/multi-jvm/scala/akka/remote/testkit/MultiNodeConfig.scala index 50cd7eb44a6..1d91a039629 100644 --- a/akka-http-tests/src/multi-jvm/scala/akka/remote/testkit/MultiNodeConfig.scala +++ b/akka-http-tests/src/multi-jvm/scala/akka/remote/testkit/MultiNodeConfig.scala @@ -14,7 +14,8 @@ import scala.util.control.NonFatal import scala.collection.immutable import akka.actor._ import akka.util.Timeout -import akka.remote.testconductor.{ RoleName, TestConductor, TestConductorExt } +import akka.http.ccompat._ +import akka.remote.testconductor.{ TestConductor, TestConductorExt } import akka.testkit._ import akka.testkit.TestEvent._ @@ -359,7 +360,7 @@ abstract class MultiNodeSpec(val myself: RoleName, _system: ActorSystem, _roles: def enterBarrier(name: String*): Unit = testConductor.enter( Timeout.durationToTimeout(remainingOr(testConductor.Settings.BarrierTimeout.duration)), - name.to[immutable.Seq]) + name.to(immutable.Seq)) /** * Query the controller for the transport address of the given node (by role name) and diff --git a/akka-http-tests/src/test/scala/akka/http/javadsl/server/HttpAppSpec.scala b/akka-http-tests/src/test/scala/akka/http/javadsl/server/HttpAppSpec.scala index 2c488bfb3b9..cf29abc8f05 100644 --- a/akka-http-tests/src/test/scala/akka/http/javadsl/server/HttpAppSpec.scala +++ b/akka-http-tests/src/test/scala/akka/http/javadsl/server/HttpAppSpec.scala @@ -13,7 +13,6 @@ import akka.http.javadsl.settings.ServerSettings import akka.http.scaladsl.Http import akka.http.scaladsl.client.RequestBuilding import akka.http.scaladsl.model.{ HttpRequest, StatusCodes } -import akka.stream.ActorMaterializer import akka.testkit.{ AkkaSpec, EventFilter } import com.typesafe.config.ConfigFactory import org.scalatest.concurrent.Eventually diff --git a/akka-http-tests/src/test/scala/akka/http/scaladsl/marshalling/MarshallingSpec.scala b/akka-http-tests/src/test/scala/akka/http/scaladsl/marshalling/MarshallingSpec.scala index 3305bff38b5..322d1b151b6 100644 --- a/akka-http-tests/src/test/scala/akka/http/scaladsl/marshalling/MarshallingSpec.scala +++ b/akka-http-tests/src/test/scala/akka/http/scaladsl/marshalling/MarshallingSpec.scala @@ -202,7 +202,10 @@ class MarshallingSpec extends FreeSpec with Matchers with BeforeAndAfterAll with override def afterAll() = TestKit.shutdownActorSystem(system) protected class FixedRandom extends java.util.Random { - override def nextBytes(array: Array[Byte]): Unit = "my-stable-boundary".getBytes("UTF-8").copyToArray(array) + override def nextBytes(array: Array[Byte]): Unit = { + val bytes = "my-stable-boundary".getBytes("UTF-8") + bytes.copyToArray(array, 0, bytes.length) + } } override protected val multipartBoundaryRandom = new FixedRandom // fix for stable value } diff --git a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/DiscardEntityDefaultExceptionHandlerSpec.scala b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/DiscardEntityDefaultExceptionHandlerSpec.scala index c5fcf341006..2c208553e49 100644 --- a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/DiscardEntityDefaultExceptionHandlerSpec.scala +++ b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/DiscardEntityDefaultExceptionHandlerSpec.scala @@ -4,6 +4,7 @@ package akka.http.scaladsl.server +import akka.http.impl.util.WithLogCapturing import akka.http.scaladsl.model.ContentTypes.`text/plain(UTF-8)` import akka.http.scaladsl.model.HttpEntity import akka.http.scaladsl.model.StatusCodes.InternalServerError @@ -11,10 +12,11 @@ import akka.stream.scaladsl.Source import akka.util.ByteString import org.scalatest.concurrent.Eventually._ import org.scalatest.concurrent.ScalaFutures +import akka.http.ccompat.imm._ import scala.concurrent.Future -class DiscardEntityDefaultExceptionHandlerSpec extends RoutingSpec with ScalaFutures { +class DiscardEntityDefaultExceptionHandlerSpec extends RoutingSpec with ScalaFutures with WithLogCapturing { private val route = concat( path("crash") { @@ -30,7 +32,7 @@ class DiscardEntityDefaultExceptionHandlerSpec extends RoutingSpec with ScalaFut trait Fixture { @volatile var streamConsumed = false - val thousandElements: Stream[ByteString] = Stream.continually(ByteString("foo")).take(999).append { + val thousandElements: Stream[ByteString] = Stream.continually(ByteString("foo")).take(999).lazyAppendedAll { streamConsumed = true Seq(ByteString("end")) } diff --git a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/HttpAppSpec.scala b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/HttpAppSpec.scala index 0e8ba837924..c7d38cdfbb2 100644 --- a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/HttpAppSpec.scala +++ b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/HttpAppSpec.scala @@ -15,7 +15,6 @@ import akka.http.scaladsl.Http import akka.http.scaladsl.client.RequestBuilding import akka.http.scaladsl.model.{ HttpRequest, StatusCodes } import akka.http.scaladsl.settings.ServerSettings -import akka.stream.ActorMaterializer import akka.testkit.{ AkkaSpec, EventFilter } import com.typesafe.config.ConfigFactory import org.scalatest.concurrent.Eventually diff --git a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/FormFieldDirectivesSpec.scala b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/FormFieldDirectivesSpec.scala index 35ba737a465..862390fdde6 100644 --- a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/FormFieldDirectivesSpec.scala +++ b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/FormFieldDirectivesSpec.scala @@ -197,9 +197,16 @@ class FormFieldDirectivesSpec extends RoutingSpec { "The 'formFieldMap' directive" should { "extract fields with different keys" in { + var res: Map[String, String] = null + Post("/", FormData("age" → "42", "numberA" → "3", "numberB" → "5")) ~> { - formFieldMap { echoComplete } - } ~> check { responseAs[String] shouldEqual "Map(age -> 42, numberA -> 3, numberB -> 5)" } + formFieldMap { map ⇒ + res = map + completeOk + } + } ~> check { + res shouldEqual Map("age" -> "42", "numberA" -> "3", "numberB" -> "5") + } } "not show bad performance characteristics when field names' hashCodes collide" in { val numKeys = 10000 @@ -247,9 +254,16 @@ class FormFieldDirectivesSpec extends RoutingSpec { "The 'formFieldMultiMap' directive" should { "extract fields with different keys (with duplicates)" in { + var res: Map[String, List[String]] = null + Post("/", FormData("age" → "42", "number" → "3", "number" → "5")) ~> { - formFieldMultiMap { echoComplete } - } ~> check { responseAs[String] shouldEqual "Map(age -> List(42), number -> List(5, 3))" } + formFieldMultiMap { m ⇒ + res = m + completeOk + } + } ~> check { + res shouldEqual Map("age" -> List("42"), "number" -> List("5", "3")) + } } "not show bad performance characteristics when field names' hashCodes collide" in { val numKeys = 10000 diff --git a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/RespondWithDirectivesSpec.scala b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/RespondWithDirectivesSpec.scala index f912f735a26..62f5a7b6341 100644 --- a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/RespondWithDirectivesSpec.scala +++ b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/RespondWithDirectivesSpec.scala @@ -32,7 +32,7 @@ class RespondWithDirectivesSpec extends RoutingSpec { } "respondWithDefaultHeader" should { def route(extraHeaders: HttpHeader*) = respondWithDefaultHeader(customHeader) { - respondWithHeaders(extraHeaders: _*) { + respondWithHeaders(extraHeaders.toList) { completeOk } } @@ -46,7 +46,7 @@ class RespondWithDirectivesSpec extends RoutingSpec { } "respondWithDefaultHeaders" should { def route(extraHeaders: HttpHeader*) = respondWithDefaultHeaders(customHeader, customHeader2) { - respondWithHeaders(extraHeaders: _*) { + respondWithHeaders(extraHeaders.toList) { completeOk } } diff --git a/akka-http/src/main/java/akka/http/javadsl/common/RegexConverters.java b/akka-http/src/main/java/akka/http/javadsl/common/RegexConverters.java index 54af0c9d53c..d6cd0dd7960 100644 --- a/akka-http/src/main/java/akka/http/javadsl/common/RegexConverters.java +++ b/akka-http/src/main/java/akka/http/javadsl/common/RegexConverters.java @@ -6,7 +6,7 @@ import java.util.regex.Pattern; -import scala.collection.Seq; +import scala.collection.immutable.Seq; import scala.collection.immutable.VectorBuilder; import scala.util.matching.Regex; diff --git a/akka-http/src/main/mima-filters/10.1.7.backwards.excludes b/akka-http/src/main/mima-filters/10.1.7.backwards.excludes index 4b9d1a8a043..d2326ba025f 100644 --- a/akka-http/src/main/mima-filters/10.1.7.backwards.excludes +++ b/akka-http/src/main/mima-filters/10.1.7.backwards.excludes @@ -1,3 +1,5 @@ # Changes against 10.1.7 - ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.http.scaladsl.unmarshalling.sse.EventStreamUnmarshalling.fromEventsStream") + +# Scala 2.13.0-M5 +ProblemFilters.exclude[MissingTypesProblem]("akka.http.impl.settings.RoutingSettingsImpl$") diff --git a/akka-http/src/main/scala/akka/http/impl/settings/RoutingSettingsImpl.scala b/akka-http/src/main/scala/akka/http/impl/settings/RoutingSettingsImpl.scala index 1d943d92027..7b8b567e4f7 100644 --- a/akka-http/src/main/scala/akka/http/impl/settings/RoutingSettingsImpl.scala +++ b/akka-http/src/main/scala/akka/http/impl/settings/RoutingSettingsImpl.scala @@ -25,7 +25,7 @@ private[http] final case class RoutingSettingsImpl( override def productPrefix = "RoutingSettings" } -object RoutingSettingsImpl extends SettingsCompanion[RoutingSettingsImpl]("akka.http.routing") { +object RoutingSettingsImpl extends SettingsCompanionImpl[RoutingSettingsImpl]("akka.http.routing") { def fromSubConfig(root: Config, c: Config) = new RoutingSettingsImpl( c.getBoolean("verbose-error-messages"), c.getBoolean("file-get-conditional"), diff --git a/akka-http/src/main/scala/akka/http/impl/settings/ServerSentEventSettingsImpl.scala b/akka-http/src/main/scala/akka/http/impl/settings/ServerSentEventSettingsImpl.scala index b57bf97a6a1..80b0ac8d0fa 100644 --- a/akka-http/src/main/scala/akka/http/impl/settings/ServerSentEventSettingsImpl.scala +++ b/akka-http/src/main/scala/akka/http/impl/settings/ServerSentEventSettingsImpl.scala @@ -5,7 +5,7 @@ package akka.http.impl.settings import akka.annotation.InternalApi -import akka.http.impl.util.SettingsCompanion +import akka.http.impl.util.SettingsCompanionImpl import com.typesafe.config.Config @InternalApi @@ -20,7 +20,7 @@ private[http] final case class ServerSentEventSettingsImpl( } -object ServerSentEventSettingsImpl extends SettingsCompanion[ServerSentEventSettingsImpl]("akka.http.sse") { +object ServerSentEventSettingsImpl extends SettingsCompanionImpl[ServerSentEventSettingsImpl]("akka.http.sse") { def fromSubConfig(root: Config, c: Config) = ServerSentEventSettingsImpl( c.getInt("max-event-size"), c.getInt("max-line-size") diff --git a/akka-http/src/main/scala/akka/http/javadsl/server/directives/FormFieldDirectives.scala b/akka-http/src/main/scala/akka/http/javadsl/server/directives/FormFieldDirectives.scala index 503a82ddbde..ca8bde772ff 100644 --- a/akka-http/src/main/scala/akka/http/javadsl/server/directives/FormFieldDirectives.scala +++ b/akka-http/src/main/scala/akka/http/javadsl/server/directives/FormFieldDirectives.scala @@ -77,7 +77,7 @@ abstract class FormFieldDirectives extends FileUploadDirectives { * Extracts HTTP form fields from the request as a ``Map>``. */ def formFieldMultiMap(inner: JFunction[JMap[String, JList[String]], Route]): Route = RouteAdapter { - D.formFieldMultiMap { map ⇒ inner.apply(map.mapValues { l ⇒ l.asJava }.asJava).delegate } + D.formFieldMultiMap { map ⇒ inner.apply(map.mapValues { l ⇒ l.asJava }.toMap.asJava).delegate } } /** diff --git a/akka-http/src/main/scala/akka/http/javadsl/server/directives/ParameterDirectives.scala b/akka-http/src/main/scala/akka/http/javadsl/server/directives/ParameterDirectives.scala index 89af52fc917..5c914d8eb77 100644 --- a/akka-http/src/main/scala/akka/http/javadsl/server/directives/ParameterDirectives.scala +++ b/akka-http/src/main/scala/akka/http/javadsl/server/directives/ParameterDirectives.scala @@ -83,7 +83,7 @@ abstract class ParameterDirectives extends MiscDirectives { } def parameterMultiMap(inner: JFunction[JMap[String, JList[String]], Route]): Route = RouteAdapter { - D.parameterMultiMap { map ⇒ inner.apply(map.mapValues { l ⇒ l.asJava }.asJava).delegate } + D.parameterMultiMap { map ⇒ inner.apply(map.mapValues { l ⇒ l.asJava }.toMap.asJava).delegate } } @CorrespondsTo("parameterSeq") diff --git a/akka-http/src/main/scala/akka/http/scaladsl/coding/Encoder.scala b/akka-http/src/main/scala/akka/http/scaladsl/coding/Encoder.scala index a11142e7249..4f25ce75899 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/coding/Encoder.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/coding/Encoder.scala @@ -38,7 +38,7 @@ trait Encoder { def encodeChunk(bytes: ByteString): ByteString = compressor.compressAndFlush(bytes) def finish(): ByteString = compressor.finish() - StreamUtils.byteStringTransformer(encodeChunk, finish) + StreamUtils.byteStringTransformer(encodeChunk, () ⇒ finish) } } diff --git a/akka-http/src/main/scala/akka/http/scaladsl/common/StrictForm.scala b/akka-http/src/main/scala/akka/http/scaladsl/common/StrictForm.scala index 9057066bde8..072098fd301 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/common/StrictForm.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/common/StrictForm.scala @@ -9,6 +9,7 @@ import scala.collection.immutable import scala.concurrent.{ ExecutionContext, Future } import scala.concurrent.duration._ import akka.stream.Materializer +import akka.http.ccompat._ import akka.http.scaladsl.unmarshalling._ import akka.http.scaladsl.model._ import akka.http.scaladsl.util.FastFuture @@ -111,7 +112,7 @@ object StrictForm { def tryUnmarshalToQueryForm: Future[StrictForm] = for (formData ← formDataUM(entity).fast) yield { new StrictForm { - val fields = formData.fields.map { case (name, value) ⇒ name → Field.FromString(value) }(collection.breakOut) + val fields = formData.fields.iterator.map { case (name, value) ⇒ name → Field.FromString(value) }.to(scala.collection.immutable.IndexedSeq) } } @@ -121,9 +122,9 @@ object StrictForm { strictMultiPartFD ← multiPartFD.toStrict(toStrictTimeout).fast } yield { new StrictForm { - val fields = strictMultiPartFD.strictParts.map { + val fields = strictMultiPartFD.strictParts.iterator.map { case x: Multipart.FormData.BodyPart.Strict ⇒ x.name → Field.FromPart(x) - }(collection.breakOut) + }.to(scala.collection.immutable.IndexedSeq) } } diff --git a/akka-http/src/main/scala/akka/http/scaladsl/marshalling/Marshal.scala b/akka-http/src/main/scala/akka/http/scaladsl/marshalling/Marshal.scala index 872c9991e30..9b0cdd3530e 100755 --- a/akka-http/src/main/scala/akka/http/scaladsl/marshalling/Marshal.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/marshalling/Marshal.scala @@ -5,6 +5,7 @@ package akka.http.scaladsl.marshalling import scala.concurrent.{ ExecutionContext, Future } +import akka.http.ccompat._ import akka.http.scaladsl.server.ContentNegotiator import akka.http.scaladsl.model._ import akka.http.scaladsl.util.FastFuture._ @@ -53,10 +54,10 @@ class Marshal[A](val value: A) { m(value).fast.map { marshallings ⇒ val supportedAlternatives: List[ContentNegotiator.Alternative] = - marshallings.collect { + marshallings.iterator.collect { case Marshalling.WithFixedContentType(ct, _) ⇒ ContentNegotiator.Alternative(ct) case Marshalling.WithOpenCharset(mt, _) ⇒ ContentNegotiator.Alternative(mt) - }(collection.breakOut) + }.to(scala.collection.immutable.List) val bestMarshal = { if (supportedAlternatives.nonEmpty) { ctn.pickContentType(supportedAlternatives) diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/Rejection.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/Rejection.scala index d8120586e52..6d165d14440 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/Rejection.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/Rejection.scala @@ -266,9 +266,11 @@ final case class ValidationRejection(message: String, cause: Option[Throwable] = final case class TransformationRejection(transform: immutable.Seq[Rejection] ⇒ immutable.Seq[Rejection]) extends jserver.TransformationRejection with Rejection { override def getTransform = new Function[Iterable[jserver.Rejection], Iterable[jserver.Rejection]] { - override def apply(t: Iterable[jserver.Rejection]): Iterable[jserver.Rejection] = - // explicit collects instead of implicits is because of unidoc failing compilation on .asScala and .asJava here - transform(Util.immutableSeq(t).collect { case r: Rejection ⇒ r }).collect[jserver.Rejection, Seq[jserver.Rejection]] { case j: jserver.Rejection ⇒ j }.asJava // TODO "asJavaDeep" and optimise? + override def apply(t: Iterable[jserver.Rejection]): Iterable[jserver.Rejection] = { + // explicit collects assignment is because of unidoc failing compilation on .asScala and .asJava here + val transformed: Seq[jserver.Rejection] = transform(Util.immutableSeq(t).collect { case r: Rejection ⇒ r }).collect { case j: jserver.Rejection ⇒ j } + transformed.asJava // TODO "asJavaDeep" and optimise? + } } } diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/RejectionHandler.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/RejectionHandler.scala index 019d2937f3f..af541054a4b 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/RejectionHandler.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/RejectionHandler.scala @@ -287,7 +287,7 @@ object RejectionHandler { */ def applyTransformations(rejections: immutable.Seq[Rejection]): immutable.Seq[Rejection] = { val (transformations, rest) = rejections.partition(_.isInstanceOf[TransformationRejection]) - (rest.distinct /: transformations.asInstanceOf[Seq[TransformationRejection]]) { + transformations.asInstanceOf[Seq[TransformationRejection]].foldLeft(rest.distinct) { case (remaining, transformation) ⇒ transformation.transform(remaining) } } diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/RequestContextImpl.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/RequestContextImpl.scala index 03524cd9e9b..584d502a24a 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/RequestContextImpl.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/RequestContextImpl.scala @@ -15,6 +15,7 @@ import akka.http.scaladsl.model._ import akka.http.scaladsl.model.StatusCodes._ import akka.http.scaladsl.util.FastFuture import akka.http.scaladsl.util.FastFuture._ +import akka.http.ccompat._ /** * INTERNAL API diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala index 7f854f4e3ae..9de0033ab4d 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/CodingDirectives.scala @@ -144,7 +144,7 @@ object CodingDirectives extends CodingDirectives { private def _encodeResponse(encoders: immutable.Seq[Encoder]): Directive0 = BasicDirectives.extractRequest.flatMap { request ⇒ val negotiator = EncodingNegotiator(request.headers) - val encodings: List[HttpEncoding] = encoders.map(_.encoding)(collection.breakOut) + val encodings: List[HttpEncoding] = encoders.map(_.encoding).toList val bestEncoder = negotiator.pickEncoding(encodings).flatMap(be ⇒ encoders.find(_.encoding == be)) bestEncoder match { case Some(encoder) ⇒ mapResponse(encoder.encodeMessage(_)) diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RespondWithDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RespondWithDirectives.scala index 81edce240e0..2cec9397c3e 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RespondWithDirectives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/RespondWithDirectives.scala @@ -6,6 +6,7 @@ package akka.http.scaladsl.server package directives import akka.http.scaladsl.model._ +import akka.http.ccompat._ import scala.collection.immutable /** @@ -20,7 +21,8 @@ trait RespondWithDirectives { * * @group response */ - def respondWithHeader(responseHeader: HttpHeader): Directive0 = respondWithHeaders(responseHeader) + def respondWithHeader(responseHeader: HttpHeader): Directive0 = + respondWithHeaders(immutable.Seq(responseHeader)) /** * Adds the given response header to all HTTP responses of its inner Route, @@ -35,6 +37,7 @@ trait RespondWithDirectives { * * @group response */ + @pre213 def respondWithHeaders(responseHeaders: HttpHeader*): Directive0 = respondWithHeaders(responseHeaders.toList) @@ -44,7 +47,11 @@ trait RespondWithDirectives { * @group response */ def respondWithHeaders(responseHeaders: immutable.Seq[HttpHeader]): Directive0 = - mapResponseHeaders(responseHeaders ++ _) + mapResponseHeaders(responseHeaders.toList ++ _) + + @since213 + def respondWithHeaders(firstHeader: HttpHeader, otherHeaders: HttpHeader*): Directive0 = + respondWithHeaders(firstHeader +: otherHeaders.toList) /** * Adds the given response headers to all HTTP responses of its inner Route, @@ -52,6 +59,7 @@ trait RespondWithDirectives { * * @group response */ + @pre213 def respondWithDefaultHeaders(responseHeaders: HttpHeader*): Directive0 = respondWithDefaultHeaders(responseHeaders.toList) @@ -63,6 +71,17 @@ trait RespondWithDirectives { */ def respondWithDefaultHeaders(responseHeaders: immutable.Seq[HttpHeader]): Directive0 = mapResponse(_.withDefaultHeaders(responseHeaders)) + + /** + * Adds the given response headers to all HTTP responses of its inner Route, + * if a header already exists it is not added again. + * + * @group response + */ + @since213 + def respondWithDefaultHeaders(firstHeader: HttpHeader, otherHeaders: HttpHeader*): Directive0 = + respondWithDefaultHeaders(firstHeader +: otherHeaders.toList) + } object RespondWithDirectives extends RespondWithDirectives diff --git a/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/sse/EventStreamUnmarshalling.scala b/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/sse/EventStreamUnmarshalling.scala index 2518065f59e..a78c33563d3 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/sse/EventStreamUnmarshalling.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/unmarshalling/sse/EventStreamUnmarshalling.scala @@ -11,7 +11,6 @@ import akka.NotUsed import akka.actor.ActorSystem import akka.annotation.ApiMayChange import akka.http.impl.settings.ServerSentEventSettingsImpl -import akka.http.impl.util.SettingsCompanion import akka.http.scaladsl.model.HttpEntity import akka.http.scaladsl.model.MediaTypes.`text/event-stream` import akka.http.scaladsl.model.sse.ServerSentEvent diff --git a/akka-http2-support/src/main/scala/akka/http/impl/engine/http2/PriorityTree.scala b/akka-http2-support/src/main/scala/akka/http/impl/engine/http2/PriorityTree.scala index 17e12b2448d..7872efe8f94 100644 --- a/akka-http2-support/src/main/scala/akka/http/impl/engine/http2/PriorityTree.scala +++ b/akka-http2-support/src/main/scala/akka/http/impl/engine/http2/PriorityTree.scala @@ -6,6 +6,7 @@ package akka.http.impl.engine.http2 import akka.annotation.InternalApi import akka.http.impl.engine.http2.util.AsciiTreeLayout +import akka.http.ccompat.imm._ import scala.collection.immutable import scala.collection.immutable.{ TreeMap, TreeSet } @@ -103,7 +104,7 @@ private[http2] object PriorityTree { create( (nodes - streamId) + (info.streamDependency → dependencyInfo.copy(childrenIds = dependencyInfo.childrenIds - streamId)) ++ - info.childrenIds.map(id ⇒ + info.childrenIds.unsorted.map(id ⇒ id → nodes(id).copy(streamDependency = info.streamDependency) ) ) diff --git a/akka-http2-support/src/main/scala/akka/http/scaladsl/Http2.scala b/akka-http2-support/src/main/scala/akka/http/scaladsl/Http2.scala index 172e5f0700e..620e5ade282 100644 --- a/akka-http2-support/src/main/scala/akka/http/scaladsl/Http2.scala +++ b/akka-http2-support/src/main/scala/akka/http/scaladsl/Http2.scala @@ -145,9 +145,9 @@ final class Http2Ext(private val config: Config)(implicit val system: ActorSyste Http2AlpnSupport.applySessionParameters(engine, httpsContext.firstSession) Http2AlpnSupport.enableForServer(engine, setChosenProtocol) } - val tls = TLS(createEngine, _ ⇒ Success(()), IgnoreComplete) + val tls = TLS(() ⇒ createEngine, _ ⇒ Success(()), IgnoreComplete) - AlpnSwitch(getChosenProtocol, http.serverLayer(settings, None, log), http2Layer()) atop + AlpnSwitch(() ⇒ getChosenProtocol, http.serverLayer(settings, None, log), http2Layer()) atop tls } diff --git a/akka-http2-support/src/test/scala/akka/http/impl/engine/http2/Http2ServerSpec.scala b/akka-http2-support/src/test/scala/akka/http/impl/engine/http2/Http2ServerSpec.scala index 753c04efb4b..0dade9b02e6 100644 --- a/akka-http2-support/src/test/scala/akka/http/impl/engine/http2/Http2ServerSpec.scala +++ b/akka-http2-support/src/test/scala/akka/http/impl/engine/http2/Http2ServerSpec.scala @@ -1069,12 +1069,12 @@ class Http2ServerSpec extends AkkaSpec(""" } // keep counters that are updated on outgoing sendDATA and incoming WINDOW_UPDATE frames - private var toServerWindows = Map.empty[Int, Int].withDefaultValue(Http2Protocol.InitialWindowSize) + private var toServerWindows: Map[Int, Int] = Map.empty.withDefaultValue(Http2Protocol.InitialWindowSize) private var toServerWindowForConnection = Http2Protocol.InitialWindowSize def remainingToServerWindowForConnection: Int = toServerWindowForConnection def remainingToServerWindowFor(streamId: Int): Int = toServerWindows(streamId) min remainingToServerWindowForConnection - private var fromServerWindows = Map.empty[Int, Int].withDefaultValue(Http2Protocol.InitialWindowSize) + private var fromServerWindows: Map[Int, Int] = Map.empty.withDefaultValue(Http2Protocol.InitialWindowSize) private var fromServerWindowForConnection = Http2Protocol.InitialWindowSize // keep counters that are updated for incoming DATA frames and outgoing WINDOW_UPDATE frames def remainingFromServerWindowForConnection: Int = fromServerWindowForConnection diff --git a/akka-parsing/src/main/scala/akka/http/ccompat/pre213macro.scala b/akka-parsing/src/main/scala/akka/http/ccompat/pre213macro.scala new file mode 100644 index 00000000000..1a4d7d71f16 --- /dev/null +++ b/akka-parsing/src/main/scala/akka/http/ccompat/pre213macro.scala @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2019 Lightbend Inc. + */ + +package akka.http.ccompat + +import scala.annotation.StaticAnnotation +import scala.language.experimental.macros +import scala.reflect.macros.blackbox.Context + +object pre213macro { + def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = annottees match { + case Seq(method) ⇒ + import c.universe._ + if (scala.util.Properties.versionNumberString.startsWith("2.13")) + c.Expr[Nothing](EmptyTree) + else + method + case _ ⇒ + throw new IllegalArgumentException("Please annotate single expressions") + } +} +class pre213 extends StaticAnnotation { + def macroTransform(annottees: Any*): Any = macro pre213macro.impl +} diff --git a/akka-parsing/src/main/scala/akka/http/ccompat/since213macro.scala b/akka-parsing/src/main/scala/akka/http/ccompat/since213macro.scala new file mode 100644 index 00000000000..9c68a1d483f --- /dev/null +++ b/akka-parsing/src/main/scala/akka/http/ccompat/since213macro.scala @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2019 Lightbend Inc. + */ + +package akka.http.ccompat + +import scala.annotation.StaticAnnotation +import scala.language.experimental.macros +import scala.reflect.macros.blackbox.Context + +object since213macro { + def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = annottees match { + case Seq(method) ⇒ + import c.universe._ + if (scala.util.Properties.versionNumberString.startsWith("2.13")) + method + else + c.Expr[Nothing](EmptyTree) + case _ ⇒ + throw new IllegalArgumentException("Please annotate single expressions") + } +} +class since213 extends StaticAnnotation { + def macroTransform(annottees: Any*): Any = macro since213macro.impl +} diff --git a/akka-parsing/src/main/scala/akka/parboiled2/CharPredicate.scala b/akka-parsing/src/main/scala/akka/parboiled2/CharPredicate.scala index 0c90d84fc72..458ab7e6d54 100644 --- a/akka-parsing/src/main/scala/akka/parboiled2/CharPredicate.scala +++ b/akka-parsing/src/main/scala/akka/parboiled2/CharPredicate.scala @@ -118,7 +118,7 @@ object CharPredicate { case x ⇒ General(x) } - def apply(magnets: ApplyMagnet*): CharPredicate = (Empty /: magnets) { (a, m) ⇒ a ++ m.predicate } + def apply(magnets: ApplyMagnet*): CharPredicate = magnets.foldLeft(Empty) { (a, m) ⇒ a ++ m.predicate } class ApplyMagnet(val predicate: CharPredicate) object ApplyMagnet { diff --git a/akka-parsing/src/main/scala/akka/parboiled2/ErrorFormatter.scala b/akka-parsing/src/main/scala/akka/parboiled2/ErrorFormatter.scala index e85471f9d90..4dc11f959bf 100644 --- a/akka-parsing/src/main/scala/akka/parboiled2/ErrorFormatter.scala +++ b/akka-parsing/src/main/scala/akka/parboiled2/ErrorFormatter.scala @@ -16,8 +16,8 @@ package akka.parboiled2 -import scala.annotation.tailrec import java.lang.{ StringBuilder ⇒ JStringBuilder } +import scala.annotation.tailrec /** * Abstraction for error formatting logic. @@ -133,7 +133,7 @@ class ErrorFormatter( * Formats what is expected at the error location as a [[List]] of Strings. */ def formatExpectedAsList(error: ParseError): List[String] = { - val distinctStrings: Set[String] = error.effectiveTraces.map(formatAsExpected)(collection.breakOut) + val distinctStrings: Set[String] = error.effectiveTraces.iterator.map(formatAsExpected).toSet distinctStrings.toList } diff --git a/akka-parsing/src/main/scala/akka/parboiled2/support/OpTreeContext.scala b/akka-parsing/src/main/scala/akka/parboiled2/support/OpTreeContext.scala index 8c62f230e28..1ba185f92de 100644 --- a/akka-parsing/src/main/scala/akka/parboiled2/support/OpTreeContext.scala +++ b/akka-parsing/src/main/scala/akka/parboiled2/support/OpTreeContext.scala @@ -595,7 +595,10 @@ trait OpTreeContext[OpTreeCtx <: ParserMacros.ParserContext] { case Left(_) ⇒ super.render(wrapped) case Right(x) ⇒ q"$x ne null" } - def renderInner(wrapped: Boolean) = call.asInstanceOf[Left[OpTree, Tree]].a.render(wrapped) + def renderInner(wrapped: Boolean) = { + val Left(value) = call.asInstanceOf[Left[OpTree, Tree]] + value.render(wrapped) + } } def CharRange(lowerTree: Tree, upperTree: Tree): CharacterRange = { @@ -638,7 +641,7 @@ trait OpTreeContext[OpTreeCtx <: ParserMacros.ParserContext] { case Block(statements, res) ⇒ block(statements, actionBody(res)) case x @ (Ident(_) | Select(_, _)) ⇒ - val valNames: List[TermName] = argTypes.indices.map { i ⇒ TermName("value" + i) }(collection.breakOut) + val valNames: List[TermName] = argTypes.indices.iterator.map { i ⇒ TermName("value" + i) }.toList val args = valNames map Ident.apply block(popToVals(valNames), q"__push($x(..$args))") diff --git a/build.sbt b/build.sbt index f21946930e6..5567092301a 100644 --- a/build.sbt +++ b/build.sbt @@ -45,7 +45,7 @@ inThisBuild(Def.settings( Dependencies.Versions, Formatting.formatSettings, shellPrompt := { s => Project.extract(s).currentProject.id + " > " }, - concurrentRestrictions in Global += Tags.limit(Tags.Test, 1) + concurrentRestrictions in Global += Tags.limit(Tags.Test, 1), )) lazy val root = Project( @@ -86,7 +86,36 @@ lazy val root = Project( docs ) +val commonSettings = Seq( + // Adds a `src/main/scala-2.13+` source directory for Scala 2.13 and newer + // and a `src/main/scala-2.13-` source directory for Scala version older than 2.13 + unmanagedSourceDirectories in Compile += { + val sourceDir = (sourceDirectory in Compile).value + CrossVersion.partialVersion(scalaVersion.value) match { + case Some((2, n)) if n >= 13 => sourceDir / "scala-2.13+" + case _ => sourceDir / "scala-2.13-" + } + }, +) + +val scalaMacroSupport = Seq( + scalacOptions ++= { + CrossVersion.partialVersion(scalaVersion.value) match { + case Some((2, n)) if n >= 13 => + Seq("-Ymacro-annotations") + case _ => + Seq.empty + } + }, + libraryDependencies ++= (CrossVersion.partialVersion(scalaVersion.value) match { + case Some((2, n)) if n < 13 => Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)) + case _ => Seq.empty + }), +) + + lazy val parsing = project("akka-parsing") + .settings(commonSettings) .settings(AutomaticModuleName.settings("akka.http.parsing")) .addAkkaModuleDependency("akka-actor", "provided") .settings(Dependencies.parsing) @@ -95,19 +124,23 @@ lazy val parsing = project("akka-parsing") scalacOptions += "-language:_", unmanagedSourceDirectories in ScalariformKeys.format in Test := (unmanagedSourceDirectories in Test).value ) + .settings(scalaMacroSupport) .enablePlugins(ScaladocNoVerificationOfDiagrams) .disablePlugins(MimaPlugin) lazy val httpCore = project("akka-http-core") + .settings(commonSettings) .settings(AutomaticModuleName.settings("akka.http.core")) .dependsOn(parsing) .addAkkaModuleDependency("akka-stream", "provided") .addAkkaModuleDependency("akka-stream-testkit", "test") .settings(Dependencies.httpCore) .settings(VersionGenerator.versionSettings) + .settings(scalaMacroSupport) .enablePlugins(BootstrapGenjavadoc) lazy val http = project("akka-http") + .settings(commonSettings) .settings(AutomaticModuleName.settings("akka.http")) .dependsOn(httpCore) .addAkkaModuleDependency("akka-stream", "provided") @@ -115,9 +148,11 @@ lazy val http = project("akka-http") .settings( scalacOptions in Compile += "-language:_" ) + .settings(scalaMacroSupport) .enablePlugins(BootstrapGenjavadoc, BoilerplatePlugin) lazy val http2Support = project("akka-http2-support") + .settings(commonSettings) .settings(AutomaticModuleName.settings("akka.http.http2")) .dependsOn(httpCore, httpTestkit % "test", httpCore % "test->test") .addAkkaModuleDependency("akka-stream", "provided") @@ -159,6 +194,7 @@ lazy val http2Support = project("akka-http2-support") .disablePlugins(MimaPlugin) // experimental module still lazy val httpTestkit = project("akka-http-testkit") + .settings(commonSettings) .settings(AutomaticModuleName.settings("akka.http.testkit")) .dependsOn(http) .addAkkaModuleDependency("akka-stream-testkit", "provided") @@ -173,6 +209,7 @@ lazy val httpTestkit = project("akka-http-testkit") .disablePlugins(MimaPlugin) // testkit, no bin compat guaranteed lazy val httpTests = project("akka-http-tests") + .settings(commonSettings) .settings(Dependencies.httpTests) .dependsOn(httpSprayJson, httpXml, httpJackson, httpTestkit % "test", httpCore % "test->test") @@ -187,6 +224,7 @@ lazy val httpTests = project("akka-http-tests") .addAkkaModuleDependency("akka-multi-node-testkit", "test") lazy val httpJmhBench = project("akka-http-bench-jmh") + .settings(commonSettings) .dependsOn(http) .addAkkaModuleDependency("akka-stream") .enablePlugins(JmhPlugin) @@ -194,6 +232,7 @@ lazy val httpJmhBench = project("akka-http-bench-jmh") .disablePlugins(MimaPlugin) lazy val httpMarshallersScala = project("akka-http-marshallers-scala") + .settings(commonSettings) .enablePlugins(NoPublish/*, AggregatePRValidation*/) .disablePlugins(BintrayPlugin, MimaPlugin) .aggregate(httpSprayJson, httpXml) @@ -211,6 +250,7 @@ lazy val httpSprayJson = .settings(Dependencies.httpSprayJson) lazy val httpMarshallersJava = project("akka-http-marshallers-java") + .settings(commonSettings) .enablePlugins(NoPublish/*, AggregatePRValidation*/) .disablePlugins(BintrayPlugin, MimaPlugin) .aggregate(httpJackson) @@ -223,6 +263,7 @@ lazy val httpJackson = .enablePlugins(ScaladocNoVerificationOfDiagrams) lazy val httpCaching = project("akka-http-caching") + .settings(commonSettings) .settings(AutomaticModuleName.settings("akka.http.caching")) .addAkkaModuleDependency("akka-stream", "provided") .addAkkaModuleDependency("akka-stream-testkit", "provided") @@ -239,6 +280,7 @@ def httpMarshallersScalaSubproject(name: String) = base = file(s"akka-http-marshallers-scala/akka-http-$name") ) .dependsOn(http) + .settings(commonSettings) .enablePlugins(BootstrapGenjavadoc) def httpMarshallersJavaSubproject(name: String) = @@ -247,6 +289,7 @@ def httpMarshallersJavaSubproject(name: String) = base = file(s"akka-http-marshallers-java/akka-http-$name"), ) .dependsOn(http) + .settings(commonSettings) .enablePlugins(BootstrapGenjavadoc) lazy val docs = project("docs") diff --git a/docs/src/test/scala/docs/http/scaladsl/server/directives/CachingDirectivesExamplesSpec.scala b/docs/src/test/scala/docs/http/scaladsl/server/directives/CachingDirectivesExamplesSpec.scala index 77c103fe630..fac3d340432 100644 --- a/docs/src/test/scala/docs/http/scaladsl/server/directives/CachingDirectivesExamplesSpec.scala +++ b/docs/src/test/scala/docs/http/scaladsl/server/directives/CachingDirectivesExamplesSpec.scala @@ -29,9 +29,10 @@ class CachingDirectivesExamplesSpec extends RoutingSpec { val isGet: RequestContext ⇒ Boolean = _.request.method == GET val isAuthorized: RequestContext ⇒ Boolean = _.request.headers.exists(_.is(Authorization.lowercaseName)) - PartialFunction { + val result: PartialFunction[RequestContext, Uri] = { case r: RequestContext if isGet(r) && !isAuthorized(r) ⇒ r.request.uri } + result } // Created outside the route to allow using @@ -74,9 +75,10 @@ class CachingDirectivesExamplesSpec extends RoutingSpec { val isGet: RequestContext ⇒ Boolean = _.request.method == GET val isAuthorized: RequestContext ⇒ Boolean = _.request.headers.exists(_.is(Authorization.lowercaseName)) - PartialFunction { + val result: PartialFunction[RequestContext, Uri] = { case r: RequestContext if isGet(r) && !isAuthorized(r) ⇒ r.request.uri } + result } // Created outside the route to allow using diff --git a/project/Dependencies.scala b/project/Dependencies.scala index b4247dc0014..b61bd09578d 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -24,18 +24,21 @@ object Dependencies { lazy val scalaCheckVersion = settingKey[String]("The version of ScalaCheck to use.") val Versions = Seq( - crossScalaVersions := Seq("2.12.8", "2.11.12"/*, "2.13.0-M3"*/), + crossScalaVersions := Seq("2.12.8", "2.11.12", "2.13.0-M5"), scalaVersion := crossScalaVersions.value.head, scalaCheckVersion := System.getProperty("akka.build.scalaCheckVersion", "1.14.0"), - scalaTestVersion := "3.0.5", + scalaTestVersion := "3.0.6-SNAP5", specs2Version := "4.3.6" ) - import Versions._ + object Provided { + val jsr305 = "com.google.code.findbugs" % "jsr305" % "3.0.2" % "provided" // ApacheV2 + + val scalaReflect = ScalaVersionDependentModuleID.versioned("org.scala-lang" % "scala-reflect" % _ % "provided") // Scala License + } object Compile { val scalaXml = "org.scala-lang.modules" %% "scala-xml" % "1.1.1" // Scala License - val scalaReflect = ScalaVersionDependentModuleID.versioned("org.scala-lang" % "scala-reflect" % _) // Scala License // For akka-http spray-json support val sprayJson = "io.spray" %% "spray-json" % "1.3.5" // ApacheV2 @@ -51,7 +54,6 @@ object Dependencies { val alpnApi = "org.eclipse.jetty.alpn" % "alpn-api" % "1.1.3.v20160715" // ApacheV2 val caffeine = "com.github.ben-manes.caffeine" % "caffeine" % "2.6.2" - val jsr305 = "com.google.code.findbugs" % "jsr305" % "3.0.2" % Provided // ApacheV2 object Docs { val sprayJson = Compile.sprayJson % "test" @@ -80,18 +82,22 @@ object Dependencies { lazy val parsing = Seq( DependencyHelpers.versionDependentDeps( - Dependencies.Compile.scalaReflect % "provided" + Dependencies.Provided.scalaReflect ), - addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full) ) lazy val httpCore = l ++= Seq( Test.sprayJson, // for WS Autobahn test metadata - Test.scalatest.value, Test.scalacheck.value, Test.junit) + Test.scalatest.value, Test.scalacheck.value, Test.junit + ) - lazy val httpCaching = l ++= Seq(caffeine, jsr305, Test.scalatest.value) + lazy val httpCaching = l ++= Seq( + caffeine, + Provided.jsr305, + Test.scalatest.value + ) - lazy val http = l ++= Seq() + lazy val http = Seq() lazy val http2 = l ++= Seq(hpack, alpnApi) diff --git a/project/Doc.scala b/project/Doc.scala index b3da918c16b..c106868b355 100644 --- a/project/Doc.scala +++ b/project/Doc.scala @@ -69,7 +69,10 @@ object Scaladoc extends AutoPlugin { if (name.endsWith(".html") && !name.startsWith("index-") && !name.equals("index.html") && !name.equals("package.html")) { val source = scala.io.Source.fromFile(f)(scala.io.Codec.UTF8) - val hd = try source.getLines().exists(_.contains("
")) + val hd = try source.getLines().exists(lines => + lines.contains("
") || + lines.contains(" throw new IllegalStateException("Scaladoc verification failed for file '"+f+"'", e) } finally source.close() diff --git a/project/MiMa.scala b/project/MiMa.scala index 6e048dfb75d..f0f1df3bd24 100644 --- a/project/MiMa.scala +++ b/project/MiMa.scala @@ -27,10 +27,11 @@ object MiMa extends AutoPlugin { val currentFork = "10.1." override val projectSettings = Seq( - mimaPreviousArtifacts := + mimaPreviousArtifacts := { // manually maintained list of previous versions to make sure all incompatibilities are found // even if so far no files have been been created in this project's mima-filters directory - Set("10.0.0", + val pre213Versions = Set( + "10.0.0", "10.0.1", "10.0.2", "10.0.3", @@ -55,27 +56,37 @@ object MiMa extends AutoPlugin { "10.1.6", "10.1.7", ) - .collect { case version if !ignoredModules.get(name.value).exists(_.contains(version)) => - organization.value %% name.value % version - }, - mimaBackwardIssueFilters := { - val filters = mimaBackwardIssueFilters.value - val allVersions = (mimaPreviousArtifacts.value.map(_.revision) ++ filters.keys).toSeq + val post213Versions = Set( + // We don't promise binary compatibility + // for 2.13 milestones yet + ) + + val versions = + if (scalaBinaryVersion.value == "2.13.0-M5") post213Versions + else pre213Versions ++ post213Versions - /** - * Collect filters for all versions of a fork and add them as filters for the latest version of the fork. - * Otherwise, new versions in the fork that are listed above will reintroduce issues that were already filtered - * out before. We basically rebase this release line on top of the fork from the view of Mima. - */ - def forkFilter(fork: String): Option[(String, Seq[ProblemFilter])] = { - val forkVersions = filters.keys.filter(_.startsWith(fork)).toSeq - val collectedFilterOption = forkVersions.map(filters).reduceOption(_ ++ _) - collectedFilterOption.map(latestForkVersion(fork, allVersions) -> _) - } + versions.collect { case version if !ignoredModules.get(name.value).exists(_.contains(version)) => + organization.value %% name.value % version + } + }, + mimaBackwardIssueFilters := { + val filters = mimaBackwardIssueFilters.value + val allVersions = (mimaPreviousArtifacts.value.map(_.revision) ++ filters.keys).toSeq - forks.flatMap(forkFilter).toMap ++ - filters.filterKeys(_ startsWith currentFork) + /** + * Collect filters for all versions of a fork and add them as filters for the latest version of the fork. + * Otherwise, new versions in the fork that are listed above will reintroduce issues that were already filtered + * out before. We basically rebase this release line on top of the fork from the view of Mima. + */ + def forkFilter(fork: String): Option[(String, Seq[ProblemFilter])] = { + val forkVersions = filters.keys.filter(_.startsWith(fork)).toSeq + val collectedFilterOption = forkVersions.map(filters).reduceOption(_ ++ _) + collectedFilterOption.map(latestForkVersion(fork, allVersions) -> _) } + + forks.flatMap(forkFilter).toMap ++ + filters.filterKeys(_ startsWith currentFork) + } ) def latestForkVersion(fork: String, allVersions: Seq[String]): String =