2014年5月25日日曜日
Spring でのAsync処理 Queue
Queuingといえばメール送信や重たい処理を非同期で実行させる場合に
使わないと行けないというケースがあります。Spring には TaskExecutor という
非同期で処理を実行するQueueを取り扱うクラスがあります
これが何かと便利なので覚書
コマンド実行をQueueにするサンプル
asyncExecutorをautowiredして使います。
AsyncExecutor.java :
public class AsyncExecutor {
String command;
public void setCommand(String command) {
this.command = command;
}
@Autowired
private TaskExecutor taskExecutor;
public void execute(File file) {
taskExecutor.execute(new AsyncTask(file));
}
private class AsyncTask implements Runnable {
File file;
private AsyncTask(File file) {
this.file = file;
}
public void run() {
Runtime rt = Runtime.getRuntime();
try {
Process pr = rt.exec(command + " " + file.toString());
pr.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
bean定義
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" p:corePoolSize="5"
p:maxPoolSize="10" p:queueCapacity="100" p:waitForTasksToCompleteOnShutdown="true"/>
<bean id="asyncExecutor" class="sample.AsyncExecutor">
<property name="command" value=”/opt/jetty/bin/batch.sh"></property> </bean>
MailをTaskExecutorでおくる例は下記参照
http://www.i-develop.be/blog/2010/10/01/execute-tasks-asynchronously-with-spring-3-0/
非同期処理は自分で実装するのは気が引けるのでSpringでの実装は助かります
2014年5月15日木曜日
Spring Batch Adminにスケジュール機能をつけてみる
前回、Spring Batch Adminについて触れましたが、
Springには 3.0からTaskSchedulerという機能がついているのでそれを使って
Spring Batch Adminにスケジュールをホストさせてみます。
あくまで、Spring Batch Adminの使っているtaskLauncherを
TaskSchedulerから使うというものでAdminからスケジュールを編集できるとかではありません。
あしからず。
RunScheduler.java :
@Component
public class RunScheduler {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private ListableJobLocator jobLocator;
private String jobName;
public void setJobName(String jobName) {
this.jobName = jobName;
}
public void run() {
try {
String dateParam = new Date().toString();
JobParameters param = new JobParametersBuilder().addString("date",
dateParam).toJobParameters();
System.out.println(dateParam);
Job job = jobLocator.getJob(jobName);
JobExecution execution = jobLauncher.run(job, param);
} catch (Exception e) {
}
}
bean定義に次のようにスケジュールを定義します。
下の例では、テンプレートにあるsimpleJobを5分毎に実行します。
<bean id="runScheduler" class="my.package.RunScheduler">
<property name="jobName" value="simpleJob"/>
</bean>
<!-- Run every 5 minutes -->
<task:scheduled-tasks>
<task:scheduled ref="runScheduler" method="run" cron="0 */5 * * * *" />
</task:scheduled-tasks>
cronの記述方法については下記
http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/tutorial-lesson-06
記事を書いていて気づいた、
このscheduler自体をJob化すればadminからスケジュールの開始、停止もできる
Springには 3.0からTaskSchedulerという機能がついているのでそれを使って
Spring Batch Adminにスケジュールをホストさせてみます。
あくまで、Spring Batch Adminの使っているtaskLauncherを
TaskSchedulerから使うというものでAdminからスケジュールを編集できるとかではありません。
あしからず。
RunScheduler.java :
@Component
public class RunScheduler {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private ListableJobLocator jobLocator;
private String jobName;
public void setJobName(String jobName) {
this.jobName = jobName;
}
public void run() {
try {
String dateParam = new Date().toString();
JobParameters param = new JobParametersBuilder().addString("date",
dateParam).toJobParameters();
System.out.println(dateParam);
Job job = jobLocator.getJob(jobName);
JobExecution execution = jobLauncher.run(job, param);
} catch (Exception e) {
e.printStackTrace();
}}
}
bean定義に次のようにスケジュールを定義します。
下の例では、テンプレートにあるsimpleJobを5分毎に実行します。
<bean id="runScheduler" class="my.package.RunScheduler">
<property name="jobName" value="simpleJob"/>
</bean>
<!-- Run every 5 minutes -->
<task:scheduled-tasks>
<task:scheduled ref="runScheduler" method="run" cron="0 */5 * * * *" />
</task:scheduled-tasks>
cronの記述方法については下記
http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/tutorial-lesson-06
記事を書いていて気づいた、
このscheduler自体をJob化すればadminからスケジュールの開始、停止もできる
Spring Batch AdminのMySQL設定
バッチ実行にSpring Batchを利用しようかと検討しています。
jBatchがJavaEEに組み込まれたこともあり、
それに準拠した形でバッチを作ったほうがなにかと恩恵があるのかなと思ったというだけですが。
で、Spring BatchにはSpring Batch AdminというWebUIがあるので
使ってみます。あくまで、実行、停止、実行履歴が見れる程度のものです。
標準のdatabaseがhsqldbとなっているのでMySQLに変更します。
Adminのテンプレートでは
META-INF/batch-hsql.properties
というファイルがあるので次のファイルに変更します。
META-INF/batch-mysql.properties:
batch.jdbc.driver=com.mysql.jdbc.Driver
batch.jdbc.url=jdbc:mysql://localhost/test
batch.jdbc.user=user
batch.jdbc.password=
batch.jdbc.testWhileIdle=true
batch.jdbc.validationQuery=SELECT 1
batch.jdbc.maxActive=70
batch.jdbc.initialSize=20
batch.schema.script=classpath:/org/springframework/batch/core/schema-mysql.sql
batch.drop.script=classpath*:/org/springframework/batch/core/schema-drop-mysql.sql
batch.business.schema.script=classpath:/business-schema-mysql.sql
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer
# Non-platform dependent settings that you might like to change
batch.data.source.init=false
batch.data.source.init=falseはdatabase初期化するかという設定です。
一番最初に起動するときのみtrueにする必要があります。
このままだと、遅いので dataSourceをoverrideします。
次のファイルを作成します。
META-INF/spring/batch/override/war-content.xml :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch-2.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id=”dataSource” class=”org.apache.commons.dbcp.BasicDataSource”>
<property name=”driverClassName” value=”${batch.jdbc.driver}” />
<property name=”url” value=”${batch.jdbc.url}” />
<property name=”username” value=”${batch.jdbc.user}” />
<property name=”password” value=”${batch.jdbc.password}” />
<property name=”initialSize” value=”${batch.jdbc.initialSize}”/>
<property name=”maxActive” value=”${batch.jdbc.maxActive}”/>
</bean>
</beans>
実行時に引数を渡す必要があります。
-DENVIRONMENT=mysql
なのでmaven でデバッグするときは 次のようになる
jetty:run -Dmaven.surefire.debug test -DENVIRONMENT=mysql
せっかくなのでスケジュールに機能もつけてみました→次
jBatchがJavaEEに組み込まれたこともあり、
それに準拠した形でバッチを作ったほうがなにかと恩恵があるのかなと思ったというだけですが。
で、Spring BatchにはSpring Batch AdminというWebUIがあるので
使ってみます。あくまで、実行、停止、実行履歴が見れる程度のものです。
標準のdatabaseがhsqldbとなっているのでMySQLに変更します。
Adminのテンプレートでは
META-INF/batch-hsql.properties
というファイルがあるので次のファイルに変更します。
META-INF/batch-mysql.properties:
batch.jdbc.driver=com.mysql.jdbc.Driver
batch.jdbc.url=jdbc:mysql://localhost/test
batch.jdbc.user=user
batch.jdbc.password=
batch.jdbc.testWhileIdle=true
batch.jdbc.validationQuery=SELECT 1
batch.jdbc.maxActive=70
batch.jdbc.initialSize=20
batch.schema.script=classpath:/org/springframework/batch/core/schema-mysql.sql
batch.drop.script=classpath*:/org/springframework/batch/core/schema-drop-mysql.sql
batch.business.schema.script=classpath:/business-schema-mysql.sql
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer
# Non-platform dependent settings that you might like to change
batch.data.source.init=false
batch.data.source.init=falseはdatabase初期化するかという設定です。
一番最初に起動するときのみtrueにする必要があります。
このままだと、遅いので dataSourceをoverrideします。
次のファイルを作成します。
META-INF/spring/batch/override/war-content.xml :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch-2.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id=”dataSource” class=”org.apache.commons.dbcp.BasicDataSource”>
<property name=”driverClassName” value=”${batch.jdbc.driver}” />
<property name=”url” value=”${batch.jdbc.url}” />
<property name=”username” value=”${batch.jdbc.user}” />
<property name=”password” value=”${batch.jdbc.password}” />
<property name=”initialSize” value=”${batch.jdbc.initialSize}”/>
<property name=”maxActive” value=”${batch.jdbc.maxActive}”/>
</bean>
</beans>
実行時に引数を渡す必要があります。
-DENVIRONMENT=mysql
なのでmaven でデバッグするときは 次のようになる
jetty:run -Dmaven.surefire.debug test -DENVIRONMENT=mysql
せっかくなのでスケジュールに機能もつけてみました→次
2014年5月13日火曜日
Jetty 9.1.* の設定について
jetty 9.1.*系以降jettyの一部がモジュール化され
設定項目体系が変わっています
設定方法についてをすこしまとめておきます。
1.httpsを有効化
ダウンロードしたアーカイブのdemo-base以下にあるstart.d/ssl.ini、https.iniが参考になります
demo-baseのstart.d/ssl.ini、https.iniを start.dにコピペして
環境に合わせて修正する
2. jetty-envを有効化
そのままでOKただし、pom.xmlにjetty関連のdependancyがある場合
loaderエラーになる可能性があるのでjetty pluginでのみ必要な物は
jetty plugin 以下のdependancyに移す
3. jspを有効化
start.iniの--module=jspのコメントを外す
4. servletを有効化
defaultでservletsモジュールは読み込まれないので
jetty-servlets を使う場合は、
start.iniに--module=servletsを追加
5. リクエストログの有効化
start.iniに--module=requestlogを追加
等々
9.1.4はログ出力のリンク回りがバグっているのかjetty.shが動かない場合があるので注意
多分9.1.5で修正ずか?
設定項目体系が変わっています
設定方法についてをすこしまとめておきます。
1.httpsを有効化
ダウンロードしたアーカイブのdemo-base以下にあるstart.d/ssl.ini、https.iniが参考になります
demo-baseのstart.d/ssl.ini、https.iniを start.dにコピペして
環境に合わせて修正する
2. jetty-envを有効化
そのままでOKただし、pom.xmlにjetty関連のdependancyがある場合
loaderエラーになる可能性があるのでjetty pluginでのみ必要な物は
jetty plugin 以下のdependancyに移す
3. jspを有効化
start.iniの--module=jspのコメントを外す
4. servletを有効化
defaultでservletsモジュールは読み込まれないので
jetty-servlets を使う場合は、
start.iniに--module=servletsを追加
5. リクエストログの有効化
start.iniに--module=requestlogを追加
等々
9.1.4はログ出力のリンク回りがバグっているのかjetty.shが動かない場合があるので注意
多分9.1.5で修正ずか?
2014年4月17日木曜日
UUID <-> Base64 変換する Jackson用wrapperクラス
データベースでUUIDを何かと使うのですが、
JSONで出力すると'afb055a0-c18f-11e3-8b27-b1398a321474'みないな
文字列になってちょっと長いですし、
UUIDだというのがバレバレでそこはかとなく心配になります。
なので、JSONマッパーに渡すUUIDをwrapしてBase64としてマップするクラスを作ったので共有
表題にある通りJackson向けです
@JsonValueアノテーションをつけることで
このクラスをシリアライズする際にtoString()が呼ばれBase64化された値を返します
デシリアライズ 時には、
UUIDBase64(String uuidBase64)で初期化されUUIDBase64クラスとしてマップされます。
UUIDBase64.java :
import java.nio.ByteBuffer;
import java.util.UUID;
import org.apache.commons.codec.binary.Base64;
import org.codehaus.jackson.annotate.JsonValue;
import org.codehaus.jackson.annotate.JsonIgnore;
public class UUIDBase64 {
@JsonIgnore
private final UUID uuid;
public UUIDBase64(UUID uuid) {
this.uuid = uuid;
}
public UUIDBase64(String uuidBase64) {
byte[] bytes = Base64.decodeBase64(uuidBase64);
ByteBuffer bb = ByteBuffer.wrap(bytes);
this.uuid = new UUID(bb.getLong(), bb.getLong());
}
@JsonValue
public String toString(){
if (uuid == null)
return null;
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return Base64.encodeBase64URLSafeString(bb.array());
}
public UUID getUUID() {
return this.uuid;
}
public static UUIDBase64 fromUUID(UUID uuid) {
return new UUIDBase64(uuid);
}
public static UUIDBase64 fromBase64(String str) {
return new UUIDBase64(str);
}
}
次のように変換されます
class User {
UUIDBase64 id;
}
<-> { "id" : "base64の文字列" }->
JSONで出力すると'afb055a0-c18f-11e3-8b27-b1398a321474'みないな
文字列になってちょっと長いですし、
UUIDだというのがバレバレでそこはかとなく心配になります。
なので、JSONマッパーに渡すUUIDをwrapしてBase64としてマップするクラスを作ったので共有
表題にある通りJackson向けです
@JsonValueアノテーションをつけることで
このクラスをシリアライズする際にtoString()が呼ばれBase64化された値を返します
デシリアライズ 時には、
UUIDBase64(String uuidBase64)で初期化されUUIDBase64クラスとしてマップされます。
UUIDBase64.java :
import java.nio.ByteBuffer;
import java.util.UUID;
import org.apache.commons.codec.binary.Base64;
import org.codehaus.jackson.annotate.JsonValue;
import org.codehaus.jackson.annotate.JsonIgnore;
public class UUIDBase64 {
@JsonIgnore
private final UUID uuid;
public UUIDBase64(UUID uuid) {
this.uuid = uuid;
}
public UUIDBase64(String uuidBase64) {
byte[] bytes = Base64.decodeBase64(uuidBase64);
ByteBuffer bb = ByteBuffer.wrap(bytes);
this.uuid = new UUID(bb.getLong(), bb.getLong());
}
@JsonValue
public String toString(){
if (uuid == null)
return null;
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return Base64.encodeBase64URLSafeString(bb.array());
}
public UUID getUUID() {
return this.uuid;
}
public static UUIDBase64 fromUUID(UUID uuid) {
return new UUIDBase64(uuid);
}
public static UUIDBase64 fromBase64(String str) {
return new UUIDBase64(str);
}
}
次のように変換されます
class User {
UUIDBase64 id;
}
<-> { "id" : "base64の文字列" }->
2014年4月11日金曜日
HttpServletRequestのthread内共有 Spring編
HttpServletRequestを参照しようとした時に
引数で渡さずに、static fieldのthread localに保存して
スレッド内から参照できるようにする方法を昔紹介していましたが、
Spring使用時には標準の機能としてすでにあります。
次のようにRequestContextHolderからHttpServletRequestを取得します。
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
HttpServletRequest request =
(HttpServletRequest)attrs.resolveReference(RequestAttributes.REFERENCE_REQUEST);
web.xmlにlistenerを登録する必要があります。
web.xml:
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
Spring 2.5以上が必要です
使い道としては、エラー出力にリクエスト情報を出すとか
エラーハンドルのためにいちいち、
リクエストを引数には渡せないのでthreadに保持しているものを参照します。
ThreadLocalに自分で保存する記事よりは
既存のものを使うべきでしょう
引数で渡さずに、static fieldのthread localに保存して
スレッド内から参照できるようにする方法を昔紹介していましたが、
Spring使用時には標準の機能としてすでにあります。
次のようにRequestContextHolderからHttpServletRequestを取得します。
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
HttpServletRequest request =
(HttpServletRequest)attrs.resolveReference(RequestAttributes.REFERENCE_REQUEST);
web.xmlにlistenerを登録する必要があります。
web.xml:
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
Spring 2.5以上が必要です
使い道としては、エラー出力にリクエスト情報を出すとか
エラーハンドルのためにいちいち、
リクエストを引数には渡せないのでthreadに保持しているものを参照します。
ThreadLocalに自分で保存する記事よりは
既存のものを使うべきでしょう
2014年3月28日金曜日
Spring Security Auto Login
Spring Security を利用してログインセッション管理を
している方も多いと思います。
Spring Securityデフォルトのままで使うと
アカウント作成後に一度ユーザにログインしてもらわないといけないとか
イケてないので、そういう時に自動でログインセッションを作成する方法です
アカウント作成後に次のようなメソッドを呼びます
AuthenticationProvideのBeanを指定します(自作クラスでも動きます)
@Autowired
AuthenticationProvider authenticationProvider;
HttpServletRequestを予め取得しておいて、username, passwordから
tokenを発行し、authenticationProviderに登録します
private void doAutoLogin(String username, String password,
HttpServletRequest request) {
try {
// Must be called from request filtered by Spring Security,
// otherwise SecurityContextHolder is not updated
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
username, password);
token.setDetails(new WebAuthenticationDetails(request));
Authentication authentication = this.authenticationProvider
.authenticate(token);
// logger.debug("Logging in with [{}]",
// authentication.getPrincipal());
SecurityContextHolder.getContext()
.setAuthentication(authentication);
} catch (Exception e) {
SecurityContextHolder.getContext().setAuthentication(null);
logger.error("Failure in autoLogin", e);
}
}
AutowiredしなくてもSecurityContextHolderからいけるかも
しれないですね。そのうちやってみよ。
している方も多いと思います。
Spring Securityデフォルトのままで使うと
アカウント作成後に一度ユーザにログインしてもらわないといけないとか
イケてないので、そういう時に自動でログインセッションを作成する方法です
アカウント作成後に次のようなメソッドを呼びます
AuthenticationProvideのBeanを指定します(自作クラスでも動きます)
@Autowired
AuthenticationProvider authenticationProvider;
HttpServletRequestを予め取得しておいて、username, passwordから
tokenを発行し、authenticationProviderに登録します
private void doAutoLogin(String username, String password,
HttpServletRequest request) {
try {
// Must be called from request filtered by Spring Security,
// otherwise SecurityContextHolder is not updated
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
username, password);
token.setDetails(new WebAuthenticationDetails(request));
Authentication authentication = this.authenticationProvider
.authenticate(token);
// logger.debug("Logging in with [{}]",
// authentication.getPrincipal());
SecurityContextHolder.getContext()
.setAuthentication(authentication);
} catch (Exception e) {
SecurityContextHolder.getContext().setAuthentication(null);
logger.error("Failure in autoLogin", e);
}
}
AutowiredしなくてもSecurityContextHolderからいけるかも
しれないですね。そのうちやってみよ。
2014年3月25日火曜日
Session Counter Listener
セッション数をカウントするServlet コンテナ用のListenerを自作したので共有
サービスのセッション数 を監視してーという人はどうぞ
thread safeなはず。 Java1.5以上必要です
SessionCounterListener.java:
public class SessionCounterListener implements HttpSessionListener {
private static AtomicInteger totalActiveSessions = new AtomicInteger();
public static int getTotalActiveSession() {
return totalActiveSessions.get();
}
@Override
public void sessionCreated(HttpSessionEvent arg0) {
totalActiveSessions.incrementAndGet();
}
@Override
public void sessionDestroyed(HttpSessionEvent arg0) {
totalActiveSessions.decrementAndGet();
}
}
web.xmlにはListenerとして登録
web.xml :
<listener>
<listener-class>my.package.SessionCounterListener</listener-class>
</listener>
サービスのセッション数 を監視してーという人はどうぞ
thread safeなはず。 Java1.5以上必要です
SessionCounterListener.java:
public class SessionCounterListener implements HttpSessionListener {
private static AtomicInteger totalActiveSessions = new AtomicInteger();
public static int getTotalActiveSession() {
return totalActiveSessions.get();
}
@Override
public void sessionCreated(HttpSessionEvent arg0) {
totalActiveSessions.incrementAndGet();
}
@Override
public void sessionDestroyed(HttpSessionEvent arg0) {
totalActiveSessions.decrementAndGet();
}
}
web.xmlにはListenerとして登録
web.xml :
<listener>
<listener-class>my.package.SessionCounterListener</listener-class>
</listener>
Cassandra3.x CQLでBlobを扱う
CassandraでのBlobの扱いに半日ぐらい使ったので覚書
Cassandra3.0、datastax driver 2.0
でCQLを利用してBlobを扱う場合、
bindにByteBufferをかまさないといけません。
それと、row.getBytes()で取得したByteBufferをそのままarray()しても
ゴミの入ったbyte[]になってしまいます。
なので、次のようにする
bind時
byte[] byteArray;
prepare(cql).bind(ByteBuffer.wrap(byteArray));
取得時
import com.datastax.driver.core.utils.Bytes;
byte[] byteArray = Bytes.getArray(row.getBytes("bytes"));
Cassandra3.0、datastax driver 2.0
でCQLを利用してBlobを扱う場合、
bindにByteBufferをかまさないといけません。
それと、row.getBytes()で取得したByteBufferをそのままarray()しても
ゴミの入ったbyte[]になってしまいます。
なので、次のようにする
bind時
byte[] byteArray;
prepare(cql).bind(ByteBuffer.wrap(byteArray));
取得時
import com.datastax.driver.core.utils.Bytes;
byte[] byteArray = Bytes.getArray(row.getBytes("bytes"));
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>
2014年2月12日水曜日
Maven での デバッグ
Mavenでのデバッグ方法が検索しても見当たらなかったので
書き留めておきます。
Eclipseを利用している、m2eclipseをインストールしている前提です。
1.プロジェクトを右クリック>Debug As>Maven build...
2.Goalsに goal -Dmaven.surefire.debug test を設定
例) java ファイルを実行する場合
exec:java -Dmaven.surefire.debug test [-Dexec.mainClass="クラス名"] [-Dexec.args="引数"]
例) jettyを実行する場合
jetty:run -Dmaven.surefire.debug test
3.ParameterにName:forkCount Value:0を追加
これがないと、デバッグ用のポートをリスニングするのを回避
Maven v2.0.8 以降はmaven.surefire.debugを利用すれば
ポートを指定したリモートデバッグの必要はありません。
(実はずっとリモートデバッグしていた…)
書き留めておきます。
Eclipseを利用している、m2eclipseをインストールしている前提です。
1.プロジェクトを右クリック>Debug As>Maven build...
2.Goalsに goal -Dmaven.surefire.debug test を設定
例) java ファイルを実行する場合
exec:java -Dmaven.surefire.debug test [-Dexec.mainClass="クラス名"] [-Dexec.args="引数"]
例) jettyを実行する場合
jetty:run -Dmaven.surefire.debug test
3.ParameterにName:forkCount Value:0を追加
これがないと、デバッグ用のポートをリスニングするのを回避
Maven v2.0.8 以降はmaven.surefire.debugを利用すれば
ポートを指定したリモートデバッグの必要はありません。
(実はずっとリモートデバッグしていた…)
2014年1月31日金曜日
Java 8を使ってみる(使用編・Stream編1)
Java 8には、Streamというクラスが追加されています。
面倒くさい説明を少々しますので飛ばす人はこちらへ→スキップ
StreamはC#でいうIEnumbleに準ずるもので、中間処理を実行しても実際の絞り込みは
実行されず、終端処理を呼び出された際に実行されるというものです。
下の例のような記述ができます。
ここでは、
中間処理のfilter、mapToIntでは絞込は行われず、
終端処理のsumが呼ばれる際に遅延的に実行されます。
言い換えると、繰り返し処理を関数的に記述できるようになるというところでしょうか。
また、終端処理まで状態を保持しないため並列化にも適しています。
stream()のかわりにparallelStream()を使うことによって、処理を並列的に実行します。
サーバではもともとマルチスレッドなので他のコアも処理してたりして、
あまり恩恵ないかもしれないですが、可読性と並列化が捗りますね\(^o^)/。
ということで、
StreamとSQLのクエリと比較してみましょう。
SELECT TestMember.id
//Listに変換
List list = members.stream().map(TestMember::getId)
.collect(Collectors.toList());
//Setに変換
Set set = members.stream().map(TestMember::getId)
.collect(Collectors.toCollection(TreeSet::new));
TestMember::getIdは関数渡しでメソッドを渡しています。
map中でgetIdを呼び出した値を利用しています。
SELECT sum(TestMember.weight)
total = members.stream()
.mapToInt(x -> x.getWeight())
.sum();
合計を求める方法には、Collectorを使う方法もあります
int total = members.stream()
.collect(Collectors.summingInt(x -> x.getWeight()));
SELECT avg(TestMember.weight)
double average = members.stream()
.mapToInt(x -> x.getWeight())
.average()
.orElse(0d);
orElse()というメソッドが出てきました。
average()は、OptionalDoubleというNull許容なオブジェクトを返します。
OptionalDoubleのNullの場合のデフォルト値を指定してdoubleを返すのがorElse()です。
OptionalDoubleは、C#でいうところのdouble?ですね。
//SQL
SELECT TestMember.weight
members.stream()
.mapToInt(x -> x.getWeight())
.findFirst()
.orElse(0);
//SQL
//グループ分け
Map = members.stream()
.collect(Collectors.groupingBy(x -> x.getPart()));
同じpartのTestMemberをpart毎のマップにする。
本当は、groupingByには関数渡しで、TestMember::getPartとできるはずが、
エラーになっちゃいますね。
//パーティション
Map members.stream()
.collect(Collectors.partitioningBy(s -> s.getId() >= 5));
boolean match = members.stream().anyMatch(b -> b.getId() > 5);
countを使うより軽いはず?
weightでソートする
ソートをstream、ラムダ式で実装してみた
members.stream().sorted((r,l) -> {
return Integer.compare(r.weight, l.weight);
}).collect(Collectors.toList());
ソートするだけならもっと効率のいい方法があるかな
parallelStreamが使えるから早いのか?むむ?
今回使ったプロジェクト->StreamSample.zip
面倒くさい説明を少々しますので飛ばす人はこちらへ→スキップ
StreamはC#でいうIEnumbleに準ずるもので、中間処理を実行しても実際の絞り込みは
実行されず、終端処理を呼び出された際に実行されるというものです。
下の例のような記述ができます。
int sumOfRedWeights = blocks.stream().filter(b -> b.getColor() == RED)
.mapToInt(b -> b.getWeight())
.sum();
ここでは、
blocksをgetColor()==REDで絞り込み(filter)、
getWeight()を抽出して(mapToInt)合計しています(sum)。
中間処理のfilter、mapToIntでは絞込は行われず、
終端処理のsumが呼ばれる際に遅延的に実行されます。
言い換えると、繰り返し処理を関数的に記述できるようになるというところでしょうか。
また、終端処理まで状態を保持しないため並列化にも適しています。
stream()のかわりにparallelStream()を使うことによって、処理を並列的に実行します。
サーバではもともとマルチスレッドなので他のコアも処理してたりして、
あまり恩恵ないかもしれないですが、可読性と並列化が捗りますね\(^o^)/。
ということで、
StreamとSQLのクエリと比較してみましょう。
単純なSELECTでTestMember.idのみを抽出する
//SQLSELECT TestMember.id
//Listに変換
List
.collect(Collectors.toList());
//Setに変換
Set
.collect(Collectors.toCollection(TreeSet::new));
TestMember::getIdは関数渡しでメソッドを渡しています。
map中でgetIdを呼び出した値を利用しています。
Member.weightの合計を求める
//SQLSELECT sum(TestMember.weight)
total = members.stream()
.mapToInt(x -> x.getWeight())
.sum();
合計を求める方法には、Collectorを使う方法もあります
int total = members.stream()
.collect(Collectors.summingInt(x -> x.getWeight()));
平均を求める
//SQLSELECT avg(TestMember.weight)
double average = members.stream()
.mapToInt(x -> x.getWeight())
.average()
.orElse(0d);
orElse()というメソッドが出てきました。
average()は、OptionalDoubleというNull許容なオブジェクトを返します。
OptionalDoubleのNullの場合のデフォルト値を指定してdoubleを返すのがorElse()です。
OptionalDoubleは、C#でいうところのdouble?ですね。
切り出し
何番目の要素を指定して取り出すということもできます。//SQL
SELECT TestMember.weight
LIMIT 1
members.stream()
.mapToInt(x -> x.getWeight())
.findFirst()
.orElse(0);
//SQL
SELECT * OFFSET 1 LIMIT 2
members.stream()
.skip(1)
.limit(2).toArray();
グループ・パーティション
Stream には group byや partitioned byに当たるメソッドもあります//グループ分け
Map
.collect(Collectors.groupingBy(x -> x.getPart()));
同じpartのTestMemberをpart毎のマップにする。
本当は、groupingByには関数渡しで、TestMember::getPartとできるはずが、
エラーになっちゃいますね。
//パーティション
Map
.collect(Collectors.partitioningBy(s -> s.getId() >= 5));
その他
条件に一致したものが一件でもあるboolean match = members.stream().anyMatch(b -> b.getId() > 5);
countを使うより軽いはず?
weightでソートする
ソートをstream、ラムダ式で実装してみた
members.stream().sorted((r,l) -> {
return Integer.compare(r.weight, l.weight);
}).collect(Collectors.toList());
ソートするだけならもっと効率のいい方法があるかな
parallelStreamが使えるから早いのか?むむ?
今回使ったプロジェクト->StreamSample.zip
次回もStream編がつづく
2014年1月28日火曜日
OpenCV for iOS 1/27, 2014 ビルド
1/27, 2014現在のgitリポジトリからダウンロードした
OpenCV はiOS向けにはそのままだとビルドできません。
そのための修正をメモ
ソース修正
対象ファイルの指定行を追加修正
3rdParty/libjpeg/CMakeLists.txt:12, jmemansi.c をビルドから除く(これはすでに適応済み?)
if(ANDROID OR IOS)
ocv_list_filterout(lib_srcs jmemansi.c)
else()
ocv_list_filterout(lib_srcs jmemnobs.c)
endif()
modules/world/CMakeLists.txt:105 追加
ocv_list_filterout(objlist jmemansi) # <<= dirty fix
arm64対応
https://stackoverflow.com/questions/18976893/how-to-compile-opencv-for-ios7-arm64
arm64ビルドは諦めて、
armv7, armv7sのみのビルドに変更する
のincludeに追加
opencv/3rdparty/zlib/ にある
gzlib.c, gzread.c, gzwrite.c#include
<
unistd.h>
opencv/platforms/ios/build_framework.py
行99、100: 変更targets = ["iPhoneOS", "iPhoneOS", ""iPhoneSimulator", "iPhoneSimulator"]
archs = ["armv7", "armv7s", "i386", "x86_64"]
arm64を削除します
なくても、iPhone5sでも動く(プロジェクトが
armv7,armv7sでビルドされる場合)
ので取りあえずなしでビルド
ビルドする
ビルド環境のパスを通す
sudo ln -s /Applications/Xcode.app/Contents/Developer /Developer
cmakeない場合は、portからinstall
sudo port install cmake
ビルド
python platforms/ios/build_framework.py ios
※モバイル系の記事は人気あるなあ
2014年1月23日木曜日
Java 8を使ってみる (Timeクラス編)
Java 8を使ってみよう 3回目は、Timeクラスです。
前回はインターフェースを扱いました。流れ的に次はラムダ式かStreamかと思ったのですが、
まとめるのが難しいので先に箸休めでTimeクラスを紹介します。
さて、Dateクラス使うの面倒臭いと思いませんか。
日付処理をしようとするとCalendarクラスを使わないといけないし、
差分とかとっていろいろしたいけど…、
という要望に答えた、CalenerクラスとDateクラス(+α)を統合した
のがJava 8からのTimeクラスです。
時間を表すクラスには、いくつかあります。
代表的なのは、
LocalDateTime : タイムゾーンを含まない、日時
ZonedDateTime : タイムゾーンを含む、日時
になります。
ほかにもいろいろ追加されてますが、ここではLocalDateTimeを扱います。
今日の3時のDateクラスを作成したいとなった時に今までは、
Calendarクラスを使っていました。
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 3);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Date date = cal.getTime();
LocalDateTimeでは、クラスに日付処理が組み込まれているので、
Calendarのようなクラスを呼ぶ必要はありません。
LocalDateTime datetime = LocalDateTime.now()
.withHour(3).withMinute(0).withSecond(0).withNano(0);
指定日時のDateも作成しやすくなりました。
LocalDateTime datetime1 = LocalDateTime.of(2014, 5, 21, 1, 12);
一行で書けます。Javaではちょっと前から、一行で書くというのに
狂信的な人たちがいますね。
Dateクラスは比較がafter,beforeくらいだったのですが
Java 8からは、専用のクラスが追加されてかなり拡張されています。
むしろこちらの方が嬉しい
ふたつのLocalDateTimeクラスの差分をDurationクラスで表せます。
Duration duration = Duration.between(datetime, datetime1);
このdurationは、datetimeからdatetime1までのナノ秒を保持しています。
LocalDateTimeクラスに、plusすることでdurationの秒数を追加できます。
LocalDateTime datePlused = datetime.plus(duration);
他にもminusとかできます。
Durationがあると、C#のTimeSpanのようなことができます。
この記事の内容をTimeSpanからDurationに置き換えると次のようになる。
public static final TimeSpan TIMESPAN = TimeSpan.Days(7);
↓
Duration duration1 = Duration.ofDays(1);
で現在と差分を足したDateを求めるには、
Date date = TIMESPAN.getDate(new Date());
↓
now.plus(duration1);
とすればいい。
何に利用するかというと主に
Memcachedに渡すExpireの 定義とかです。
Memcached.get(key, new Memgetable<String>() {
public String get() {
return value;
}
}, TIMESPAN.getDate(new Date()));
↓
Memcached.get(key, () -> {
return value;
}, Date.from(now.plus(duration1).toInstant());
こんな風に記述ができます。
まだ、*DateTimeに対応してないのでDateに直さないといけないのが面倒
つづく
前回はインターフェースを扱いました。流れ的に次はラムダ式かStreamかと思ったのですが、
まとめるのが難しいので先に箸休めでTimeクラスを紹介します。
さて、Dateクラス使うの面倒臭いと思いませんか。
日付処理をしようとするとCalendarクラスを使わないといけないし、
差分とかとっていろいろしたいけど…、
という要望に答えた、CalenerクラスとDateクラス(+α)を統合した
のがJava 8からのTimeクラスです。
DateTime
時間を表すクラスには、いくつかあります。
代表的なのは、
LocalDateTime : タイムゾーンを含まない、日時
ZonedDateTime : タイムゾーンを含む、日時
になります。
ほかにもいろいろ追加されてますが、ここではLocalDateTimeを扱います。
日付処理
今日の3時のDateクラスを作成したいとなった時に今までは、
Calendarクラスを使っていました。
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 3);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Date date = cal.getTime();
LocalDateTimeでは、クラスに日付処理が組み込まれているので、
Calendarのようなクラスを呼ぶ必要はありません。
LocalDateTime datetime = LocalDateTime.now()
.withHour(3).withMinute(0).withSecond(0).withNano(0);
指定日時のDateも作成しやすくなりました。
LocalDateTime datetime1 = LocalDateTime.of(2014, 5, 21, 1, 12);
一行で書けます。Javaではちょっと前から、一行で書くというのに
狂信的な人たちがいますね。
日付差分
Dateクラスは比較がafter,beforeくらいだったのですが
Java 8からは、専用のクラスが追加されてかなり拡張されています。
むしろこちらの方が嬉しい
ふたつのLocalDateTimeクラスの差分をDurationクラスで表せます。
Duration duration = Duration.between(datetime, datetime1);
このdurationは、datetimeからdatetime1までのナノ秒を保持しています。
LocalDateTimeクラスに、plusすることでdurationの秒数を追加できます。
LocalDateTime datePlused = datetime.plus(duration);
他にもminusとかできます。
Durationがあると、C#のTimeSpanのようなことができます。
この記事の内容をTimeSpanからDurationに置き換えると次のようになる。
public static final TimeSpan TIMESPAN = TimeSpan.Days(7);
↓
Duration duration1 = Duration.ofDays(1);
で現在と差分を足したDateを求めるには、
Date date = TIMESPAN.getDate(new Date());
↓
now.plus(duration1);
とすればいい。
何に利用するかというと主に
Memcachedに渡すExpireの 定義とかです。
Memcached.get(key, new Memgetable<String>() {
public String get() {
return value;
}
}, TIMESPAN.getDate(new Date()));
↓
Memcached.get(key, () -> {
return value;
}, Date.from(now.plus(duration1).toInstant());
こんな風に記述ができます。
まだ、*DateTimeに対応してないのでDateに直さないといけないのが面倒
つづく
2014年1月20日月曜日
Java 8を使ってみる(使用編・インターフェース)
準備編のつづきです。
今回はJava 8 を実際に使ってみましょう。
重みづけ抽選のロジック(以下RandomUtil)を、Java 8だとどうなるのか見ていきます。
ここでは、主にインターフェースの変更点についてみていきます。
Java 8はインターフェースにFunctionalInterfaceというものが追加されました。
インターフェースに対して@FunctionalInterface宣言をするまたは、
一つのメソッドのみ定義するとFunctionalInterfaceと認識されます
RandomUtilだと、
public interface Weight<T> {
int getWeight(T temp) ;
}
はJava 8ではFunctionalInterfaceとなります。
@FunctionalInterface
public interface Weight<T> {
int getWeight(T temp) ;
}
と宣言をつけたものと同じ意味です。
FunctionalInterfaceにはラムダ式を渡すことができます。
TestMember member = RandomUtil.weightedRandom(members,
new Weight<TestMember>() {
public int getWeight(TestMember m) {
return m.weight;
}
});
以前までは、上記のように関数を渡していたのですが、
ラムダ式を渡すようにすると、次のように簡略化できます。
TestMember member = RandomUtil.weightedRandom(members,
m -> {
return m.weight;
});
また、インターフェースにDefaultMethodを追加できるようになりました。
public interface Weight<T> {
default int getWeight(T temp) {
return 1;
}
}
上のように定義した場合、
TestMember member = RandomUtil.weightedRandom(members,
new Weight<TestMember>() { });
とすると、getWeight の定義をしなくてもDefaultMethodとして定義している
メソッドが呼ばれます。ちなみに、DefaultMethodを定義していると
FunctionalInterfaceにはできません。
つづく
使用したプロジェクト:RandomUtil1.zip
今回はJava 8 を実際に使ってみましょう。
重みづけ抽選のロジック(以下RandomUtil)を、Java 8だとどうなるのか見ていきます。
ここでは、主にインターフェースの変更点についてみていきます。
FunctionalInterface
Java 8はインターフェースにFunctionalInterfaceというものが追加されました。
インターフェースに対して@FunctionalInterface宣言をするまたは、
一つのメソッドのみ定義するとFunctionalInterfaceと認識されます
RandomUtilだと、
public interface Weight<T> {
int getWeight(T temp) ;
}
はJava 8ではFunctionalInterfaceとなります。
@FunctionalInterface
public interface Weight<T> {
int getWeight(T temp) ;
}
と宣言をつけたものと同じ意味です。
FunctionalInterfaceにはラムダ式を渡すことができます。
TestMember member = RandomUtil.weightedRandom(members,
new Weight<TestMember>() {
public int getWeight(TestMember m) {
return m.weight;
}
});
以前までは、上記のように関数を渡していたのですが、
ラムダ式を渡すようにすると、次のように簡略化できます。
TestMember member = RandomUtil.weightedRandom(members,
m -> {
return m.weight;
});
Default Method
また、インターフェースにDefaultMethodを追加できるようになりました。
public interface Weight<T> {
default int getWeight(T temp) {
return 1;
}
}
上のように定義した場合、
TestMember member = RandomUtil.weightedRandom(members,
new Weight<TestMember>() { });
とすると、getWeight の定義をしなくてもDefaultMethodとして定義している
メソッドが呼ばれます。ちなみに、DefaultMethodを定義していると
FunctionalInterfaceにはできません。
つづく
使用したプロジェクト:RandomUtil1.zip
2014年1月19日日曜日
Java 8を使ってみる(準備編)
遅ればせながら、Java8を触ってみようと思います。
以前、昨年の5月かそれぐらいに、一度動かしてみようと思っていたのですが
対応するIDEもなく、あきらめて日数がかなりたってしまいました。
Java 8の特徴は、なんといってもラムダ式の導入と
C#でIEnumbleにあたるStreamを導入し、Linqのような実装ができるようになるということです。
C#もつかう身としてJavaでLinqポイ実装ができるのは感慨もひとしおです。
まずは、Java 8が動作する環境を作ります。
Java 8はまだ正式リリースではないので、あくまでも試験的なものです。
JDK 8 Early Access Releasesをダウンロードします。
https://jdk8.java.net/download.html
から環境に適したものをダウンロード、インストールします。
Eclipseというか、Spring Tool SuiteにJava8 supportのプラグインが
すでに入ったものがあるのでそれを利用します。
http://dist.springsource.com/snapshot/STS/nightly-distributions.html
上記のURLから
Spring Tool Suite - based on Eclipse 4.3 - including Java8 support
とあるところから、環境に適したものをダウンロードして、適当な場所に解凍します。
解凍したフォルダにあるSTS.exeを起動します。
起動したらまず、JDkのパスを通しましょう
Window[メニュー] > Preferences > Java > InstalledJREs
からインストールしたJDK 8 ("C:\Program Files\Java\jdk1.8.0")を追加します。
Java 8に対応したプロジェクトを追加してみましょう
プロジェクト追加する際に、
Use an execution environment JREからJavaSE-1.8を選びます。
これで、プロジェクトでJava 8が利用できます。
準備編はここまで、使用編につづきます
以前、昨年の5月かそれぐらいに、一度動かしてみようと思っていたのですが
対応するIDEもなく、あきらめて日数がかなりたってしまいました。
Java 8の特徴は、なんといってもラムダ式の導入と
C#でIEnumbleにあたるStreamを導入し、Linqのような実装ができるようになるということです。
C#もつかう身としてJavaでLinqポイ実装ができるのは感慨もひとしおです。
まずは、Java 8が動作する環境を作ります。
Java 8はまだ正式リリースではないので、あくまでも試験的なものです。
Java 8 JDKのインストール
JDK 8 Early Access Releasesをダウンロードします。
https://jdk8.java.net/download.html
から環境に適したものをダウンロード、インストールします。
Eclipseのインストール
Eclipseというか、Spring Tool SuiteにJava8 supportのプラグインが
すでに入ったものがあるのでそれを利用します。
http://dist.springsource.com/snapshot/STS/nightly-distributions.html
上記のURLから
Spring Tool Suite - based on Eclipse 4.3 - including Java8 support
とあるところから、環境に適したものをダウンロードして、適当な場所に解凍します。
Eclipseの設定
解凍したフォルダにあるSTS.exeを起動します。
起動したらまず、JDkのパスを通しましょう
Window[メニュー] > Preferences > Java > InstalledJREs
からインストールしたJDK 8 ("C:\Program Files\Java\jdk1.8.0")を追加します。
プロジェクトの追加
Java 8に対応したプロジェクトを追加してみましょう
プロジェクト追加する際に、
Use an execution environment JREからJavaSE-1.8を選びます。
これで、プロジェクトでJava 8が利用できます。
準備編はここまで、使用編につづきます
2014年1月18日土曜日
Windows8 でのmecab javaバインディング ビルド
mecabとjavaバインディングをビルドしたのでそのメモ
環境は、Windows 8.1 x64, Visual C++ 2010 Express
mecab0.996
Windows Software Development Kit (SDK) for Windows 8.1 をインストール
http://msdn.microsoft.com/en-US/windows/desktop/bg162891
mecabソースをダウンロード
https://mecab.googlecode.com/files/mecab-java-0.996.tar.gz
https://mecab.googlecode.com/files/mecab-0.996.tar.gz
取り敢えず、MsysでConfigureする
cd mecab-0.996
./configure
mecab-0.996/src/make.bat のパスを環境に合わせて修正
私の環境では次のように、上三行を変更
Set PATH=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin;%PATH%
Set INCLUDE=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include;%INCLUDE%
Set LIB=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib;%LIB%
mecab-0.996にlibmecab.dllができる
用意されてるバインディング(MeCab_wrap.cxx)だと動かないので
自分で作成する
swig -java -package org.chasen.mecab -c++ MeCab.i
MeCab_wrap.cxxが生成される
swigがない場合はここから、パスを通しても完全パス指定でもOK
mecab-java-0.997に作成したlibmecab.dllとMeCab_wrap.cxxをコピー
下のようなコマンドを実行する。パスは環境に合わせて変更
Set PATH=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin;%PATH%
Set INCLUDE=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include;%INCLUDE%
Set LIB=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib;%LIB%
cl /EHsc /LD /I mecab-0.996\src /I "C:\Program Files (x86)\Java\jdk1.7.0_09\include" /I "C:\Program Files (x86)\Java\jdk1.7.0_09\include\win32" MeCab_wrap.cxx libmecab.dll
動作確認
libmecab.dllとMeCab_wrap.dllをコピーして
適当なサンプルを実行
参考サイト:
http://ftablog.s56.xrea.com/index.php?itemid=167
内容はほぼ同じ(Windows7,mecab0.97)
環境は、Windows 8.1 x64, Visual C++ 2010 Express
mecab0.996
インストール
Windows Software Development Kit (SDK) for Windows 8.1 をインストール
http://msdn.microsoft.com/en-US/windows/desktop/bg162891
mecabソースをダウンロード
https://mecab.googlecode.com/files/mecab-java-0.996.tar.gz
https://mecab.googlecode.com/files/mecab-0.996.tar.gz
libmecabビルド
Configure
Configureする必要がるのか?取り敢えず、MsysでConfigureする
cd mecab-0.996
./configure
make.bat修正
mecab-0.996/src/make.bat のパスを環境に合わせて修正
私の環境では次のように、上三行を変更
Set PATH=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin;%PATH%
Set INCLUDE=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include;%INCLUDE%
Set LIB=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib;%LIB%
libmecab.dllを作成
mecab-0.996/src/make.batを実行mecab-0.996にlibmecab.dllができる
Javaバインディング
用意されてるバインディング(MeCab_wrap.cxx)だと動かないので
自分で作成する
mecab-0.996/src/mecab.h を修正する
「#ifndef SIWG」を「#ifndef SWIG」に全部修正(何か所かある)swigを実行する
cd mecab-0.996\swigswig -java -package org.chasen.mecab -c++ MeCab.i
MeCab_wrap.cxxが生成される
swigがない場合はここから、パスを通しても完全パス指定でもOK
MeCab_wrap.dllを作成
mecab-java-0.997に作成したlibmecab.dllとMeCab_wrap.cxxをコピー
下のようなコマンドを実行する。パスは環境に合わせて変更
Set PATH=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin;%PATH%
Set INCLUDE=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include;%INCLUDE%
Set LIB=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib;%LIB%
cl /EHsc /LD /I mecab-0.996\src /I "C:\Program Files (x86)\Java\jdk1.7.0_09\include" /I "C:\Program Files (x86)\Java\jdk1.7.0_09\include\win32" MeCab_wrap.cxx libmecab.dll
動作確認
libmecab.dllとMeCab_wrap.dllをコピーして 適当なサンプルを実行
参考サイト:
http://ftablog.s56.xrea.com/index.php?itemid=167
内容はほぼ同じ(Windows7,mecab0.97)
2014年1月17日金曜日
Android NDKビルド環境をUbuntu Serverに作ってみた
AndroidのNDKビルド用の環境はWindowsやMac上でも作れるのですが、
Windowsだとcygwinとか面倒くさいし
Macだとたまにldtoolがないとか怒られるので
VMWare上のUbuntuに作成することにしました。
これだとコピペで環境を保存したり増やしたりえきるので便利ですね。
VMWare上にすでにUbuntuがインストールされていることが前提です。
Serverなのは消費メモリが少ないとかリソースの問題です。
Build環境
sudo apt-get install build-essential
Windowsだとcygwinとか面倒くさいし
Macだとたまにldtoolがないとか怒られるので
VMWare上のUbuntuに作成することにしました。
これだとコピペで環境を保存したり増やしたりえきるので便利ですね。
VMWare上にすでにUbuntuがインストールされていることが前提です。
Serverなのは消費メモリが少ないとかリソースの問題です。
Build環境
sudo apt-get install build-essential
1.Javaのインストール
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get install oracle-java7-installer
2. Android NDKインストール
Android NDKをダウンロードします
tar -xvjof android-ndk-r9c-linux-x86_64.tar.bz2
sudo mv ./android-ndk-r9c /usr/local/
echo 'export PATH=$PATH:/usr/local/android-ndk-r9c' >> .bashrc
echo 'export NDKROOT=/usr/local/android-ndk-r9c' >> .bashrc
3. Android SDK インストール
Android SDKをダウンロードします
unzip adt-bundle-linux-x86_64-20131030.zip
sudo mv adt-bundle-linux-x86_64-20131030 /usr/local/
echo 'export PATH=$PATH:/usr/local/adt-bundle-linux-x86_64-20131030/sdk/tools' >> .bashrc
echo 'export PATH=$PATH:/usr/local/adt-bundle-linux-x86_64-20131030/sdk/platform-tools' >> .bashrc
ライセンス許可
Android SDKの実行には最初にライセンスの認証が必要です
cd /usr/local/adt-bundle-linux-x86_64-20131030/sdk/tools
echo "y" | ./android update sdk --no-ui
SDK一覧
次のコマンドでSDKの一覧が表示されます
./android list sdk
SDKアップデート
必要なSDKをインストール、アップデートします
android update sdk -u --filter platform-tools,android-16,android-8,extra-android-support
動かしてみる
ndk-buildを実行してみる
4.ビルドする際のメモ
個人的にAndroid.mkを利用するよりも
Configure時にSysroot, CC, CFLAG, LD, AR等を指定して
クロスコンパイルするほうがiOSと同じ要領なので楽
lib作成時にだいたいは次のようにして、static libraryを作って
あとで、static libraryを参照するAndroid.mkでsoにします
build.sh :
BINPATH=$NDK_ROOT/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin
export CROSS_COMPILE=$BINPATH/arm-linux-androideabi
export CC=${CROSS_COMPILE}-gcc
export CXX=${CROSS_COMPILE}-g++
export LD=${CROSS_COMPILE}-ld
export AR=${CROSS_COMPILE}-ar
export CFLAGS="--sysroot $SYSROOT -std=gnu99 -L$LIB_DIR -L${NDK_ROOT}/usr/lib -I${NDK_ROOT}/usr/include"
./configure --prefix="一時フォルダ" --enable-static --disable-shared --host=arm-linux-androideabi
※おそらくConfigure時にarm-linux-androideabiの定義がないと怒られるので
下のリンクからconfigure.guess, configure.subをダウンロードして
configureのあるフォルダに移動、上書きします
http://git.savannah.gnu.org/gitweb/?p=automake.git;a=blob_plain;f=lib/config.guess
http://git.savannah.gnu.org/gitweb/?p=automake.git;a=blob_plain;f=lib/config.sub
Android.mk :
この辺りが参考になるかとhttps://groups.google.com/forum/#!topic/android-group-japan/NMoJAioGi04
2014年1月15日水曜日
Windows 実行時、引数の最大長
Windowsでexeを実行する際の引数の最大長について
調べたのでメモ
Windowsのバージョンによっても違いますが
ここではWindows7以降の話
実行ファイルに渡すことのできる引数の最大長 32767 文字
これはUnicodeの制限から来ています
CMD.EXEからの実行の場合、
実行ファイル名も含めて、 8192文字
CMD.EXEの制限です
C#.net等からProcessを作成する場合、2048文字(たぶん)
UseShellExecute = falseにすればいいという噂もありますが、確認できませんでした
CMD.EXEから8192文字 以上の引数を実行 できないのは
結構ネックです。batファイルが実行できないですから。
CMD.EXEではなく、Shellを変更して,PowerShellやMsysを利用すれば
32767 文字まで利用可能なようです。
なので、batで動かない時はpsに拡張子を変更しましょう。
※長い引数を使うよりは、なるべくファイルで渡すべきですが
調べたのでメモ
Windowsのバージョンによっても違いますが
ここではWindows7以降の話
実行ファイルに渡すことのできる引数の最大長 32767 文字
これはUnicodeの制限から来ています
CMD.EXEからの実行の場合、
実行ファイル名も含めて、 8192文字
CMD.EXEの制限です
C#.net等からProcessを作成する場合、2048文字(たぶん)
UseShellExecute = falseにすればいいという噂もありますが、確認できませんでした
CMD.EXEから8192文字 以上の引数を実行 できないのは
結構ネックです。batファイルが実行できないですから。
CMD.EXEではなく、Shellを変更して,PowerShellやMsysを利用すれば
32767 文字まで利用可能なようです。
なので、batで動かない時はpsに拡張子を変更しましょう。
※長い引数を使うよりは、なるべくファイルで渡すべきですが
登録:
投稿 (Atom)