2014年2月22日土曜日
Jersey2.6(JAX-RS2.2) with Jetty9 セットアップ
JAX-RS2.*を使いたいと思って、Jersey2.6をJetty9に組み込もうとしたのですが、
四苦八苦したのでメモ
いろいろdependancyに入れすぎてたのが問題だったようです。
jsr311-apiをdependancyから取り除くとうまくいきました。
JAX-RS2.*では、Pojomappingを指定するのではなく
JAX-RS JSON Providerに対応するライブラリを追加することでJSONに対応します。
下の例では、jackson-jaxrs-json-providerを追加しています。
JavaEE3以上は、jersey-container-servlet-coreを使うよう言われますが
自分は以前のweb.xmlでの指定方法が好みなので
jersey-container-servletを使っています。
pom.xml :
<略>
<properties>
<java.version>1.7</java.version>
<jettyVersion>9.1.2.v20140210</jettyVersion>
<jerseyVersion>2.6</jerseyVersion>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jettyVersion}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jettyVersion}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jerseyVersion}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jerseyVersion}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.2.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jettyVersion}</version>
<configuration>
<webAppSourceDirectory>${basedir}/webapp</webAppSourceDirectory>
<webXmlFile>${basedir}/webapp/WEB-INF/web.xml</webXmlFile>
<jettyEnvXml>${basedir}/webapp/WEB-INF/jetty-env.xml</jettyEnvXml>
<contextPath>/</contextPath>
</configuration>
</plugin>
</plugins>
</build>
WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>パッケージ</param-value>
</init-param>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</web-app>
WEB-INF/jetty-env.xml:
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
<Call name="setAttribute">
<Arg>org.eclipse.jetty.webapp.configuration</Arg>
<Arg>
<Array type="java.lang.String">
<Item>org.eclipse.jetty.webapp.WebInfConfiguration</Item>
<Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
<Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
<Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
<Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
<Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
<Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>
<Item>org.eclipse.jetty.webapp.TagLibConfiguration</Item>
</Array>
</Arg>
</Call>
<Set name="war"><SystemProperty name="jetty.home" default="."/>/</Set>
</Configure>
2013年11月15日金曜日
Jersey ApacheHttpClientをつかう
Javaでhttpから何かを取得する場合に、
一番簡単に扱えてかつ拡張性が高いのは
Jersey ApacheHttpClient だとおもいますという話。
ApacheHttpClientの特徴は、オブジェクトマッピングをしてくれるという点です
String型で取得する場合は次のようにすればよい
String res = ApacheHttpClient.create().resource(urlString).get(String.class);
一行ですんじゃいます。
またJSONやXMLを取得する場合にJAXBによる変換を行うことができます。
取得するXMLがつぎのような場合、
<?xml version="1.0"?>
<date>2012/10/11</date>
<hash>hogehogegeee</hash>
<rank>1</rank>
<value>2</value>
<addTime>2012/10/11 12:00</addTime>
マッピングをするクラスを次のように定義して、
Ranking.java :
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Ranking {
@XmlElement
public Date date;
@XmlElement
public String hash;
@XmlElement
public int rank;
@XmlElement
public long value;
@XmlElement
public Date addTime;
public Ranking(){}
}
で、次のようにすれば指定したクラスにマッピングして取得することができます。
Ranking ranking = restClient.resource(urlString).get(Ranking.class);
タイムアウトの設定
接続タイムアウト
ApacheHttpClient client = ApacheHttpClient.create();
client.setConnectTimeout(360000);
読み込みタイムアウト
client.setReadTimeout(900000);
フィルターを定義することによって、通信の前後の挙動を
ファンクションクラス?として定義して使いまわすことができます。
クッキーを管理してセッション等を保持する場合は下のような
フィルターを登録すればよいようです。
ApacheHttpClientConfig config = new DefaultApacheHttpClientConfig();
config.getProperties().put(ApacheHttpClientConfig.PROPERTY_HANDLE_COOKIES, true);
ApacheHttpClient client = ApacheHttpClient.create(config);
client.addFilter(new ClientFilter() {
private ArrayList
単にCookieを渡したいだけならWebResourceから指定もできます。
ApacheHttpClient client = ApacheHttpClient.create();
String res = client
.resource(url)
.header(HttpHeaders.COOKIE, cookieString)
.get(String.class);
Jersey Clientと同じようにFilterで登録するかWebResourceにヘッダーを追加する方法です。
Filterを追加する場合:
ApacheHttpClient client = ApacheHttpClient.create();
client.addFilter(new ClientFilter() {
@Override
public ClientResponse handle(ClientRequest request)
throws ClientHandlerException {
request.getHeaders().put("UserAgent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9b5) Gecko/2008032619 Firefox/3.0b5");
return getNext().handle(request);
}
});
WebResourceに追加する場合:
ApacheHttpClient client = ApacheHttpClient.create();
String res = client
.resource(url)
.header(HttpHeaders.USER_AGENT, userAgent)
.get(String.class);
Client作成時に渡します。
ApacheHttpClientConfig config = new DefaultApacheHttpClientConfig();
config.getProperties().put(
ApacheHttpClientConfig.PROPERTY_PROXY_URI,
"proxyurl");
ApacheHttpClient client = ApacheHttpClient.create(config);
Java自体の機能を利用します。
System.setProperty("socksProxyHost", "127.0.0.1");
System.setProperty("socksProxyPort", "9050");
SocksプロクシとApacheHttpClientのconfigでのプロクシの設定は
同時に利用可能です。両方設定した場合、Socksが優先されます。
一番簡単に扱えてかつ拡張性が高いのは
Jersey ApacheHttpClient だとおもいますという話。
通常の使い方
ApacheHttpClientの特徴は、オブジェクトマッピングをしてくれるという点です
String型で取得する場合は次のようにすればよい
String res = ApacheHttpClient.create().resource(urlString).get(String.class);
一行ですんじゃいます。
またJSONやXMLを取得する場合にJAXBによる変換を行うことができます。
取得するXMLがつぎのような場合、
<?xml version="1.0"?>
<date>2012/10/11</date>
<hash>hogehogegeee</hash>
<rank>1</rank>
<value>2</value>
<addTime>2012/10/11 12:00</addTime>
マッピングをするクラスを次のように定義して、
Ranking.java :
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Ranking {
@XmlElement
public Date date;
@XmlElement
public String hash;
@XmlElement
public int rank;
@XmlElement
public long value;
@XmlElement
public Date addTime;
public Ranking(){}
}
で、次のようにすれば指定したクラスにマッピングして取得することができます。
Ranking ranking = restClient.resource(urlString).get(Ranking.class);
よくある設定
タイムアウトの設定
接続タイムアウト
ApacheHttpClient client = ApacheHttpClient.create();
client.setConnectTimeout(360000);
読み込みタイムアウト
client.setReadTimeout(900000);
フィルターの定義
フィルターを定義することによって、通信の前後の挙動を
ファンクションクラス?として定義して使いまわすことができます。
Cookieの管理
クッキーは検証してないのですが、コンフィグで渡せば使えそうです。クッキーを管理してセッション等を保持する場合は下のような
フィルターを登録すればよいようです。
ApacheHttpClientConfig config = new DefaultApacheHttpClientConfig();
config.getProperties().put(ApacheHttpClientConfig.PROPERTY_HANDLE_COOKIES, true);
ApacheHttpClient client = ApacheHttpClient.create(config);
client.addFilter(new ClientFilter() {
private ArrayList
単にCookieを渡したいだけならWebResourceから指定もできます。
ApacheHttpClient client = ApacheHttpClient.create();
String res = client
.resource(url)
.header(HttpHeaders.COOKIE, cookieString)
.get(String.class);
UserAgentの設定
UserAgentの設定は2つの方法があります。Jersey Clientと同じようにFilterで登録するかWebResourceにヘッダーを追加する方法です。
Filterを追加する場合:
ApacheHttpClient client = ApacheHttpClient.create();
client.addFilter(new ClientFilter() {
@Override
public ClientResponse handle(ClientRequest request)
throws ClientHandlerException {
request.getHeaders().put("UserAgent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9b5) Gecko/2008032619 Firefox/3.0b5");
return getNext().handle(request);
}
});
WebResourceに追加する場合:
ApacheHttpClient client = ApacheHttpClient.create();
String res = client
.resource(url)
.header(HttpHeaders.USER_AGENT, userAgent)
.get(String.class);
プロキシの設定
HTTP プロクシの設定にはApacheHttpClientConfigをClient作成時に渡します。
ApacheHttpClientConfig config = new DefaultApacheHttpClientConfig();
config.getProperties().put(
ApacheHttpClientConfig.PROPERTY_PROXY_URI,
"proxyurl");
ApacheHttpClient client = ApacheHttpClient.create(config);
SocksプロクシとHTTPプロクシの優先順位
SocksプロクシにはApacheHttpClient自体は対応していないので、Java自体の機能を利用します。
System.setProperty("socksProxyHost", "127.0.0.1");
System.setProperty("socksProxyPort", "9050");
SocksプロクシとApacheHttpClientのconfigでのプロクシの設定は
同時に利用可能です。両方設定した場合、Socksが優先されます。
2013年10月5日土曜日
JAXB アノテーションを利用したJSON マッピング
Jerseyを使っているとレスポンス用のJSONの定義クラスに
アノテーションの@XmlTransitで省略したり
@XmlElement(name="element")で名前変更したりして
ObjectをJAXB経由でJSONに自動でパースさせてたりしますが
その定義を他でも使いまわして各々の処理でJSON文字列にパースする場合には
JacksonJAXBAnnotations
を利用すればいいです。
これは利用すればJAXBアノテーションを利用したマッピングが可能です。
mavenでpom.xmlに追加
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId>
<version>1.9.13</version>
</dependency>
Javaでは次のようにするればobjをJSONにパース可能
例ではやってないけどObjectMapperはthread safeなので使いまわしましょう
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectWriter;
import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;
…
JaxbAnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
ObjectWriter ow = new ObjectMapper().setAnnotationIntrospector(introspector).writer()
.withDefaultPrettyPrinter();
String json = ow.writeValueAsString(obj);
最初は、jerseyの内部ロジックを利用しようとしましたが
ひとつのオブジェクトしかないリストがオブジェクトでパースされる問題が発生したり
いちいちクラスタイプ指定しないといけないので面倒でやめました
ちなみに 最初はこんなかんじにしてました
private Class[] types = {
MyClass.class,
ArrayList.class,
};
String result = null;
JSONConfiguration config = JSONConfiguration.natural().build();
JSONJAXBContext ctx = new JSONJAXBContext(config, types);
JSONMarshaller m = ctx.createJSONMarshaller();
StringWriter sw = new StringWriter();
m.marshallToJSON(xmlObj, sw);
result = sw.toString();
return result;
JAXBContextResolverと似たような感じですね
POJOMappingFeatureで問題はどうにかなるかと思ったんですが
JacksonJAXBAnnotationsを使ったほうが楽だし早い
アノテーションの@XmlTransitで省略したり
@XmlElement(name="element")で名前変更したりして
ObjectをJAXB経由でJSONに自動でパースさせてたりしますが
その定義を他でも使いまわして各々の処理でJSON文字列にパースする場合には
JacksonJAXBAnnotations
を利用すればいいです。
これは利用すればJAXBアノテーションを利用したマッピングが可能です。
mavenでpom.xmlに追加
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId>
<version>1.9.13</version>
</dependency>
Javaでは次のようにするればobjをJSONにパース可能
例ではやってないけどObjectMapperはthread safeなので使いまわしましょう
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectWriter;
import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;
…
JaxbAnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
ObjectWriter ow = new ObjectMapper().setAnnotationIntrospector(introspector).writer()
.withDefaultPrettyPrinter();
String json = ow.writeValueAsString(obj);
最初は、jerseyの内部ロジックを利用しようとしましたが
ひとつのオブジェクトしかないリストがオブジェクトでパースされる問題が発生したり
いちいちクラスタイプ指定しないといけないので面倒でやめました
ちなみに 最初はこんなかんじにしてました
private Class[] types = {
MyClass.class,
ArrayList.class,
};
String result = null;
JSONConfiguration config = JSONConfiguration.natural().build();
JSONJAXBContext ctx = new JSONJAXBContext(config, types);
JSONMarshaller m = ctx.createJSONMarshaller();
StringWriter sw = new StringWriter();
m.marshallToJSON(xmlObj, sw);
result = sw.toString();
return result;
JAXBContextResolverと似たような感じですね
POJOMappingFeatureで問題はどうにかなるかと思ったんですが
JacksonJAXBAnnotationsを使ったほうが楽だし早い
登録:
投稿 (Atom)