In Scala, it looks something like this:
// collections are immutable by default, but we want the mutable flavour import collection.mutable // An alias so we don't keep repeating ourself type DiagMultiMap[T] = mutable.Map[String, mutable.Set[Diagnostic[T]]] //pimp DiagMultiMap with the addDiagnostic method class MapDiag[T](theMap: DiagMultiMap[T]) { def addDiagnostic(d: Diagnostic[T]): Unit = { val set = theMap.getOrElseUpdate(d.getCode) {mutable.Set.empty} set += d } } //an implicit conversion to enable the pimp implicit def mapDiagPimp[T](theMap: DiagMultiMap[T]) = new MapDiag(theMap) //This is how we make one def mkDiagnosticMultiMap[T](entries: Seq[Diagnostic[T]]): DiagMultiMap[T] = { val theMap = new mutable.HashMap[String, mutable.Set[Diagnostic[T]]]() entries foreach { theMap addDiagnostic _ } theMap }
It has not been tested since I do not have access to the code for Diagnostic
UPDATE
It will teach me to publish late at night, it is actually a lot easier ...
For any sequence of Diagnostic objects:
val diags = List(new Diagnostic(...), new Diagnositic(...), ...)
they can be easily grouped using one method:
val diagMap = diags.groupBy(_.getCode)
But it's a little harder than that!
The big problem is that Diagnostic is part of the standard Java library, so you cannot rewrite it using annotations with deviations (more on this after the code). However, the wrapper would do the trick, and fortunately it is not too big:
class RichDiagnostic[S+](underlying: Diagnostic[S]) { def code: String = underlying.getCode def columnNumber: Long = underlying.getColumnNumber def endPosition: Long = underlying.getEndPosition def kind: Diagnostic.Kind = underlying.getKind def lineNumber: Long = underlying.getLineNumber def messageFor(locale: Locale): String = underlying.getMessage(locale) def position: Long = underlying.getPosition def source: S = underlying.getSource def startPosition: Long = underlying.getStartPosition implicit def toUnderlying: Diagnostic[S] = underlying }
+ in [S+] denotes this class as covariant, therefore RichDiagnostic[A] is considered a subclass of RichDiagnostic[B] if A is a subclass of B This is the key to preventing unpleasant common signatures, no more than <? extends T> <? extends T> or <? super T> <? super T> !
Too easy to use:
val richDiags = diags.map(d => new RichDiagnostic(d)) val diagMap = richDiags.groupBy(_.code)
If Diagnostics is initially delivered as a Java list, then methods like map will not automatically be available to you, but the conversion is trivial:
import collection.JavaConverters._
Creating this collection is a one-time operation and should be repeated if entries are added to the base list, but I suspect that this is not a problem.