Indify String Concatenation

I am very interested about this http://openjdk.java.net/jeps/280. And I had a session about this which is presented by @ who is one of JDK comitter.

Due to my poor skill, I have no idea about below difference which is the result of java.
Anyway I have to learn more...

code

public class Sample{
    public static void main(String... args){
        Sample sample = new Sample();
        String a = "a";
        String b = "b";
        String ab = sample.m(a,b);
    }
    String m(String a, String b){
        return a + "(" + b + ")";
    }
}

javap

  • JDK8

f:id:tomoTaka:20161123094023p:plain

  • JDK9(Indify String Concatenation)

f:id:tomoTaka:20161123093900p:plain

Try to use Jigsaw(No2)

I just wanted to use Jigsaw by myself. So I found this articlehttp://openjdk.java.net/projects/jigsaw/quick-start and had the session about Jigsaw which is presented by @. The material is here

www.slideshare.net
I like this slide and I think this is worth to read.

code

  • src/org.astro/module-info.java
module org.astro {
    exports org.astro;
}
  • src/org.astro/org/astro/World.java
package org.astro;
public class World{
    public static String name() {
        return "world";
    }
}
  • src/com.greetings/module-info.java
module com.greetings {
    requires org.astro;
}
  • src/com.greetings/com/greetins/Main.java
package com.greetings;
import org.astro.World;
public class Main {
    public static void main(String... args) {
        System.out.println(String.format("Greeting %s", World.name()));
    }
}

compile

javac -p mods -d mods/org.astro src/org.astro/module-info.java src/org.astro/org/astro/World.java
javac -p mods -d mods/com.greetings src/com.greetings/module-info.java src/com.greetings/com/greetins/Main.java

Execute

java -p mods -m com.greetings/com.greetings.Main

result

f:id:tomoTaka:20161122231348p:plain

Directory

f:id:tomoTaka:20161122231501p:plain

packaging

 jar --create --file=mlib/org.astro@1.0.jar --module-version=1.0 -C mods/org.astro .
jar --create --file=mlib/com.greetings.jar --main-class=com.greetings.Main -C mods/com.greetings .

Execute

java -p mlib -m com.greetings

result

f:id:tomoTaka:20161123082548p:plain

new option of jar

f:id:tomoTaka:20161123083214p:plain

try to use Jigsaw

The original code is herehttp://openjdk.java.net/projects/jigsaw/quick-start
I just wanted to use Jigsaw.

Directory

f:id:tomoTaka:20161122223826p:plain

code

package com.greetings;
public class Main {
    public static void main(String... args) {
        System.out.println("Greetings!");
    }
}
module com.greetings {
}

compile

javac -p mods -d mods/com.greetings src/com.greetings/module-info.java src/com.greetings/com/greetins/Main.java

Execute

java -p mods -m com.greetings/com.greetings.Main

result

f:id:tomoTaka:20161122225134p:plain

how to cast long value to int

This is just memo about how to cast long value to int.
From JavaSE8 you can use Math.toIntExact to avoid overflows while you do not know.

Sample.java

public class Sample {
    public static void main(String... args) {
        Sample sample = new Sample();
        sample.cast();
        sample.intExact();
    }
    void cast() {
        System.out.println("----- cast -----");
        int i;
        long l = Long.MAX_VALUE;
        i = (int) l;
        System.out.println(String.format("i=%d", i));
        System.out.println(String.format("l=%d", l));
    }
    void intExact() {
        System.out.println("----- intExact -----");
        int i;
        long l = Long.MAX_VALUE;
        i = Math.toIntExact(l);   // <--- This method was added from JavaSE8
        System.out.println(String.format("i=%d", i));
        System.out.println(String.format("l=%d", l));
    }
}

The result

The following result shows the difference between cast and Math.toIntExact.
f:id:tomoTaka:20161016090854p:plain

Creating Directory by NIO2

creating directory

  1. create dir1
  2. create dir2/dir3 with permission("rwxrwxr-x")

As you can see the below result, the permission is set only to the dir3.
This is obvious, since Files.setPosixFilePermissions apply only to the path(dir3).
Anyway it is possible to set permission depending on the OS.
I find out this function when reading Java SE7/8 速攻入門, author is @, who is Java champion.

f:id:tomoTaka:20160915212426p:plain

package com.test;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.Set;

public class Test {
    public static void main(String[] args) throws Exception {
        Test test = new Test();
        test.createDir("/Users/tomo/dir1");
        test.createDir("/Users/tomo/dir2/dir3", "rwxrwxr-x");
    }
    private void createDir(String dirPath) throws Exception {
        Path path = Paths.get(dirPath);
        Files.createDirectories(path);
    }
    private void createDir(String dirPath, String permission) throws Exception {
        Path path = Paths.get(dirPath);
        Files.createDirectories(path);
        Set<PosixFilePermission> permissionSet = PosixFilePermissions.fromString(permission);
        Files.setPosixFilePermissions(path, permissionSet); // *** set permission
    }
}
Permission error

You can not set permission SUID, SGID and Sticky bit...
I just wanted to set it.

PosixFilePermissions.java

    public static Set<PosixFilePermission> fromString(String perms) {
        if (perms.length() != 9)
            throw new IllegalArgumentException("Invalid mode");
        Set<PosixFilePermission> result = EnumSet.noneOf(PosixFilePermission.class);
        if (isR(perms.charAt(0))) result.add(OWNER_READ);
        if (isW(perms.charAt(1))) result.add(OWNER_WRITE);
        if (isX(perms.charAt(2))) result.add(OWNER_EXECUTE);
        if (isR(perms.charAt(3))) result.add(GROUP_READ);
        if (isW(perms.charAt(4))) result.add(GROUP_WRITE);
        if (isX(perms.charAt(5))) result.add(GROUP_EXECUTE);
        if (isR(perms.charAt(6))) result.add(OTHERS_READ);
        if (isW(perms.charAt(7))) result.add(OTHERS_WRITE);
        if (isX(perms.charAt(8))) result.add(OTHERS_EXECUTE);
        return result;
    }

Java NIO2 UnmappableCharacterException

English follows Japanese.

  • 以下のようにファイルの出力をNIOからNIO2に書き換えた場合、出力時の値によっては動作が違ってきます。

「Pokémon」を文字コードsjisを指定してファイル出力する処理をNIOとNIO2で記述してみました。

  1. NIOの場合は、正常終了するのですが、出力したファイルは「Pock?mon」となっています。
  2. NIO2の場合は、UnmappableCharacterExceptionになります。

そもそも文字コードとして正しくない値を出力しているのが問題ではあるのですが、リファクタリングしたことで動作が違ってくるのは、、、

  • When you refactor codes from Java NIO to NIO2 like below, you will have different results.

I implemented the function which writes the value [Pokémon] to the file with sjis Charset.

  1. When using NIO the method ended without Exception, but the result is Pock?mon.
  2. When using NIO2 the method ended with UnmappableCharacterException.

Basically it is wrong using mismatched Charset, but I did not expect to see the different result... :-(

package com.sample;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Sample {
    public static void main(String... args) throws IOException {
        Sample sample = new Sample();
        sample.writeNIO();
        sample.writeNIO2();
    }

    void writeNIO() {
        String val = "Pockémon";
        try (BufferedWriter writer = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream("/Users/tomo/NIO.txt"), Charset.forName("sjis")))) {
            writer.write(val);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    void writeNIO2() throws IOException {
        String val = "Pockémon";
        Path path = Paths.get("/Users", "tomo", "NIO2.txt");
        try (BufferedWriter writer = Files.newBufferedWriter(path, Charset.forName("sjis"));) {
            writer.write(val);
        }
    }
}
package com.sample;

import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.nio.charset.UnmappableCharacterException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.junit.Before;
import org.junit.Test;
public class SampleTest {
    Sample sample;

    @Before
    public void setUp() throws Exception {
        sample = new Sample();
    }
    @Test
    public void testWriteNIO() {
        sample.writeNIO();
        Path path = Paths.get("/Users", "tomo", "NIO.txt");
        boolean exists = Files.exists(path);
        assertTrue(exists);
    }

    @Test(expected = UnmappableCharacterException.class)
    public void testWriteNIO2() throws IOException {
        sample.writeNIO2();
    }

}

f:id:tomoTaka:20160730164258p:plain
The code is here gist.github.com

Mail template sample

@さんのセッションでThymeleaf3からtextでも使用できることを学んだので、ちょっと試してみました。

Sample.java
package com.sample;

import java.io.IOException;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Locale;
import java.util.stream.Collectors;

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templateresolver.FileTemplateResolver;

public class Sample {
    public static void main(String... args) {
        Sample sample = new Sample();
        sample.createMail(Locale.JAPAN);
        sample.createMail(Locale.US);
    }

    private void createMail(Locale locale) {
        Locale.setDefault(locale);
        Context context = new Context();
        context.setVariable("mailTo", "Hanako"); // <- mail.template ${mailTo}
        List<String> bodies = Arrays.asList("body1", "body2", "body3");
        context.setVariable("bodies", bodies); <- set bodies as ArrayList
        FileTemplateResolver resolver = new FileTemplateResolver();
        resolver.setPrefix("resources/");
        resolver.setTemplateMode(TemplateMode.TEXT); <- *** set mode
        TemplateEngine engine = new TemplateEngine();
        engine.addTemplateResolver(resolver);
        Path path = Paths.get(String.format("mail_%s.txt", locale.getLanguage()));
        try (Writer writer = Files.newBufferedWriter(path);) {
            engine.process("mail.template", context, writer);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
mail.template

${mailTo}と${body}の部分は、変数になるので上記のcontextでkey,valueで設定
#{greeting}は、propertyファイルより設定されるので、上記のLocaleに依存して、日本語の場合は「mail_ja_jp.properties」英語の場合は英語用を作成していないのでデフォルトの「mail.properties」を使用
基本的にtemplateと同じ名前にしておくとデフォルトで使用できます。

To:[[${mailTo}]]

[[#{greeting}]]

[# th:each="body : ${bodies}"]
[[${body}]]
[/]

from [[${#locale.country}]]
mail_ja_jp.properties
greeting=こんにちは
mail.properties
greeting=Hello
実行後のmail
  • mail_ja.txt
To:Hanako

こんにちは

body1
body2
body3

from JP
  • mail_en.txt
To:Hanako

Hello

body1
body2
body3

from US
build.gradle
apply plugin:'java'

sourceSets {
    main {
        resources {
            srcDir 'resources'
        }
    }
}

repositories {
    mavenCentral()
}
sourceCompatibility=1.8
targetCompatibility=1.8

jar {
    manifest {
        attributes 'Main-class': 'com.sample.Sample'
    }
}
dependencies {
    compile 'org.thymeleaf:thymeleaf:3.0.0.RELEASE'
}
  • 可変の内容について

上記のbodyの部分は、改行コードを使って複数行の実装していますが、th:eachとかを使いたかったのですが、実装方法が?です(汗)
もしよければコメントお願いします!
早速@さんからコメント頂いて訂正しました。ありがとうございます!
以下のサイトも参考にしました。
Thymeleaf 3 ten-minute migration guide - Thymeleaf

以下にアップしてます。
github.com