Search code examples
scalatypeclasstraitsfinagle

Traits not implemented in finagle service


I have a simple finagle service as follows:

import com.twitter.finagle.{Http,Service}
import com.twitter.util.{Await, Future}
import java.net.InetSocketAddress
import org.jboss.netty.handler.codec.http._
import org.jboss.netty.buffer.ChannelBuffers.copiedBuffer
import org.jboss.netty.util.CharsetUtil
import net.liftweb.json._
import com.twitter.finagle.http.{Request,Response,RichHttp}
import com.twitter.finagle.builder.ServerBuilder

case class Add(num1:Int, num2:Int)
case class Result(result:Int)  

trait Transformer[R1,T,U,R2] {
  def extractPayload(r:R1):T
  def responsePayload(u:U):R2
}

object Transformer{
  implicit object AddPayloadTransformer 
        extends Transformer[HttpRequest,Add,Result,HttpResponse]{
   implicit val formats = DefaultFormats

   def extractPayload(r:HttpRequest):Add = {
        val body = r.getContent
    val length = body.readableBytes()
    val bytes = new Array[Byte](length)
    body.getBytes(body.readerIndex(),bytes,0,length)
    val bodyStr = new String(bytes)
    parse(bodyStr).extract[Add]
    }

   def responsePayload(u:Result):HttpResponse = {   
    val result = u.result
    val response = Response(HttpVersion.HTTP_1_1,
                HttpResponseStatus.OK)
        response.setContentTypeJson()       
        response.setContentString(
          s"""
            {
            "result": $result
            }
           """)
        response.httpResponse
   }   
  }
}

object AdditionServer extends App with Transformer[HttpRequest,Add,Result,HttpResponse]{
 private def add(add:Add):Result = Result(add.num1 + add.num2) 

 private def additionHandler(req:HttpRequest): HttpResponse = {
     val addPayload = extractPayload(req)
     val result = add(addPayload)
     responsePayload(result)    
 }   

 val service = new Service[HttpRequest,HttpResponse] {
     def apply(req: HttpRequest): Future[HttpResponse] = 
    {
       Future.value(additionHandler(req))
    }
 }

  val server = Http.serve(":8080", service)
  Await.ready(server)
  println("Started service")                
}

When I try to compile it, I get the following exception:

AdditionService.scala:49: object creation impossible, since:
[error] it has 2 unimplemented members.
[error] /** As seen from object AdditionServer, the missing signatures are as follows.
[error]  *  For convenience, these are usable as stub implementations.
[error]  */
[error]   def extractPayload(r: org.jboss.netty.handler.codec.http.HttpRequest): Add = ???
[error]   def responsePayload(u: Result): org.jboss.netty.handler.codec.http.HttpResponse = ???
[error] object AdditionServer extends App with Transformer[HttpRequest,Add,Result,HttpResponse]{
[error]        ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed

To my knowledge I am implementing the traits with their proper signature.

Can somebody point out what might be going wrong here.

Thanks


Solution

  • AdditionServer is the object which is extending Transformer. In your code, this object is not defining neither extractPayload nor responsePayload thus the compilation error you get.

    You should move your methods definitions from the trait companion object to AdditionServer

    object AdditionServer extends App with
    Transformer[HttpRequest,Add,Result,HttpResponse] {
    
    import Transformer._
    
    def extractPayload(r:HttpRequest):Add = {
            val body = r.getContent
        val length = body.readableBytes()
        val bytes = new Array[Byte](length)
        body.getBytes(body.readerIndex(),bytes,0,length)
        val bodyStr = new String(bytes)
        parse(bodyStr).extract[Add]
    }
    
    def responsePayload(u:Result):HttpResponse = {   
        val result = u.result
        val response = Response(HttpVersion.HTTP_1_1,
                HttpResponseStatus.OK)
            response.setContentTypeJson()       
            response.setContentString(
              s"""
                {
                "result": $result
                }
               """)
            response.httpResponse
       }   
    }
    

    If you'd rather keep your methods defined at the companion object you can refer to them from AdditionServer:

    object Transformer{
      implicit object AddPayloadTransformer 
      extends Transformer[HttpRequest,Add,Result,HttpResponse]{
       implicit val formats = DefaultFormats
    
       def extractPayload(r:HttpRequest):Add = {
            val body = r.getContent
            val length = body.readableBytes()
            val bytes = new Array[Byte](length)
            body.getBytes(body.readerIndex(),bytes,0,length)
            val bodyStr = new String(bytes)
            parse(bodyStr).extract[Add]
        }
    
       def responsePayload(u:Result):HttpResponse = {   
            val result = u.result
            val response = Response(HttpVersion.HTTP_1_1,
                HttpResponseStatus.OK)
            response.setContentTypeJson()       
            response.setContentString(
              s"""
                {
                "result": $result
                }
               """)
            response.httpResponse
       }   
      }
    }
    
    object AdditionServer extends App with
    Transformer[HttpRequest,Add,Result,HttpResponse]{
    
       def extractPayload(r:HttpRequest):Add = Transformer.extractPayload(r)
    
       def responsePayload(u:Result):HttpResponse = Transformer.responsePayload(u)
    
      ...
      ...