1

I have a Play 2.3 project with custom headers coming from AJAX that need to be passed to every service call (to be passed further to the web services). I thought about making it an implicit parameter, like in this dumbed down example :

case class CriteriaHeaders(license: String) case class Criteria(criteriaHeaders: CriteriaHeaders, id: Int) class ProjectController(service: Service) { implicit def criteriaToCiteriaHeaders(criteria: Criteria): CriteriaHeaders = criteria.criteriaHeaders def findName(criteria: Criteria) = { // implicit val criteriaHeaders: CriteriaHeaders = criteria.criteriaHeaders service .findName(criteria.id) .fold( error => error, name => name ) } } class Service { def findName(id: Int) (implicit criteriaHeaders: CriteriaHeaders): Either[String, String] = ??? // TODO } 

(Of course in the real project there is an ActionBuilder, a Json parser etc.)

Usage :

val controller = new ProjectController(new Service()) val name = controller.findName(Criteria(CriteriaHeaders("abc"), 123)) 

It doesn't compile, giving an error :

Error:(21, 17) could not find implicit value for parameter licenseHeaders: A$A172.this.CriteriaHeaders.findName(criteria.id) 

However, if I uncomment the implicit val, it works. Why it doesn't work with the implicit method?

EDIT : In case anyone find this useful, I took second suggestion from @till-rohrmann and I put the implicit in the companion object of the CriteriaHeaders, so it is available in every controller using it.

object CriteriaHeaders { implicit def criteriaToCiteriaHeaders(implicit criteria: Criteria) = criteria.criteriaHeaders } 
2
  • does this work for you: implicit def criteriaToCiteriaHeaders: CriteriaHeaders = criteria.criteriaHeaders instead of the val? Commented Aug 27, 2015 at 8:08
  • Nope... I tried like this as well : implicit def criteriaToCiteriaHeaders: Criteria => CriteriaHeaders = implicit criteria => criteria.criteriaHeaders but to no avail. Thanks for suggestion, Till Rohrmann's worked for me perfectly. Commented Aug 27, 2015 at 14:19

1 Answer 1

1

The problem is that an implicit conversion which takes an explicit parameter won't be called to obtain the implicit argument for the Service.findName method. There are two solutions to your problem.

  1. Call the findName method with an explicit second parameter list and the Criteria argument. Then the compiler knows that it has to convert the criteria value into a CriteriaHeaders.
class ProjectController(service: Service) { implicit def criteriaToCriteriaHeaders(criteria: Criteria): CriteriaHeaders = criteria.criteriaHeaders def findName(criteria: Criteria) = { service .findName(criteria.id)(criteria) .fold( error => error, name => name ) } } 
  1. Make the parameter criteria of ProjectController.criteriaToCriteriaHeaders and ProjectController.findName implicit. Then the implicit conversion will be used.
class ProjectController(service: Service) { implicit def criteriaToCiteriaHeaders(implicit criteria: Criteria): CriteriaHeaders = criteria.criteriaHeaders def findName(implicit criteria: Criteria) = { service .findName(criteria.id) .fold( error => error, name => name ) } } 
Sign up to request clarification or add additional context in comments.

1 Comment

@KaC, glad that I could help :-)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.