IntelliJさんの最新のEAP(build no:162.646.4)にしてみたら、
標準機能でIDEの背景画像設定できるようになってたので試してみた。
背景画像を設定する画面を開く
Find Actionから「Set Background Image」を検索して、設定画面を開きます。
下の画像の設定画面が開かれるので、お好きな画像を設定します。
オプションは試してないのでよくわかりません。
背景画像が設定された!
こんな感じになります。
おわり。
JBeretでは、ロジックでジョブ定義を構築することが出来るみたいなので試してみた。
これを使うと、xmlでジョブ定義をすることなくバッチを実行することができるようになる。
ただし、JSRで定められているわけではないので、バッチ実行時にJBeretを直接扱う必要がある。
ドキュメントはこちら→Programmatic Job Definition with Java | JBeret User Guide
JobBuilderやStepBuilderを使ってジョブ定義を構築していく感じになる。
batchletやreaderなんかに指定する名前は、xmlに定義する時と同じようにBeanの名称を設定する。
この例だと、sample-jobジョブに2つのステップがあって、batchlet-step -> chunk-stepの順に実行される。
val job = JobBuilder("sample-job") .step( StepBuilder("batchlet-step") .batchlet("sampleBatchlet") .next("chunk-step") .build() ) .step( StepBuilder("chunk-step") .reader("sampleItemReader") .writer("sampleItemWriter") .itemCount(2) .build() ) .build()
ジョブを実行するには、BatchRuntimeから取得したJobOperatorをJBeretの実装(JobOperatorImpl)にダウンキャストしてあげる。
JobOperatorImplには、JobBuilderで構築したJobオブジェクトを指定してジョブを実行するメソッドが用意されているので、それを使ってジョブを実行してあげる。
val jobOperator = BatchRuntime.getJobOperator() as JobOperatorImpl
val executionId = jobOperator.start(job, null)
ソースは全体はこちら→GitHub
おわり。
Gradleのグループ化機能を使うと同じ種類位のタスクをグループでまとめられるようになる。
IntelliJを使っている場合、Gradleウィンドウではグループ毎にタスクがまとめられて表示されるので、ビルドスクリプト側でグループ化しておくとIntelliJさんでもタスクが探しやすくなる感じです。
タスクをグループ化するには、タスクのgroupプロパティにグループ名を設定します。
この場合、run_batchletとrun_chunkのタスクがapplicationグループとなる。
task run_batchlet(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath main = 'org.jberet.se.Main' args 'batchlet-next-element-sample' } task run_chunk(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath main = 'org.jberet.se.Main' args 'chunk-next-element-sample' } [run_batchlet, run_chunk]*.group = 'application'
applicationグループにまとまってますね。
こちらも、ちゃんとグループにまとめられています。
ちなみにタスクの説明は、タスクのdescriptionプロパティに設定してあげると表示されるようになります。
Application tasks ----------------- installApp - Installs the project as a JVM application along with libs and OS specific scripts. run - Runs this project as a JVM application run_batchlet run_chunk
おわり。
Sphinxのドキュメントから、Javadocページ編のリンクを貼るのを簡単にするjavasphinx User’s Guide — javasphinx 0.9.8 documentationという拡張です。
この拡張を使うと、Javadocのトップページへのパスをconf.pyに設定して置けるので、
ここのページではクラスの完全修飾名を書くだけでよく割りと簡単にリンクが作成できます。
拡張のページに有るようにpipかeasy_installを使ってインストールします。
pip install javasphinx
か
easy_install -U javasphinx
拡張を使うためには、conf.pyのextensionsにこの拡張を追加する必要があります。
初期状態の場合、conf.pyに空の配列が設定されたextensionsがあるので以下のようにします。
extensions = ['javasphinx']
この拡張機能は、パッケージ単位にJavadocのURLを設定します。
この設定は、conf.pyに対して行います。
例えば、spring(org.springframework)のJavadocページヘのマッピングは、以下のようになります。
javadoc_url_map = { 'org.springframework' : ('http://docs.spring.io/spring-framework/docs/current/javadoc-api/', 'javadoc'), }
SpringのRestTemplateへのリンクの場合、以下のように書きます。
:java:extdoc:`org.springframework.web.client.RestTemplate`
生成されたSphinxのドキュメントは、以下のようになります。
リンクテキストを変えたい場合は、以下のように「リンクテキスト <クラスの完全修飾名>」とします。
:java:extdoc:`RestTemplate <org.springframework.web.client.RestTemplate>`
メソッドへのリンクは、完全修飾名の後にドット(.)+メソッド名で書きます。
メソッドの引数も正確に書く必要があります。
* :java:extdoc:`String#toString <java.lang.String.toString()>` * :java:extdoc:`String#replace <java.lang.String.replace(java.lang.CharSequence,%20java.lang.CharSequence)>`
生成されたSphinxのドキュメントは、以下のようになります。
おわり。
IntelliJ IDEAのバージョン16で、Mavenプロジェクトを開こううとした時に下のエラーが出た場合の対処方法。
com.intellij.execution.ExecutionException:
java.lang.UnsupportedClassVersionError: org/jetbrains/idea/maven/server/RemoteMavenServer : Unsupported major.minor version 52.0
お仕事で、リクエストボディのJSONの内容をログに出力したいんだと言われたので作ってみた。
1. FilterでServletRequestをラップする
2. ServletRequestのラッパーでは、InputStreamのgetterでログ出力機能をもったServletInputStream実装を返す
3. ログ出力機能を持ったServletInputStream実装では、read要求の中で読み込んだデータをログに出力する。
Filterでボディの内容を全部ログに出力してから、ServletRequestラップして後続に処理を移譲するでも良いんだけど、ボディが全部到達するまでFilterで処理止まってしまうんで、read要求の中でログ出力するようにしている感じです。
WildFly9.0.2で試したところ、デフォルトの構成だとServletRequestをラップすると怒られるので、以下コマンドでラップしたRequestやResponseを許容するようにしてあげる必要があるみたいです。
$ ./jboss-cli.sh [disconnected /] connect [standalone@localhost:9990 /] cd subsystem=undertow/servlet-container=default [standalone@localhost:9990 servlet-container=default] :write-attribute(name=allow-non-standard-wrappers, value=true)
ラッパーを許容しない設定の場合に発生する例外はこれ。
Exception handling request to /loggingfilter-1.0-SNAPSHOT/app: java.lang.IllegalArgumentException: UT010023: Request siosio.LoggingFilter$RequestWrapper@77ab9fb3 was not original or a wrapper
@WebFilter(urlPatterns = arrayOf("/app/*")) class LoggingFilter : Filter { override fun destroy() { } override fun init(filterConfig: FilterConfig?) { } override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) { // ServletRequestをラップして後続のフィルタに処理を移譲 chain.doFilter(RequestWrapper(request as HttpServletRequest), response) } class RequestWrapper(val request: HttpServletRequest) : HttpServletRequest by request { override fun getInputStream(): ServletInputStream? { // ログ出力機能付きのServletInputStreamを返す return LoggingInputStream(request.inputStream) } } class LoggingInputStream(val inputStream: ServletInputStream) : ServletInputStream() { companion object { val logger: Logger = Logger.getLogger(LoggingInputStream::class.java) } override fun isReady(): Boolean { return inputStream.isFinished } override fun isFinished(): Boolean { return inputStream.isFinished } override fun setReadListener(readListener: ReadListener?) { inputStream.setReadListener(readListener) } override fun read(b: ByteArray?): Int { return inputStream.read(b) } override fun read(b: ByteArray, off: Int, len: Int): Int { // 読み込んだ内容やバイト数をログに出力する val result = inputStream.read(b, off, len) logger.info("read http body. offset:$off, length:$result, data:${b.copyOf(result).toString("UTF-8")} ") return result } override fun readLine(b: ByteArray?, off: Int, len: Int): Int { return super.readLine(b, off, len) } override fun read(): Int { return inputStream.read() } } }
こんな感じにログに出力されますよと。
16:59:52,263 INFO [siosio.LoggingFilter$LoggingInputStream] (default task-4) read http body. offset:0, length:31, data:{ "name": "あいうえお" }
おわり。