プログラマメモ2 - programmer no memo2

SimpleDateFormatがスレッドセーフではない - 悪魔は忘れた頃にやってきた。 2024/03/30
2024/04/07

頭の片隅では、SimpleDateFormatがスレッドセーフでない件は、うっすら聞きかじっていたような気がしないでもないですが、スレッドセーフではないです。 それで、自分がよく過去に書くスタイルとして final static でnewしてもたせるというのを好んでやっていたので、うっすら汗をかくわけです。 そういえば、検証用のコード書いてためしていないようなーということで、いくつか試してみました。 検証をうまくするコツは、parseメソッドはすんなり検証することができましたが、 formatメソッドは、都度、新しいnew Date()で行わないと、だせなかった... 

 

 

nano秒スリープさせたいと思ったわけです。 2021/04/29

 javaです。

nano秒スリープさせたいと思ったわけです。

それで、スレッドのsleepにnanoとあったので、おっと思ったのですが、javadocを読むと「nanos - 0-999999追加でスリープするナノ秒」とあって、追加でなのでした。

 


public static void sleep(long millis,
                         int nanos)
                  throws InterruptedException



sleep - How to suspend a java thread for a small period of time, like 100 nanoseconds? - Stack Overflow
 

アイデアとしてはシンプルで、whileで回して止まったようにするというもの

コード書いて試してみました。cpuとかの仕組みがわかっとらんので、僕もあやういなー

https://github.com/ugonakawaka/pub/blob/master/java/aexample/src/a001_nano_sleep/Test01.java

 

そんなとこ

 

 

 

java.lang.IllegalArgumentException: Can not set com.google.api.services.blogger.model.Post$Author field com.google.api.services.blogger.model.Post.author to com.google.gson.internal.LinkedTreeMap 2021/03/28
2021/04/04

はじまり

blogger api です。javaです。 json→java objectをやっていて、gson使えばよいのかとやっていて エラーになってしまっていました。
java.lang.IllegalArgumentException: Can not set com.google.api.services.blogger.model.Post$Author field com.google.api.services.blogger.model.Post.author to com.google.gson.internal.LinkedTreeMap

方針変更

gsonを直接使う方法ではなく、com.google.api.client.json.JsonObjectParserを使う方法に変更。 以下、コード
final JsonFactory factory = GsonFactory.getDefaultInstance();
final JsonObjectParser parser = new JsonObjectParser(factory);
final InputStream inputStream = TestGson.class.getResourceAsStream("/list.json");
{
final Post[] posts = parser.parseAndClose(new InputStreamReader(inputStream), Post[].class);
Arrays.asList(posts).forEach(a -> {
System.out.println(a);
});
}

お試し投稿 2021/03/14
2021/04/17

 

class Test {


} 

お試し更新

openapi事始 2020/11/03

 openapi事始

 

 

まずは生成してみることにします。 いろいろやり方があるとは思うけど、
GitHub - jdegre/5GC_APIs: RESTful APIs of main Network Functions in the 3GPP 5G Core Network

 

試してみるのは、TS29510_Nnrf_NFManagement.yaml

3GPPのサイトを参照するのはよいとは思うけど

 

 

$ wget https://raw.githubusercontent.com/jdegre/5GC_APIs/master/TS29510_Nnrf_NFManagement.yaml

 

いまいちopenapiわかってないけど

 生成したいのはmodelだけ

あと、json<=>objectとのマッピングができることを確認したい。

 

 

Central Repository: org/openapitools/openapi-generator-cli
Config Options for java

 

なんかうまくいかない

https://github.com/OpenAPITools/openapi-generator/issues/559




 

 

java11 gaeのスタンダードエディションで その2 2020/07/27

前回の続き

うまくデプロイして動かすことができたので、次は最適化ということで、不要なjarファイルをwarから取る作業
webjarsは含めておこないとだめっぽいのでそれ以外←これはただしい?

参考)
[Apache Maven WAR Plugin – Including and Excluding Files From the WAR](https://maven.apache.org/plugins/maven-war-plugin/examples/including-excluding-files-from-war.html)
            <!-- [START make-a-war_plugin] -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.1</version>
                <configuration>
                    <packagingExcludes>
                        WEB-INF/lib/asm*.jar,
                        WEB-INF/lib/jetty*.jar,
                        WEB-INF/lib/kuromoji*.jar,
                        WEB-INF/lib/javax*.jar,
                        WEB-INF/lib/jackson*.jar,
                        WEB-INF/lib/commons*.jar,
                        WEB-INF/lib/firebase*.jar,
                        WEB-INF/lib/slf4j*.jar,
                        WEB-INF/lib/classg*.jar,
                    </packagingExcludes>
                </configuration>
            </plugin>
            <!-- [END make-a-war_plugin] -->

java11 gaeのスタンダードエディションで 2020/07/27

ようやく移行できたのでメモ


単純なjspがサーブレットぐらいしか動かさないかなということで、移行は、単純なjettyを含むやりかたでデプロイ

以前のやりかたから、なれたとてもシンプルになっているのかもしれない。
定義は以下

例)
# [START gae_java11_servlet_yaml]
runtime: java11
entrypoint: 'java -cp "*" jp.deiji.Main deijitools_googlapp-0.0.1.war'
# [END gae_java11_servlet_yaml]

自分で定義した、Mainクラスでjettyを動かして、そこにwarを渡してあげるというものっぽい。
ローカルの実行はうまくいって、さてGAEにデプロイしたら、

java.lang.ClassNotFoundException

が発生...ため息がでつつ調べたら以下


そうだんだねーと思いつつ。

どうもローカルで実行したときとデプロイしたときで動きが違うのかどうかわからないけど

entrypoint: 'java -cp "*"
のこの部分の✴︎でmainクラスがあるjarが読まれていない。そりゃそうだ、warはでpackageでつくっていたからなのだから

そういえばsampleみてもpom.xmlのpackageはjarだったかなーと思いつつ、jarで作成したらokだったが、引数にわたすwarは?

ならば、jarとwarを同時につくればいいんじゃないということで、調べたたら以下

[java - Maven - Generate Jar and War - Stack Overflow](https://stackoverflow.com/questions/10862980/maven-generate-jar-and-war)

これでjarとwarができたけど、もうひと手間

            <!-- [START make-a-jar_plugin] -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <executions>
                    <execution>
                        <id>make-a-jar</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                        <configuration>
                            <!-- need! -->
                            <outputDirectory>
                                ${project.build.directory}/appengine-staging
                            </outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- [END make-a-jar_plugin] -->
ローカルからデプロイするときにappengine-stagingからファイルをコピーしているようなので、作成したjarを入れておく必要があるぽっい。

ふーこれで一応うごいたよ。

java11




~/.appcfg_oauth2_tokens_java を消せば良い 2019/02/11

 GAEです。ひさびさにデプロイしようとていエラーになったので。
Either the access code is invalid or the OAuth token is revoked.Details: invalid_grant

環境はmac osxです。
下記のファイルを削除すればよろし

~/.appcfg_oauth2_tokens_java

lenb,midb? 2017/01/21
2021/03/14

javaです。
たとえばですが、最新じゃないoracle dbを使用していて、項目を、文字数でなくバイト数で定義してたりするとします。
文字コードは、Shift_JISとします。
そういう場合、アプリケーション側から、dbに登録する場合に、文字をバイト数で切って登録しないと、
桁数オーバーとなってしまいます。
なので、バイト数で切り出して登録するとします。

Shift_JISを以下、sjisといいます。

sjisは、1バイト文字、2バイト文字が混合です。
クリアしなければいけない課題があります。
2バイト固定であったりすればバイト数で切る場合は、2の倍数で切ればよいのですが、
素直にバイト数で切ると文字列の一番最後の文字の2バイト文字を半分で切ってしまうことになる場合があります。

実装方式その1
1文字づつ切り出して、sjis変換して、バイト数チェックしつながら、バイト数を加算していきます。
sjis変換は、javaのStringクラスのgetBytesを使います。
この実装方式はまちがいないです。メリットはコードがわかりやすいことです。デメリットは、文字数が多い場合、切り出しのバイト数が多い場合、1文字1文字の処理なのでそれなりのコストがかかること。


実装方式その2
1の方法ですと、文字列が多いと効率が悪くなので、少しだけ効率をよくしてみます。
ただし、実装が面倒となります。
はじめにバイト数を切り取り、最後の1バイトが2文字の片割れかどうか判定し、片割れだとそれ除く処理を行います。
コード表はこちらのサイトを参考にさせてもらっています。

Shift_JIS 文字コード表
キャプチャ(http://seiai.ed.jp/sys/text/java/shiftjis_table.html)
2バイトの上位




sjisの1バイト目と2バイト目なのかは、単純に区別できない場合があります。

例)キャプチャ(http://seiai.ed.jp/sys/text/java/shiftjis_table.html)


ですので、一度、切り出したバイト列を変換して、最後の文字が化けていないかチェックします。
化けていたら、その文字を除いて返却するという処理を行います。

実装方式その3

高速版です。なんとなく、できる方法あるなーとは気がついてはいたのですが、自力ではないですが、がんばってコードをシンプルにしました。
実は、発想は、実装方式その1と変わらないですが、javaのもっている文字コード処理を直接呼び出すイメージでしょうか。
使っているので重要なのは、CharsetEncoderです。Stringのbyte[] getBytes(String charsetName)で使われているのもこれですね。

参考
文字列を指定の文字エンコーディングでのバイト数で切る - kameidの備忘録 - Sharpen the Saw!

以下、ソースコード
package a;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;

public class TestMidb {

 public static void main(String[] args) throws UnsupportedEncodingException {
  a();
 }

 static void a() throws UnsupportedEncodingException {
  final String[] テスト文字列 = { "", "a", "aa", "aaaa", "aムム", "ムムa", "ムaa", "ムムムム", "ムムム", "ムム", "ム" };
  final int len = 3;
  for (String s : テスト文字列) {
   final String s01 = new String(midb01(s, len), "sjis");
   final String s02 = new String(midb02(s, len), "sjis");
   final String s03 = new String(midb03(s, len), "sjis");
   final boolean judge = s01.equals(s02) && s02.equals(s03);
   System.out.printf("%s [%s] [%s] [%s] %s %n", s, s01, s02, s03, judge);
  }
 }

 /**
  * 実装方式1
  * 
  * @param s
  * @param byteLen
  * @return
  */
 public static byte[] midb01(String s, int byteLen) {
  final String characterSet = "sjis";
  final ByteArrayOutputStream baos = new ByteArrayOutputStream();
  int size = 0;
  try {
   for (int i = 0; (i < s.length() && size < byteLen); i++) {

    final byte[] bs = s.substring(i, i + 1).getBytes(characterSet);
    final int blen = bs.length;
    if ((size + blen) > byteLen)
     break;
    baos.write(bs);
    size += bs.length;
   }
  } catch (UnsupportedEncodingException e) {
   throw new RuntimeException(e);
  } catch (IOException e) {
   throw new RuntimeException(e);
  }
  return baos.toByteArray();
 }

 /**
  * 実装方式2
  * 
  * @param s
  * @param byteLen
  * @return
  */
 public static byte[] midb02(String s, int byteLen) {
  final String charset = "sjis";

  try {
   final byte[] srcbs = s.getBytes(charset);

   if (srcbs.length <= byteLen) {
    return srcbs;
   }

   final byte[] bs = new byte[byteLen];
   System.arraycopy(srcbs, 0, bs, 0, byteLen);
   final int b = bs[byteLen - 1] & 0xff;

   // sjis 1バイト目の範囲か検査する
   if ((0x80 <= b && b < 0xA0) || (0xE0 <= b && b <= 0xFF)) {
    // 検査のため全体を文字列にする
    final String s2 = new String(bs, charset);
    // 最後の文字を取得
    final char ch = s2.charAt(s2.length() - 1);
    // 変換できていない文字か検査する
    if (Character.OTHER_SYMBOL == Character.getType(ch)) {
     // 1バイト少ないバイト配列を作成
     byte[] bs2 = new byte[byteLen - 1];
     System.arraycopy(bs, 0, bs2, 0, byteLen - 1);
     return bs2;
    }
   }

   return bs;
  } catch (UnsupportedEncodingException e) {
   throw new RuntimeException(e);
  }

 }

 /**
  * 実装方式3
  * @param s
  * @param byteLen
  * @return
  */
 public static byte[] midb03(String s, int byteLen) {
  final String charsetName = "sjis";
  final Charset charset = Charset.forName(charsetName);
  final byte[] bs = new byte[byteLen];
  final ByteBuffer outByteBuffer = ByteBuffer.wrap(bs);
  final char[] array = s.toCharArray();
  final CharBuffer inCharBuffer = CharBuffer.wrap(array);
  final CharsetEncoder charsetEncoder = charset.newEncoder();
  charsetEncoder.encode(inCharBuffer, outByteBuffer, true /* endOfInput */);
  // 余ったぶんは切り捨てる
  outByteBuffer.flip(); 
  // 切り捨てたあとのサイズで返却する
  final byte[] bs2 = new byte[outByteBuffer.limit()];
  outByteBuffer.get(bs2);
  return bs2;
 }
}


ThreadLocalか。 2017/01/10
2021/03/14

Javaです。ThreadLocalです。



package a;

public class TestThreadLocal {

 static class A {
  final ThreadLocal<String> value1 = new ThreadLocal<>();
  String value2;

  void setValue(String value) {
   this.value1.set(value);
   this.value2 = value;
  }

  void print(String marker) {
   System.out.printf("%s value1:%s value2:%s threadName:%s%n", marker, this.value1.get(), this.value2, Thread.currentThread().getName());
  }
 }

 public static void main(String[] args) throws InterruptedException {
  final A a = new A();
  a.print("a1==>");
  a.setValue("a");
  a.print("a2==>");
  new Thread(new Runnable() {
   @Override
   public void run() {
    a.print("b1==>");
    a.setValue("b");
    a.print("b2==>");
   }
  }).start();
  Thread.sleep(1);
  new Thread(new Runnable() {
   @Override
   public void run() {
    a.print("c1==>");
    a.setValue("c");
    a.print("c2==>");
   }
  }).start();
  Thread.sleep(1);
  a.print("a3==>");
 }

}

結果

Webとかで使う場合、スレッドが再利用されるので、しっかり後片付けしないとだめだよ。
参考

jsr-223 - 追記中 2017/01/09
2021/03/14

jsr-223です。


javaからJVM言語をスクリプト実行したいです。
主観ですが、メジャーな言語と思えるものを調べてみました。
かなりおおざっぱです。

対象
 clojure,groovy,scala,jruby,jython,kotlin, javascript


言語 engine name(shortName) Factoryクラス JAR 特記
Clojure Clojure clojure.contrib.jsr223.ClojureScriptEngineFactory clojure-jsr223-1.2.jar  
Groovy Groovy org.codehaus.groovy.jsr223.GroovyScriptEngineFactory groovy-jsr223-2.4.7.jar  
Scala scala scala.tools.nsc.interpreter.IMain$Factory scala-compiler-2.11.8.jar -Dscala.usejavacp=true
Kotlin kotlin org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory kotlin-jsr223-local-example-1.1-M04-eap-14.jar  
JRuby jruby org.jruby.embed.jsr223.JRubyEngineFactory jruby-complete-9.1.6.0.jar -Dpython.import.site=FALSE
Jython jython org.python.jsr223.PyScriptEngineFactory jython-2.7.0.jar  
javascript javascript com.sun.script.javascript.RhinoScriptEngineFactory#java7 resources.jar java8はNashorn


jsr-223って、もともとサーバーサイドで各種スクリプト言語の実行を目指したもののようですね。

こうやってみてみるとJVM言語っていろいろありますね。かなり貪欲というか。

呼び出し方は、ScriptEngineManagerにたいして、エンジン名を指定して、ScriptEngineを取得します。取得できない場合は、nullが返ってくるようです。

ちなみに、各ScriptEngineFactoryはプログラムの起動時に行われるようです。ScriptEngineFactoryの定義は、各ライブラリ(jar)のMETA-INF/services/javax.script.ScriptEngineFactory ファイルに記述されています。
ですので、このファイルを探せばよいというのがわかります。ただし、このファイルに記述されているのに実際のクラスがない場合、不幸なことにプログラム全体が起動しません。
# 遅延ロードでできないのかしら?

参考 clojure


以下、呼び出しソース

package jsr223; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class TestMain { public static void main(String[] args) throws ScriptException { a(); } static void a() throws ScriptException { // まとめて実行するとjava.lang.OutOfMemoryErrorする.... jsr223_noengine(); jsr223_Clojure(); jsr223_Groovy(); jsr223_Scala(); jsr223_JRuby(); jsr223_Jython(); jsr223_Javascript(); jsr223_Kotlin(); } static void jsr223_noengine() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "xxxx";// 存在しないものを指定 final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); if (scriptEngine == null) { System.out.println("*** 存在しないものを指定した場合は、script engineはnullになります。"); } else { scriptEngine.eval(""); } } static void jsr223_Clojure() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "Clojure"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("(println \"clojure \")"); } static void jsr223_Groovy() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "Groovy"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("println \"groovy \""); } static void jsr223_Scala() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "scala"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("println(\"scala \")"); } static void jsr223_JRuby() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "jruby"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("printf \"jruby \n\""); } static void jsr223_Jython() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "jython"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("print 'jython'"); } static void jsr223_Javascript() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "javascript"; // java7 Rhino java8 Nashorn final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("print('javascript')"); } static void jsr223_Kotlin() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "kotlin"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("println(\"Kotlin\")"); } }


 参考

不幸は忘れたころにやってくる - OutOfMemoryError 2016/12/29


この一年、レガシーな環境の開発に参加させてもらっています。
java1.4で、各種ライブラリは、2006年、ほっとだったspring,hibernateのバージョンそのままです。

それで不幸は忘れた頃にやってくるわけですが、OutOfMemoryErrorがぽこぽこ発生。

結論からいいますと、java1.4と使用していたcommons-fileuploadの組み合わせが原因。

こちらのブログの内容が、まさにヒットでした。

File.deleteOnExit() を使用していたライブラリ - HHeLiBeXの日記 正道編

java1.4のdeleteOnExitは、メモリーリークというか、使ったらシステムが落ちるまで掴みぱなしでCヒープが消費されていきます。

javaヒープは十分にあるようにみえました。gcも動いてるし、なのにALLOCATION FAILUREがおきて、コアをはいてずどーんと落ちます。

javaヒープ、CヒープとOutOfMemoryErrorについての説明は、下記の記事がよかったです。こういう記事はずーと残って欲しいな。
2010年の記事です。

現場にキく、Webシステムの問題解決ノウハウ(4):調査の難しい「OutOfMemoryError」事例、5選 - @IT
Native Methodの呼び出しでのOutOfMemoryErrorですね。はい。

いろいろ不運な要素が重なりました。

WEBのアプリケーションは1日一度再起動されるので、これが数千件程度の呼び出しであれば、問題は発覚しなかったのでしょう。

わかったのは、strutsとこのバージョンのcommons-fileuploadですと、画面のformの項目数分、File.deleteOnExit()が呼ばれるのでした。
そして、画面の項目数が100以上あり、submitするたびにFile.deleteOnExit()が呼ばれます。

それで、上のブログの記事を参考に、fileuploadのバージョンを1.1にあげました。ただし、このバージョンのfileuploadは、commons-ioを必要とします。

依存ライブラリがひとつ増えてしまう。。。

commons-fileupload – Home
Commons IO – Commons IO Overview
いまの時代、1.4に対応したものってold versionの深い闇にしかないんですよね。
そして上記のブログには続きがあるようで、Commons IOにも何かしら問題が潜んでいるようでして。。。
Webアプリケーション開発の際の注意事項(3) - HHeLiBeXの日記 正道編

この問題まだ続くのかな(笑)

さて、何年も、メモしてきたこのブログですが、今年は2回しか、書けていなかったです。いろいろ知見を得ることができた1年だったのですが、メモしなかったのは反省です。来年(2017年)こそは。。。。

uberjarでjava sourceをコンパイルして含める 2015/11/07

uberjarでjava sourceをコンパイルして含めるです。

悩みました。

参考
Leiningen で Clojure と Java の混在プロジェクト - tnoda-clojure

project.cljに

:java-source-paths ["src"]
を含めるでした。


組み合わせふたたび 2015/08/29

Javaです。また組み合わせです。

[java]組み合わせ | プログラマメモ2

昔、やったけど、よくわからないコードですね。。。

また組み合わせです。
再帰でぐるぐるです。
みなさんどうやってるんですかね。。

結果
aaa    111    xxx    aaaa    555   
aaa    111    xxx    aaaa    666   
aaa    111    xxx    bbbb    555   
aaa    111    xxx    bbbb    666   
aaa    111    yyy    aaaa    555   
aaa    111    yyy    aaaa    666   
aaa    111    yyy    bbbb    555   
aaa    111    yyy    bbbb    666   
aaa    222    xxx    aaaa    555   
aaa    222    xxx    aaaa    666   
aaa    222    xxx    bbbb    555   
aaa    222    xxx    bbbb    666   
aaa    222    yyy    aaaa    555   
aaa    222    yyy    aaaa    666   
aaa    222    yyy    bbbb    555   
aaa    222    yyy    bbbb    666   
bbb    111    xxx    aaaa    555   
bbb    111    xxx    aaaa    666   
bbb    111    xxx    bbbb    555   
bbb    111    xxx    bbbb    666   
bbb    111    yyy    aaaa    555   
bbb    111    yyy    aaaa    666   
bbb    111    yyy    bbbb    555   
bbb    111    yyy    bbbb    666   
bbb    222    xxx    aaaa    555   
bbb    222    xxx    aaaa    666   
bbb    222    xxx    bbbb    555   
bbb    222    xxx    bbbb    666   
bbb    222    yyy    aaaa    555   
bbb    222    yyy    aaaa    666   
bbb    222    yyy    bbbb    555   
bbb    222    yyy    bbbb    666   




public class Test組み合わせ01 { public static void main(String[] args) { a(); } static void a(){ String[][] sss = {{"aaa", "bbb"},{"111","222" },{"xxx", "yyy"}, {"aaaa", "bbbb"}, {"555", "666"}}; StringBuilder builder = new StringBuilder(); out(builder, sss, new String[sss.length], 0); System.out.println(builder); } static void out(StringBuilder builder, String[][] sss, String[] holder, int pos){ if (sss.length - 1< pos) { print(builder, holder); return; } String[] ss = sss[pos]; for (String s : ss) { holder[pos] = s; out(builder, sss, holder, pos + 1); } } static void print(StringBuilder builder, String...ss){ for (String s : ss) { builder.append(s).append("\t"); } builder.append("\n"); } }

http://localhost:8888/book/12347という感じのURLでjsonを返したい - Jodd,Madvoc 2015/07/20
2021/03/14


joddです。
ぼくにはむずかしいです。。。(悲哀)
Madvocってなんて読むんですかね?まっどぼっくとか。

軽量な、マイクロフレームワークとかよばれているジャンルだそうです。
が、ぼくにはむずかしいです。

で、アクションの意味が皆目わからず、つぎにRestでなやみ。

とはいいつつも、ドキュメントが読みやすいですね


やりたいことは

http://localhost:8888/book/12347

という感じのURLでjsonを返したいわけです。

jsonとかだと、使う側でいろいろ用意しないといけないようですが(とはいってもたいした労力ではないです)

とりあえず用意したもの

JsonData、JsonResult、Book、BookActionのクラス
package helpers; import jodd.json.JsonSerializer; import jodd.madvoc.meta.RenderWith; @RenderWith(JsonResult.class) public class JsonData { private final JsonSerializer jsonSerializer; private final Object target; public JsonData(Object target) { this.target = target; jsonSerializer = new JsonSerializer(); } public JsonData include(String... includes) { jsonSerializer.include(includes); return this; } public JsonData exclude(String... excludes) { jsonSerializer.exclude(excludes); return this; } public String toJsonString() { return jsonSerializer.serialize(target); } }

package helpers; import java.io.PrintWriter; import javax.servlet.http.HttpServletResponse; import jodd.io.StreamUtil; import jodd.madvoc.ActionRequest; import jodd.madvoc.result.BaseActionResult; import jodd.util.MimeTypes; public class JsonResult extends BaseActionResult<Object> { @Override public void render( ActionRequest request, Object target) throws Exception { // write output HttpServletResponse response = request.getHttpServletResponse(); response.setContentType(MimeTypes.MIME_TEXT_PLAIN); PrintWriter writer = null; try { writer = response.getWriter(); JsonData jsonData = new JsonData(target); writer.println(jsonData.toJsonString()); } finally { StreamUtil.close(writer); } } }

package aaa; public class Book { String name; String id; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } }

package jodd.example; import aaa.Book; import helpers.JsonResult; import jodd.madvoc.meta.InOut; import jodd.madvoc.meta.MadvocAction; import jodd.madvoc.meta.RestAction; @MadvocAction public class BookAction { @InOut String id; @RestAction(value="${id}", result = JsonResult.class) public Book get() { final Book foo = new Book(); foo.setId(""+id+"b"); return foo; } }

jspのコンパイル アンサポート52.0 2015/07/18


google app engineです。


上記の記事とまったく同じで、はじめなぜJSPだけなのかでかなり悩みました。

現時点でのgoogle app engineでつかえるjavaのバージョンは1.7です。
やっかいなのは、jspのコンパイルはどうもeclipseを起動した際のjavaのバージョンによってしまうことのようです。
※指定できる方法があるのではと思ってるのですが....


参考

しかたがないので、eclipse起動で使用するjavaのバージョンをjdk1.7を指すように変更しました。
僕が使っているのは、eclipse Version: Mars Release (4.5.0)

インストールした1.7は、jdk1.7.0_80

ちなみにosx上でのjavaの場所は、
/Library/Java/JavaVirtualMachines

eclipse.iniを書き直すって面倒。

この問題はけっこう面倒ですね。

[java]順列 お手軽 2015/05/10

Javaです。
順列です。
組み合わせの列挙なのですが、
書けといわれてすぐ書けなくて。。。。
>_<!

困ったときのapacheさんです。

Math - Commons Math: The Apache Commons Mathematics Library
Collections - Home

Mathにあるんだろなーと思って探したんですが、どうもランダムに生成するのはあったのですが、たんに組みわせを全部とりだいたいという ニーズにあわなくて、するとCollectionsのほうにいい感じのものがありました。
ちなみに、最新のMathとコレクションの現時点でのバージョンは、
                 [org.apache.commons/commons-math3 "3.5"]
                 [org.apache.commons/commons-collections4 "4.0"]
 です。


PermutationIteratorはcommons-collections4からあります。
※使うのは、PermutationIteratorですよ!!

出力結果
[0, 1, 2, 3]
[0, 1, 3, 2]
[0, 3, 1, 2]
[3, 0, 1, 2]
[3, 0, 2, 1]
[0, 3, 2, 1]
[0, 2, 3, 1]
[0, 2, 1, 3]
[2, 0, 1, 3]
[2, 0, 3, 1]
[2, 3, 0, 1]
[3, 2, 0, 1]
[3, 2, 1, 0]
[2, 3, 1, 0]
[2, 1, 3, 0]
[2, 1, 0, 3]
[1, 2, 0, 3]
[1, 2, 3, 0]
[1, 3, 2, 0]
[3, 1, 2, 0]
[3, 1, 0, 2]
[1, 3, 0, 2]
[1, 0, 3, 2]
[1, 0, 2, 3]

以下コード

List<Integer> list = Arrays.asList(new Integer[]{0,1,2,3}); PermutationIterator<Integer> iterator = new PermutationIterator<>(list); while(iterator.hasNext()) { System.out.println(iterator.next()); }



[javaFX]TreeViewの練習 2015/05/03

javaFXです。TreeViewの練習

Using JavaFX UI Controls: Tree View | JavaFX 2 Tutorials and Documentation
上記のリンクまんまだけど
とりあえずコントローラとして実装

package zzz.main; import java.net.URL; import java.util.ResourceBundle; import javafx.event.Event; import javafx.event.EventHandler; import javafx.fxml.Initializable; import javafx.scene.control.ContextMenu; import javafx.scene.control.MenuItem; import javafx.scene.control.TextField; import javafx.scene.control.TreeCell; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeView; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.input.MouseEvent; import javafx.util.Callback; public class Controller implements Initializable { public TreeView<String> treeView; @Override public void initialize(URL arg0, ResourceBundle arg1) { { TreeItem<String> rootItem = new TreeItem<String>("Inbox", null); rootItem.setExpanded(true); for (int i = 1; i < 6; i++) { TreeItem<String> item = new TreeItem<String>("Message" + i); rootItem.getChildren().add(item); } this.treeView.setRoot(rootItem); this.treeView.setEditable(true); this.treeView .setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() { @Override public TreeCell<String> call(TreeView<String> p) { return new TextFieldTreeCellImpl(); } }); } } private final class TextFieldTreeCellImpl extends TreeCell<String> { private TextField textField; private ContextMenu addMenu = new ContextMenu(); @SuppressWarnings("unchecked") public TextFieldTreeCellImpl() { MenuItem addMenuItem = new MenuItem("Add Employee"); addMenu.getItems().add(addMenuItem); addMenuItem.setOnAction(new EventHandler() { public void handle(Event t) { TreeItem<String> newEmployee = new TreeItem<>( "New Employee"); getTreeItem().getChildren().add(newEmployee); } }); setOnDragDetected(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent mouseEvent) { } }); } @Override public void startEdit() { super.startEdit(); if (textField == null) { createTextField(); } setText(null); setGraphic(textField); textField.selectAll(); } @Override public void cancelEdit() { super.cancelEdit(); setText((String) getItem()); setGraphic(getTreeItem().getGraphic()); } @Override public void updateItem(String item, boolean empty) { super.updateItem(item, empty); if (empty) { setText(null); setGraphic(null); } else { if (isEditing()) { if (textField != null) { textField.setText(getString()); } setText(null); setGraphic(textField); } else { setText(getString()); setGraphic(getTreeItem().getGraphic()); if (getTreeItem().getParent() != null) { setContextMenu(addMenu); } } } } private void createTextField() { textField = new TextField(getString()); textField.setOnKeyReleased(new EventHandler<KeyEvent>() { @Override public void handle(KeyEvent t) { if (t.getCode() == KeyCode.ENTER) { commitEdit(textField.getText()); } else if (t.getCode() == KeyCode.ESCAPE) { cancelEdit(); } } }); } private String getString() { return getItem() == null ? "" : getItem().toString(); } } }

[javaFx]アプリケーションを作成して、コントローラを用意する手順をいつも忘れるのでメモ 2015/04/05

javafxです。
アプリケーションを作成して、コントローラを用意する手順をいつも忘れるのでメモ。

僕の場合、fxmlは、SceneBuilderで作って、そのファイルをIDEから自分で読み込ませて動かしています。

SceneBuilderで、コントローラを設定します。
 ここでは、mainパッケージのControllerクラスです。

あとは、 Controllerクラスにjavafx.fxml.Initializableをインプリメントしてあげるだけで、fxmlがロードされれば自動で初期化してくれます。

 たいしてことではないですが、この辺の仕組みをすぐ忘れてしまう。

javaFxさくさく作れるから、はやって欲しいなー
まあ時代は、web(html5)ですかね。。。

以前は、swingをNetBeans使って組んでたのが、シーンビルダーだけで組んで、ファイルをeclipseに配置するという組方に変わりました。






マーキングファイルを探して2 2015/04/05
2021/04/17

javaです。

前回の
プログラマメモ2: マーキングファイルを探して

ちょっとだけ改造
 public static Optional<File> findMarkingFile(URL start, String name)
   throws URISyntaxException {

  File file = new File(start.toURI());

  Predicate<File> predicate = (File f) -> {
   return (f.getName().equals(name));
  };

  do {
   Optional<File> optional = Arrays.asList(file.listFiles()).stream()
     .filter(predicate).findFirst();
   if (optional.isPresent()) {
    return optional;
   }
   file = file.getParentFile();
  } while (file != null);

  return Optional.ofNullable(null);
 }