Reputation: 941
I cannot iterate over a lightly wrapped collection in a Play! Framework template. I made the assumption that simply implementing the Iterable
interface would enable me to use for-each loops in the templates, but that seems to be incorrect.
How can I get this working?
I created a simple wrapper class around java.util.Queue. I made the assumption that implementing Iterable would allow me to use a for-each loop in a Play! Framework template.
public class DecisionQueue implements Iterable<Decision> {
Queue<Decision> decisions;
public DecisionQueue() {
decisions = new LinkedList<Decision>();
}
// redacted methods for manipulating the queue
@Override
public Iterator<Decision> iterator() {
return decisions.iterator();
}
}
I provided an instance of the wrapper to a template.
public static Result getFormOutput() {
DecisionQueue decisionQueue = getDecisionQueue();
return ok(views.html.questionnaire.output.render(decisionQueue));
}
I attempted to iterate over the wrapper in my template.
@(decisionQueue: data.DecisionQueue)
<ul>
@for(decision <- decisionQueue) // Problem here
// redacted
}
</ul>
I got the following stack trace during compilation.
[error] C:\...\app\views\questionnaire\output.scala.html:12: type mismatch;
[error] found : decisionQueue.type (with underlying type models.data.DecisionQueue)
[error] required: ?{def map(x$1: ? >: <error> => play.twirl.api.HtmlFormat.Appendable): ?}
[error] (which expands to) ?{def map(x$1: ? >: <error> => play.twirl.api.Html): ?}
[error] Note that implicit conversions are not applicable because they are ambiguous:
[error] both method javaCollectionToScala in object TemplateMagic of type [T](x: Iterable[T])Iterable[T]
[error] and method iterableAsScalaIterable in trait WrapAsScala of type [A](i: Iterable[A])Iterable[A]
[error] are possible conversion functions from decisionQueue.type to ?{def map(x$1: ? >: <error> => play.twirl.api.HtmlFormat.Appendable): ?}
[error] @for(decision <- decisionQueue) {
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
It works if I pass the underlying Queue directly to the template instead of using the wrapper.
Upvotes: 1
Views: 1061
Reputation: 838
Just had the exact same problem with Play 2.5.14 and fixed it by making the conversion explicit by adding .asScala
. Thought I'd share my solution even though the question's old, since it shows up when googling play iterable implicit conversion ambiguous
at first position.
Before
@(subscriptions: java.lang.Iterable[Subscription])
@if(subscriptions.nonEmpty) {
...
}
Gave me this error:
[error] /some/path/accountDetails.scala.html:31: type mismatch;
[error] found : subscriptions.type (with underlying type Iterable[some.package.Subscription])
[error] required: ?{def nonEmpty: ?}
[error] Note that implicit conversions are not applicable because they are ambiguous:
[error] both method javaCollectionToScala in object TemplateMagic of type [T](x: Iterable[T])Iterable[T]
[error] and method iterableAsScalaIterable in trait WrapAsScala of type [A](i: Iterable[A])Iterable[A]
[error] are possible conversion functions from subscriptions.type to ?{def nonEmpty: ?}
[error] @if(subscriptions.nonEmpty) {
[error] ^
After
@(subscriptions: java.lang.Iterable[Subscription])
@if(subscriptions.asScala.nonEmpty) {
...
}
Works out of the box for me, no additional imports required.
Hope it helps.
Upvotes: 0
Reputation: 2785
You are mixing languages here. Your DecisionQueue class is written in Java while Twirl templates compile to Scala. The languages are compatible but not transparently. You are trying to iterate in Scala over a Java collection (LinkedList). Scala doesn't know how to do that without some help and the error is telling you that it found some ambiguity with implicit functions that it tried to use to convert the Java collection. You might want to help it along a little by importing the converters and using them, like this:
@(decisionQueue: data.DecisionQueue)
import scala.collection.JavaConversions._
<ul>
@for(decision <- decisionQueue.iterator) // Problem here
// redacted
}
</ul>
Upvotes: 1