Hatena::¥Ö¥í¥°(Diary)

CLOVER

2017-09-09

RESTEasy Client ¤ ÎClientHttpEngine ¤ òº ¹ ¤ ·ÂØ ¤ ¨ ¤ ë¡Êjava.net. HttpURLConnection¡¿OkHttp3¡Ë

RESTEasy Client ¤ ò »È ¤ ¦» þ¡ ¢ HTTP ¥ ¯ ¥ é ¥ ¤ ¥ ¢ ¥ ó ¥ È ¤ μÂÁõ ¤ È ¤ · ¤ Ƽ¡ ¤ Î2 ¤ Ä ¤ «¤ éÁªÂò ¤ ¹ ¤ ë ¤ ³ ¤ È ¤ zu ¤ Ç ¤ ¤ Þ ¤ ¹ ¡£

¥ Ç ¥ Õ ¥ © ¥ ë ¥ È ¤ Ï¡ ¢ Apache HttpComponents¡¿Client ¤ Ç ¤ ¹ ¡£

Apache HTTP Client 4.x and other backends

º£²ó ¤ Ï¡ ¢ ¤ ³ ¤ ÎÀÚ ¤ êÂØ ¤ ¨ ¤ ÈHTTP ¥ ¯ ¥ é ¥ ¤ ¥ ¢ ¥ ó ¥ È ¤ μÂÁõ ¤ òOkHttp3 ¤ Ë ¤ ¹ ¤ ë ¥ µ ¥ ó ¥ × ¥ ë ¤ ò½ñ ¤ ¤ ¤ Æ ¤ ß ¤ und ¤ ¤ ¤ È »× ¤ ¤ ¤ Þ ¤ ¹ ¡£

½àÈ÷

°Í¸ ¥ é ¥ ¤ ¥ Ö ¥ é ¥ ê ¤ Ï¡ ¢ ¼¡ ¤ Î ¤ è ¤ ¦ ¤ Ë ¤ · ¤ Þ ¤ · ¤ ¿¡£

libraryDependencies ++= Seq(
  // for RESTEasy Client
  "org.jboss.resteasy" % "resteasy-client" % "3.1.4.Final" % Compile exclude("junit", "junit"),
  "org.jboss.resteasy" % "resteasy-jackson2-provider" % "3.1.4.Final" % Compile,
  "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.8.9" % Compile,

  // dependency retrieve
  "org.jboss.resteasy" % "resteasy-jaxrs" % "3.1.4.Final" % Compile,
  "org.jboss.logging" % "jboss-logging" % "3.3.0.Final" % Compile,
  "org.jboss.logging" % "jboss-logging-annotations" % "2.0.1.Final" % Compile,
  "org.jboss.logging" % "jboss-logging-processor" % "2.0.1.Final" % Compile,
  "org.apache.httpcomponents" % "httpclient" % "4.5.2" % Compile,
  "com.fasterxml.jackson.core" % "jackson-core" % "2.8.9" % Compile,
  "com.fasterxml.jackson.core" % "jackson-annotations" % "2.8.9" % Compile,
  "com.fasterxml.jackson.core" % "jackson-databind" % "2.8.9" % Compile,
  "com.fasterxml.jackson.jaxrs" % "jackson-jaxrs-json-provider" % "2.8.9" % Compile,
  "javax.activation" % "activation" % "1.1.1" % Compile,
  "org.jboss.spec.javax.servlet" % "jboss-servlet-api_3.1_spec" % "1.0.0.Final" % Compile,
  "org.jboss.spec.javax.annotation" % "jboss-annotations-api_1.2_spec" % "1.0.0.Final" % Compile,
  "org.jboss.spec.javax.ws.rs" % "jboss-jaxrs-api_2.0_spec" % "1.0.1.Beta1" % Compile,
  "commons-io" % "commons-io" % "2.5" % Compile,
  "net.jcip" % "jcip-annotations" % "1.0" % Compile,

  // for Customize HttpEngine
  "com.squareup.okhttp3" % "okhttp" % "3.9.0" % Compile,

  // for test
  "org.jboss.resteasy" % "resteasy-netty4" % "3.1.4.Final" % Test,
  "io.netty" % "netty-all" % "4.1.15.Final" % Test,
  "org.scalatest" %% "scalatest" % "3.0.4" % Test
)

¤ ¨ ¤ é ¤ ¤ Ä ¹ ¤ ¤ ¤ ó ¤ Ç ¤ ¹ ¤ ± ¤ É¡ ¢ ¤ ³ ¤ ì ¤ Ïsbt ¤ ¬bom ¤ ò ¤ ¦ ¤ Þ ¤ ¯Íý²ò ¤ Ç ¤ ¤ Ê ¤ ¤ ¤ «¤ é ¤ ß ¤ und ¤ ¤ ¤ Ç ¤ ¹ ¡Ä¡£

°Í¸ ¤ · ¤ Æ ¤ ¤ ¤ ë³Æ¼ï ¥ é ¥ ¤ ¥ Ö ¥ é ¥ ê ¤ Î ¥ С¼ ¥ ¸ ¥ ç ¥ ó ¤ Ï¡ ¢ ¤ ³ ¤ Á ¤ é ¤ ò »² ¾È¡Ä¡£
https://github.com/resteasy/Resteasy/blob/3.1.4.Final/resteasy-dependencies-bom/pom.xml

¥ Û ¥ ó ¥ È ¤ Ï¡ ¢ ¤ ³ ¤ ì ¤ ¯ ¤ é ¤ ¤ ¤ Ç ¤ ¤ ¤ ¤ ¤ Î ¤ Ç ¤ ¹ ¤ ¬¡£¡Öjackson-module-scala¡× ¤ zu ¤ ¢ ¤ ë ¤ Î ¤ Ï¡ ¢ Scala ¤ ò »È ¤ à ¤ Æ ¤ ¤ ¤ ë´Ø ·¸ ¤« ¤ é ¤ Ç ¤ ¹ ¤ ± ¤ É ¤ Í¡£

  // for RESTEasy Client
  "org.jboss.resteasy" % "resteasy-client" % "3.1.4.Final" % Compile,
  "org.jboss.resteasy" % "resteasy-jackson2-provider" % "3.1.4.Final" % Compile,
  "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.8.9" % Compile,

¤ ³ ¤ Á ¤ é ¤ Ï¡ ¢ ¥ Æ ¥ ¹ ¥ ÈÍÑ ¤ Ç ¤ ¹ ¡£

  // for test
  "org.jboss.resteasy" % "resteasy-netty4" % "3.1.4.Final" % Test,
  "io.netty" % "netty-all" % "4.1.15.Final" % Test,
  "org.scalatest" %% "scalatest" % "3.0.4" % Test

¥ Æ ¥ ¹ ¥ ÈÍÑ ¤ ÎJAX-RS ¥ µ¡¼ ¥ С¼ ¤ Ï¡ ¢ Netty4¡ÜRESTEasy ¤ Çºî ¤ ë ¤ ³ ¤ È ¤ Ë ¤ · ¤ Þ ¤ ¹ ¡£

¤ ¢ ¤ È¡ ¢ Jackson2ÍÑ ¥ â ¥ ¸ ¥ 塼 ¥ ë ¤ ò͸ú²½ ¤ · ¤ Æ ¤ ª ¤ ¤ Þ ¤ · ¤ ç ¤ ¦ ¡£ ¤ ³ ¤ ¦ ¤ ¤ ¤ ¦ ¥ ¯ ¥ é ¥ ¹ ¤ òºîÀ®¡£
src/test/scala/org/littlewings/javaee7/resteasy/ScalaObjectMapperProvider.scala

package org.littlewings.javaee7.resteasy

import javax.ws.rs.{Consumes, Produces}
import javax.ws.rs.core.MediaType
import javax.ws.rs.ext.{ContextResolver, Provider}

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule

@Provider
@Consumes(Array(MediaType.APPLICATION_JSON))
@Produces(Array(MediaType.APPLICATION_JSON))
class ScalaObjectMapperProvider extends ContextResolver[ObjectMapper] {
  override def getContext(typ: Class[_]): ObjectMapper = {
    val objectMapper = new ObjectMapper
    objectMapper.registerModule(DefaultScalaModule)
    objectMapper
  }
}

¤ ³ ¤ Î ¥ ¯ ¥ é ¥ ¹ ¤ ¬Í¸ú ¤ Ë ¤ Ê ¤ ë ¤ è ¤ ¦ ¤ Ë¡ ¢ META-INF/services ¤ Ë »Å ¹ þ ¤ ó ¤ Ç ¤ ª ¤ ¤ Þ ¤ ¹ ¡£
src/test/resources/META-INF/services/javax.ws.rs.ext. Providers

org.littlewings.javaee7.resteasy.ScalaObjectMapperProvider

¥ ê ¥ ¯ ¥ ¨ ¥ ¹ ¥ È¡¿ ¥ ì ¥ ¹ ¥ Ý ¥ ó ¥ ¹ ¤ Ç »È ¤ ¦ Entity ¥ ¯ ¥ é ¥ ¹

ñ½ã ¤ Ë¡ ¢ ½ñÀÒ ¤ Ç¡£
src/test/scala/org/littlewings/javaee7/resteasy/Book.scala

package org.littlewings.javaee7.resteasy

case class Book(isbn: String, title: String, price: Int)

¥ Æ ¥ ¹ ¥ ÈÍÑJAX-RS ¥ µ¡¼ ¥ С¼

¥ Æ ¥ ¹ ¥ ÈÍÑ ¤ ÎJAX-RS ¥ µ¡¼ ¥ С¼ ¤ Ï¡ ¢ Netty4¡ÜRESTEasy ¤ ò »È ¤ à ¤ Æ ¤ ³ ¤ ó ¤ Ê ´ ¶ ¤ ¸ ¤ Ç¡£
src/test/scala/org/littlewings/javaee7/resteasy/TestRestServer.scala

package org.littlewings.javaee7.resteasy

import javax.ws.rs.core.MediaType
import javax.ws.rs._

import org.jboss.resteasy.plugins.server.netty.NettyJaxrsServer

object TestRestServer {
  def withServer(fun: => Unit): Unit = {
    val netty = new NettyJaxrsServer
    val deployment = netty.getDeployment
    deployment.setResourceClasses(java.util.Arrays.asList(classOf[TestResource].getName))
    netty.setRootResourcePath("")
    netty.setPort(8080)
    netty.setDeployment(deployment)
    netty.start()

    try {
      fun
    } finally {
      netty.stop()
    }
  }
}

@Path("test")
class TestResource {
  @GET
  @Path("get")
  @Produces(Array(MediaType.APPLICATION_JSON))
  def get: Book =
    Book("978-4798140926", "Java EE 7Å°ÄìÆþÌç ɸ½àJava¥Õ¥ì¡¼¥à¥ï¡¼¥¯¤Ë¤è¤ë¹â¿®ÍêÀ­Web¥·¥¹¥Æ¥à¤Î¹½ÃÛ", 4104)

  @POST
  @Path("post")
  @Consumes(Array(MediaType.APPLICATION_JSON))
  @Produces(Array(MediaType.APPLICATION_JSON))
  def post(book: Book): Book = book.copy(price = book.price * 2)

  @PUT
  @Path("put")
  @Consumes(Array(MediaType.APPLICATION_JSON))
  @Produces(Array(MediaType.APPLICATION_JSON))
  def put(book: Book): Book = book.copy(price = book.price * 2)

  @DELETE
  @Path("delete")
  @Consumes(Array(MediaType.APPLICATION_JSON))
  @Produces(Array(MediaType.APPLICATION_JSON))
  def delete(book: Book): Unit = ()
}

¤ Á ¤ ç ¤ à ¤ ÈÎã ¤ È ¤ · ¤ Æ ¤ ÏÈù̯ ¤ Ç ¤ ¹ ¤ ¬¡ ¢ POST¡¿PUT ¤ ÏÁ÷¿® ¤ µ ¤ ì ¤ Æ ¤ ¤ ¿½ñÀÒ¾ðÊó ¤ Î²Á³Ê ¤ ò2ÇÜ ¤ Ë ¤ · ¤ ÆÊÖ ¤ ¹ ¤ ³ ¤ È ¤ Ë ¤ · ¤ Þ ¤ · ¤ ¿¡£

  @POST
  @Path("post")
  @Consumes(Array(MediaType.APPLICATION_JSON))
  @Produces(Array(MediaType.APPLICATION_JSON))
  def post(book: Book): Book = book.copy(price = book.price * 2)

  @PUT
  @Path("put")
  @Consumes(Array(MediaType.APPLICATION_JSON))
  @Produces(Array(MediaType.APPLICATION_JSON))
  def put(book: Book): Book = book.copy(price = book.price * 2)

¤ ³ ¤ ó ¤ Ê ´ ¶ ¤ ¸ ¤ Ç »È ¤ ¤ ¤ Þ ¤ ¹ ¡£

TestRestServer.withServer {
  ....
}

¥ Æ ¥ ¹ ¥ È ¥ ³¡¼ ¥ É ¤ ο÷·Á

¥ Æ ¥ ¹ ¥ È ¥ ³¡¼ ¥ É ¤ ο÷·Á ¤ Ï¡ ¢ ¤ ³ ¤ Î ¤ è ¤ ¦ ¤ Ë¡£
src/test/scala/org/littlewings/javaee7/resteasy/RestEasyHttpEngineSpec.scala

package org.littlewings.javaee7.resteasy

import javax.ws.rs.client.{ClientBuilder, Entity}
import javax.ws.rs.core.Response

import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder
import org.jboss.resteasy.client.jaxrs.engines.URLConnectionEngine
import org.scalatest.{FunSuite, Matchers}

class RestEasyHttpEngineSpec extends FunSuite with Matchers {
  // ¤³¤³¤Ë¡¢¥Æ¥¹¥È¤ò½ñ¤¯¡ª
}

¤ Ç ¤ Ï¡ ¢ ½ç¼¡½ñ ¤ ¤ ¤ Æ ¤ ¤ ¤ à ¤ Æ ¤ ß ¤ Þ ¤ · ¤ ç ¤ ¦ ¡£

ɸ½à¡ÊApache HttpComponents¡¿Client¡Ë

¤ Þ ¤ º ¤ Ï¡ ¢ Apache HttpCompontents¡¿Client ¤ ò »È ¤ à ¤ und ¥ Ñ ¥ ¿¡¼ ¥ ó ¤« ¤ é¡£

¤ È ¤ ¤ ¤ à ¤ Æ ¤ â¡ ¢ ¤ ³ ¤ Á ¤ é ¤ Ï ¤ Õ ¤ Ä ¤ ¦ ¤ ˽ñ ¤ ± ¤ ÐOK ¤ Ç ¤ ¹ ¡£

  test("use standard engine") {
    TestRestServer.withServer {
      val client = ClientBuilder.newBuilder.build

      try {
        val response =
          client
            .target("http://localhost:8080/test/get")
            .request
            .get()

        response.getStatus should be(Response.Status.OK.getStatusCode)
        response.readEntity(classOf[Book]) should be(
          Book("978-4798140926", "Java EE 7Å°ÄìÆþÌç ɸ½àJava¥Õ¥ì¡¼¥à¥ï¡¼¥¯¤Ë¤è¤ë¹â¿®ÍêÀ­Web¥·¥¹¥Æ¥à¤Î¹½ÃÛ", 4104)
        )

        response.close()
      } finally {
        client.close()
      }
    }
  }

java.net. HttpURLConnection ¤ ò »È ¤ ¦

¤ Ç ¤ Ï¡ ¢ ¤ ³ ¤ ì ¤ òjava.net. HttpURLConnection ¤ ò »È ¤ ¦ ¤ è ¤ ¦ ¤ ËÀÚ ¤ êÂØ ¤ ¨ ¤ Æ ¤ ß ¤ Þ ¤ · ¤ ç ¤ ¦ ¡£

¤ ³ ¤ ó ¤ Ê ´ ¶ ¤ ¸ ¤ Ë ¤ Ê ¤ ê ¤ Þ ¤ ¹ ¡£

  test("use java.net.HttpConnection engine") {
    TestRestServer.withServer {
      val client = new ResteasyClientBuilder().httpEngine(new URLConnectionEngine).build()

      try {
        val response =
          client
            .target("http://localhost:8080/test/get")
            .request
            .get()

        response.getStatus should be(Response.Status.OK.getStatusCode)
        response.readEntity(classOf[Book]) should be(
          Book("978-4798140926", "Java EE 7Å°ÄìÆþÌç ɸ½àJava¥Õ¥ì¡¼¥à¥ï¡¼¥¯¤Ë¤è¤ë¹â¿®ÍêÀ­Web¥·¥¹¥Æ¥à¤Î¹½ÃÛ", 4104)
        )

        response.close()
      } finally {
        client.close()
      }
    }
  }

¥ Ý ¥ ¤ ¥ ó ¥ È ¤ Ï¡ ¢ ¤ ³ ¤ ³ ¤ À ¤ ± ¤ Ç ¤ ¹ ¡£

      val client = new ResteasyClientBuilder().httpEngine(new URLConnectionEngine).build()

JAX-RS ¤ ÎClient. Builder ¤ «¤ éResteasyClientBuilder ¤ ËÊÑ ¤ ¨¡ ¢ httpEngine ¥ á ¥ der l ¥ à ¥ É ¤ ÇURLConnectionEngine ¤ Î ¥ ¤ ¥ ó ¥ ¹ ¥ und ¥ ó ¥ ¹ ¤ òÀßÄê ¤ · ¤ Þ ¤ ¹ ¡£
¤ ³ ¤ ì ¤ À ¤ ± ¤ Ç¡ ¢ RESTEasy Client ¤ ÎÆâÉô ¤ Ç »È ¤ ï ¤ ì ¤ ëHTTP ¥ ¯ ¥ é ¥ ¤ ¥ ¢ ¥ ó ¥ È ¤ μÂÁõ ¤ òÀÚ ¤ êÂØ ¤ ¨ ¤ ë ¤ ³ ¤ È ¤ zu ¤ Ç ¤ ¤ Þ ¤ ¹ ¡£

RESTEasy Client ¤ ÎHTTP ¥ ¯ ¥ é ¥ ¤ ¥ ¢ ¥ ó ¥ È ¤ μÂÁõ ¤ ò¡ ¢ OkHttp3 ¤ ËÂØ ¤ ¨ ¤ Æ ¤ ß ¤ ë

¤ Ç ¤ Ï¡ ¢ º£ÅÙ ¤ ÏRESTEasy Client ¤ zu »È ¤ ¦ HTTP ¥ ¯ ¥ é ¥ ¤ ¥ ¢ ¥ ó ¥ È ¤ μÂÁõ ¤ ò¡ ¢ m« Á° ¤ ÇÍÑ°Õ ¤ · ¤ und ¤ â ¤ Î ¤ ˺ ¹ ¤ ·ÂØ ¤ ¨ ¤ Æ ¤ ß ¤ Þ ¤ · ¤ ç ¤ ¦ ¡£

º£²ó ¤ Î ¤ ªÂê ¤ È ¤ · ¤ Æ ¤ Ï¡ ¢ OkHttp3 ¤ ò »È ¤ ¦ ¤ ³ ¤ È ¤ Ë ¤ · ¤ Þ ¤ ¹ ¡£

OkHttp

Àè ¤ Û ¤ É ¤ Îjava.net. HttpURLConnection ¤ Ǻ ¹ ¤ ·ÂØ ¤ ¨ ¤ ¿Îã ¤ Ç ¤ ¢ ¤ ëÄøÅÙ ¤ ï ¤ «¤ ë ¤« ¤ â ¤ · ¤ ì ¤ Þ ¤ »¤ ó ¤ ¬¡ ¢ ResteasyClientBuilder#httpEngine ¤ ËÅÏ ¤ ¹ ¥ ¯ ¥ é ¥ ¹ ¤ ò
ºîÀ® ¤ ¹ ¤ ì ¤ ÐOK ¤ Ç ¤ ¹ ¡£

¤ Ä ¤ Þ ¤ ê¡ ¢ ClientHttpEngine ¥ ¤ ¥ ó ¥ ¿¡¼ ¥ Õ ¥ §¡¼ ¥ ¹ ¤ μÂÁõ ¥ ¯ ¥ é ¥ ¹ ¤ òºîÀ® ¤ · ¤ Þ ¤ ¹ ¡£
http://docs .jboss.org/resteasy/docs/3.1.4.Final/javadocs/org/jboss/resteasy/client/jaxrs/ClientHttpEngine.html

¼ÂÁõ ¤ · ¤ Ê ¤ ¯ ¤ Æ ¤ Ï ¤ ¤ ¤ ± ¤ Ê ¤ ¤ ¥ á ¥ der l ¥ à ¥ É ¤ Ï¡ ¢ ¼¡ ¤ Î4 ¤ Ä ¤ Ç ¤ ¹ ¡£

  • close
  • getHostnameVerifier
  • getSslContext
  • invoke

»² ¹ Í ¤ Ë ¤ ¹ ¤ ë ¤ Î ¤ Ï¡ ¢ ´ û¸ ¤ μÂÁõ ¤ Ç ¤ · ¤ ç ¤ ¦ ¡£ ¤ Ä ¤ Þ ¤ ê¡ ¢ ¤ ³ ¤ Î2 ¤ Ä¡£
https://Client4Engine.java
https://ionEngine.java

¤ Ç¡ ¢ ¼ÂÁõ ¤ · ¤ ¿·ë²Ì ¤ Ï ¤ ³ ¤ Á ¤ é¡£
src/main/scala/org/littlewings/javaee7/resteasy/OkHttpEngine.scala

package org.littlewings.javaee7.resteasy

import java.io.{ByteArrayOutputStream, InputStream}
import javax.net.ssl.{HostnameVerifier, SSLContext}
import javax.ws.rs.core.MultivaluedMap

import okhttp3.{MediaType, OkHttpClient, Request, RequestBody}
import org.jboss.resteasy.client.jaxrs.ClientHttpEngine
import org.jboss.resteasy.client.jaxrs.internal.{ClientInvocation, ClientResponse}
import org.jboss.resteasy.util.CaseInsensitiveMap

import scala.beans.BeanProperty

class OkHttpEngine extends ClientHttpEngine {
  val okHttpClient: OkHttpClient = new OkHttpClient

  @BeanProperty
  var sslContext: SSLContext = _

  @BeanProperty
  var hostnameVerifier: HostnameVerifier = _

  override def invoke(request: ClientInvocation): ClientResponse = {
    val okHttpRequestBuilder =
      new Request.Builder()
        .url(request.getUri.toURL)

    val body = Option(request.getEntity).map { _ =>
        val baos = new ByteArrayOutputStream
        request.getDelegatingOutputStream.setDelegate(baos)
        request.writeRequestBody(baos)
        baos.close()
        baos.toByteArray
    }

    val headers = request.getHeaders.asMap
    headers.entrySet.forEach(header => header.getValue.forEach(okHttpRequestBuilder.addHeader(header.getKey, _)))

    okHttpRequestBuilder.method(
      request.getMethod,
      body.map(RequestBody.create(MediaType.parse(request.getHeaders.getMediaType.toString), _)).getOrElse(null)
    )

    val okHttpRequest = okHttpRequestBuilder.build

    val okHttpResponse = okHttpClient.newCall(okHttpRequest).execute()

    val response = new ClientResponse(request.getClientConfiguration) {
      var inputStream: InputStream = _

      override def releaseConnection(): Unit = okHttpResponse.close()

      override def setInputStream(is: InputStream): Unit = inputStream = is

      override def getInputStream = {
        if (inputStream == null) {
          inputStream = okHttpResponse.body().byteStream()
        }

        inputStream
      }
    }

    response.setStatus(okHttpResponse.code())

    val responseHeaders: MultivaluedMap[String, String] = new CaseInsensitiveMap
    val headerNames = okHttpResponse.headers.names
    headerNames.forEach(name => okHttpResponse.headers(name).forEach(value => responseHeaders.add(name, value)))

    response.setHeaders(responseHeaders)
    response
  }

  override def close(): Unit = ()
}

OkHttpClient ¤ ÏÆà ¤ Ëclose ¤ ¹ ¤ ë ¤ â ¤ Î ¤ zu ¤ Ê ¤ ¤ ¤ Î ¤ Ç¡ ¢ ¼ÂÁõ ¤ ¬É¬Í× ¤ ʼ¡ ¤ Î3 ¤ Ä ¤ Ï´Êñ ¤ Ë ¤ Þ ¤ È ¤ á ¤ Þ ¤ · ¤ ¿¡£

  @BeanProperty
  var sslContext: SSLContext = _

  @BeanProperty
  var hostnameVerifier: HostnameVerifier = _

  override def close(): Unit = ()

¤ ¢ ¤ È ¤ Ï¡ ¢ invoke ¤ ò¼ÂÁõ ¤ ¹ ¤ ë ¤ À ¤ ± ¤ Ç ¤ ¹ ¡£

invoke ¥ á ¥ der l ¥ à ¥ É ¤ Ç ¤ Ï¡ ¢ RESTEasy ¦ ¤ «¤ éÅÏ ¤ µ ¤ ì ¤ ¿ClientInvocation ¤ ò¸µ ¤ Ë ¤ · ¤ à ¤ Æ¼ÂºÝ ¤ ËHTTP ¥ ê ¥ ¯ ¥ ¨ ¥ ¹ ¥ È ¤ òÅê ¤ ² ¤ Æ¡ ¢ ¤ der l ¤ ηë²Ì ¤ ò¸µ ¤ Ë
¥ ì ¥ ¹ ¥ Ý ¥ ó ¥ ¹ ¤ òºîÀ® ¤ · ¤ Æ¡ ¢ RESTEasy ¤ ËÌá ¤ ¹ ½èÍý ¤ ò¼ÂÁõ ¤ ¹ ¤ ë ¤ ³ ¤ È ¤ Ë ¤ Ê ¤ ê ¤ Þ ¤ ¹ ¡£

OkHttp ¦ ¤ Ø ¥ ê ¥ ¯ ¥ ¨ ¥ ¹ ¥ È ¤ òÀßÄê¡£

  override def invoke(request: ClientInvocation): ClientResponse = {
    val okHttpRequestBuilder =
      new Request.Builder()
        .url(request.getUri.toURL)

    val body = Option(request.getEntity).map { _ =>
        val baos = new ByteArrayOutputStream
        request.getDelegatingOutputStream.setDelegate(baos)
        request.writeRequestBody(baos)
        baos.close()
        baos.toByteArray
    }

    val headers = request.getHeaders.asMap
    headers.entrySet.forEach(header => header.getValue.forEach(okHttpRequestBuilder.addHeader(header.getKey, _)))

    okHttpRequestBuilder.method(
      request.getMethod,
      body.map(RequestBody.create(MediaType.parse(request.getHeaders.getMediaType.toString), _)).getOrElse(null)
    )

    val okHttpRequest = okHttpRequestBuilder.build

    val okHttpResponse = okHttpClient.newCall(okHttpRequest).execute()

¥ ì ¥ ¹ ¥ Ý ¥ ó ¥ ¹ ¤ Ï¡ ¢ ClientResponse ¤ Î ¥ µ ¥ Ö ¥ ¯ ¥ é ¥ ¹ ¤ È ¤ · ¤ ÆÊÖµÑ ¤ · ¤ Þ ¤ ¹ ¡£

    val response = new ClientResponse(request.getClientConfiguration) {
      var inputStream: InputStream = _

      override def releaseConnection(): Unit = okHttpResponse.close()

      override def setInputStream(is: InputStream): Unit = inputStream = is

      override def getInputStream = {
        if (inputStream == null) {
          inputStream = okHttpResponse.body().byteStream()
        }

        inputStream
      }
    }

¤ Þ ¤ ¿¡ ¢ ¤ ³ ¤ Î ¥ ì ¥ ¹ ¥ Ý ¥ ó ¥ ¹ ¤ ËOkHttp ¤ Î ¥ ì ¥ ¹ ¥ Ý ¥ ó ¥ ¹ ¤ zu »ý ¤ Ä ¥ ¹ ¥ Æ¡¼ ¥ und ¥ ¹ ¥ ³¡¼ ¥ É ¤ ä ¥ Ø ¥ à ¥ À¡¼ ¤ Ê ¤ É ¤ òÀßÄê ¤ · ¤ Þ ¤ ¹ ¡£

    response.setStatus(okHttpResponse.code())

    val responseHeaders: MultivaluedMap[String, String] = new CaseInsensitiveMap
    val headerNames = okHttpResponse.headers.names
    headerNames.forEach(name => okHttpResponse.headers(name).forEach(value => responseHeaders.add(name, value)))

    response.setHeaders(responseHeaders)
    response
  }

¤ ³ ¤ ì ¤ Ç ´ °À® ¤ Ç ¤ ¹ ¡£

¤ Ç ¤ Ï¡ ¢ »È ¤ à ¤ Æ ¤ ß ¤ Þ ¤ · ¤ ç ¤ ¦ ¡£

GET

  test("use OkHttp engine") {
    TestRestServer.withServer {
      val client = new ResteasyClientBuilder().httpEngine(new OkHttpEngine).build()

      try {
        val response =
          client
            .target("http://localhost:8080/test/get")
            .request
            .get()

        response.getStatus should be(Response.Status.OK.getStatusCode)
        response.readEntity(classOf[Book]) should be(
          Book("978-4798140926", "Java EE 7Å°ÄìÆþÌç ɸ½àJava¥Õ¥ì¡¼¥à¥ï¡¼¥¯¤Ë¤è¤ë¹â¿®ÍêÀ­Web¥·¥¹¥Æ¥à¤Î¹½ÃÛ", 4104)
        )

        response.close()
      } finally {
        client.close()
      }
    }
  }

POST

  test("use OkHttp engine, post") {
    TestRestServer.withServer {
      val client = new ResteasyClientBuilder().httpEngine(new OkHttpEngine).build()

      try {
        val response =
          client
            .target("http://localhost:8080/test/post")
            .request
            .post(Entity.json(Book("978-4774183169", "¥Ñ¡¼¥Õ¥§¥¯¥È Java EE", 3456)))

        response.getStatus should be(Response.Status.OK.getStatusCode)
        response.readEntity(classOf[Book]) should be(
          Book("978-4774183169", "¥Ñ¡¼¥Õ¥§¥¯¥È Java EE", 6912)
        )

        response.close()
      } finally {
        client.close()
      }
    }
  }

¥ ³¡¼ ¥ É ¤ ϾÊά ¤ · ¤ Þ ¤ ¹ ¤ ¬¡ ¢ PUT¡¿DELETE ¤ Ç ¤ âÆà ¤ ËÌäÂê ¤ Ê ¤ ¯¡£

¤ Þ ¤ È ¤ á

RESTEasy Client ¤ Ç¡ ¢ ÆâÉôŪ ¤ Ë »ÈÍÑ ¤ ¹ ¤ ëHTTP ¥ ¯ ¥ é ¥ ¤ ¥ ¢ ¥ ó ¥ È ¤ μÂÁõ ¤ ÎÊÑ ¹¹ ¡ ¢ m« ºî ¤ ò ¤ ä ¤ à ¤ Æ ¤ ß ¤ Þ ¤ · ¤ ¿¡£

¤ ¢ ¤ ó ¤ Þ ¤ ê¾ðÊó ¤ zu ¤ Ê ¤ ¤ ¤ Î ¤ Ç¡ ¢ ClientHttpEngine ¤ òºî ¤ ë ¤ È ¤ ³ ¤ í ¤ ϼ㠴 ³ ¤ Æ ¤ ³ ¤ º ¤ ê ¤ Þ ¤ · ¤ und ¤ ¬¡ ¢ ¤ Þ ¤ ¢ ºÇÄã¸Â ¤ Ï ¤ ³ ¤ ó ¤ Ê ¤ È ¤ ³ ¤ í ¤ «¤ Ê ¤ ¡ ¤ È¡£ ¤ È ¤ ê ¤ ¢ ¤ ¨ ¤ ºÆ° ¤«¤»¤ und ¤ Î ¤ Ç
ÎÉ ¤ · ¤ È ¤ · ¤ Þ ¤ · ¤ ç ¤ ¦ ¡£

º£²óºîÀ® ¤ · ¤ und ¥ ½¡¼ ¥ ¹ ¥ ³¡¼ ¥ É ¤ Ï¡ ¢ ¤ ³ ¤ Á ¤ é ¤ ËÃÖ ¤ ¤ ¤ Æ ¤ ¤ ¤ Þ ¤ ¹ ¡£
https://github.com/kazuhira-r/javaee7-scala-examples/tree/master/resteasy-customize-http-engine

¤ ¢ ¤ È¡ ¢ ¤ ³ ¤ Á ¤ é ¤ â »² ¹ Í ¤ Ë ¤ ¹ ¤ ë ¤ È ¤ è ¤ ¤ ¤« ¤ â¡ ©
https://github.com/tbroyer/jaxrs-utils/tree/master/resteasy-client-okhttp3

¥ ¹ ¥ Ñ ¥ àÂкö ¤ Î ¤ und ¤ á ¤ Î ¥ À ¥ ß¡¼ ¤ Ç ¤ ¹ ¡£ ¤ â ¤ · ¸ «¤ ¨ ¤ Æ ¤ ⲿ ¤ âÆþÎÏ ¤ · ¤ Ê ¤ ¤ ¤ Ç ¤ ¯ ¤ À ¤ µ ¤ ¤
¥²¥¹¥È


²èÁüÇ § ¾ Ú

¥ È ¥ é ¥ Ã ¥ ¯ ¥ Ð ¥ Ã ¥ ¯ - http://d.hatena.ne.jp/Kazuhira/20170909/1504966931