Default Methods of Java 8 and an impact on javac


I have an interesting experience with Java 8.

public class ZonedDateTimeToInstant {
    public static void main(final String[] args) throws NoSuchMethodException {
	assert ChronoZonedDateTime.class.isAssignableFrom(ZonedDateTime.class);
        final Method toInstant = ChronoZonedDateTime.class.getMethod("toInstant");
	final ZonedDateTime now = ZonedDateTime.now();
	final Instant instant = now.toInstant();
	System.out.println(instant);
    }
}

When I tried to compile it with -source 1.7, javac complained me that she doesn’t understand the method toInstant which is clearly defined in ChronoZonedDateTime class that ZonedDateTime class implemented.

$ javac ZonedDateTimeToInstant.java
$ java ZonedDateTimeToInstant
2014-04-01T12:01:13.934Z
$ 
$ javac -source 1.7 ZonedDateTimeToInstant.java
warning: [options] bootstrap class path not set in conjunction with -source 1.7
ZonedDateTimeToInstant.java:10: error: cannot find symbol
	final Instant instant = now.toInstant();
	                           ^
  symbol:   method toInstant()
  location: variable now of type ZonedDateTime
1 error
1 warning
$ javac -version
javac 1.8.0
$ 

javac is quickly suspected of having a bug.

$ cat Java8.java
public class Java8 {
    public void print(java.io.PrintStream out) {
        out.printf("hello world\n");
    }
}
$ javac Java8.java
$
$ cat Java7.java
public class Java7 {
    public static void main(final String[] args) {
        new Java8().print(System.out);
    }
}
$ javac -source 1.7 Java7.java
warning: [options] bootstrap class path not set in conjunction with -source 1.7
1 warning
$ 
$ java Java7
hello world

No. Nothing’s wrong with javac. After spending some stackoverflowing, I answered that the javac is actually complaining about the source code, which is being compiled with -source 1.7, is using a Default Method defined in an interface.

$ cat Java8i.java
public interface Java8i {
    default void print(java.io.PrintStream out) {
        out.printf("hello world\n");
    }
}
$ javac Java8i.java
$ 
$ cat Java8c.java
public class Java8c implements Java8i {
}
$ javac Java8c.java
$ 
$ cat Java7i.java
public class Java7i {
    public static void main(final String[] args) {
        new Java8c().print(System.out);
    }
}
$ javac -source 1.7 Java7i.java
warning: [options] bootstrap class path not set in conjunction with -source 1.7
Java7i.java:3: error: cannot find symbol
	new Java8c().print(System.out);
	            ^
  symbol:   method print(PrintStream)
  location: class Java8c
1 error
1 warning
$ 

I think javac should’ve told me more helpfully.

jpa-metamodel-with-maven


Sourcecode

svn co http://jinahya.googlecode.com/svn/trunk\
/com.googlecode.jinahya.test/jpa-metamodel-with-maven

Hibernate

With direct dependencies

<dependencies>
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-jpamodelgen</artifactId>
    <scope>compile</scope>
    <optional>true</optional>
  </dependency>
</dependencies>

Using maven-processor-plugin

<build>
  <plugins>
    <plugin>
      <groupId>org.bsc.maven</groupId>
      <artifactId>maven-processor-plugin</artifactId>
      <executions>
        <execution>
          <id>process</id>
          <goals>
            <goal>process</goal>
          </goals>
          <phase>generate-sources</phase>
          <configuration>
            <processors>
               <processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
            </processors>
          </configuration>
        </execution>
      </executions>
      <dependencies>
        <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-jpamodelgen</artifactId>
          <version>${hibernate.version}</version>
        </dependency>
      </dependencies>
    </plugin>
  </plugins>
</build>

Apache OpenJPA

With direct dependencies

It seems that Apache OpenJPA must be triggered with a specific compiler argument.

<dependencies>
  <dependency>
    <groupId>org.apache.openjpa</groupId>
    <artifactId>openjpa</artifactId>
    <scope>compile</scope>
    <optional>true</optional>
  </dependency>
</dependencies>
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <configuration>
        <compilerArgs>
          <arg>-Aopenjpa.metamodel=true</arg>
        </compilerArgs>
      </configuration>
    </plugin>
  </plugins>
</build>

Using maven-processor-plugin

Again, Apache OpenJPA requires some additional configuration.

<build>
  <plugins>
    <plugin>
      <groupId>org.bsc.maven</groupId>
      <artifactId>maven-processor-plugin</artifactId>
      <executions>
        <execution>
          <id>process</id>
          <goals>
            <goal>process</goal>
          </goals>
          <phase>generate-sources</phase>
          <configuration>
            <processors>
              <processor>org.apache.openjpa.persistence.meta.AnnotationProcessor6</processor>
            </processors>
            <optionMap>
              <openjpa.metamodel>true</openjpa.metamodel>
            </optionMap>
          </configuration>
        </execution>
      </executions>
      <dependencies>
        <dependency>
          <groupId>org.apache.openjpa</groupId>
          <artifactId>openjpa</artifactId>
          <version>${openjpa.version}</version>
        </dependency>
      </dependencies>
    </plugin>
  </plugins>
</build>

EclipseLink

For EclipseLink, the location of persistence.xml must be specified.

Using direct dependencies

<dependencies>
  <dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
    <scope>compile</scope>
    <optional>true</optional>
  </dependency>
</dependencies>
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <configuration>
        <compilerArgs>
          <arg>-Aeclipselink.persistencexml=src/main/resources/META-INF/persistence.xml</arg>
        </compilerArgs>
      </configuration>
    </plugin>
  </plugins>
</build>

Using maven-processor-plugin

<build>
  <plugins>
    <plugin>
      <groupId>org.bsc.maven</groupId>
      <artifactId>maven-processor-plugin</artifactId>
      <executions>
        <execution>
          <id>process</id>
          <goals>
            <goal>process</goal>
          </goals>
          <phase>generate-sources</phase>
          <configuration>
            <processors>
              <processor>org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProcessor</processor>
            </processors>
            <compilerArguments>-Aeclipselink.persistencexml=src/main/resources/META-INF/persistence.xml</compilerArguments>
          </configuration>
        </execution>
      </executions>
      <dependencies>
        <dependency>
          <groupId>org.eclipse.persistence</groupId>
          <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
          <version>${eclipselink.version}</version>
        </dependency>
      </dependencies>
    </plugin>
  </plugins>
</build>

DataNucleus

Using direct dependencies

When working with DataNucleus, and additional dependency needs to be specified.

<dependencies>
  <dependency>
    <groupId>org.datanucleus</groupId>
    <artifactId>datanucleus-jpa-query</artifactId>
    <scope>compile</scope>
    <optional>true</optional>
  </dependency>
  <dependency>
    <groupId>org.datanucleus</groupId>
    <artifactId>datanucleus-core</artifactId>
    <version>${datanucleus.version}</version>
    <scope>compile</scope>
    <optional>true</optional>
  </dependency>
</dependencies>

Using maven-processor-plugin

<build>
  <plugins>
    <plugin>
      <groupId>org.bsc.maven</groupId>
      <artifactId>maven-processor-plugin</artifactId>
      <executions>
        <execution>
          <id>process</id>
          <goals>
            <goal>process</goal>
          </goals>
          <phase>generate-sources</phase>
          <configuration>
            <processors>
              <processor>org.datanucleus.jpa.query.JPACriteriaProcessor</processor>
            </processors>
          </configuration>
        </execution>
      </executions>
      <dependencies>
        <dependency>
          <groupId>org.datanucleus</groupId>
          <artifactId>datanucleus-jpa-query</artifactId>
          <version>${datanucleus.version}</version>
        </dependency>
        <dependency>
          <groupId>org.datanucleus</groupId>
          <artifactId>datanucleus-core</artifactId>
          <version>${datanucleus.version}</version>
        </dependency>
      </dependencies>
    </plugin>
  </plugins>
</build>

Internationalized Domain Name with Java


public static void main(final String[] args) throws Exception {
    final String unicode = "청와대";
    final String ascii = IDN.toASCII(unicode);
    final URI uri = new URI("http://www." + ascii + ".com");
    System.out.println("uri: " + uri);
    Desktop.getDesktop().browse(uri);
}
uri: http://www.xn--vk1b187a8ue.com

Fibonacci Numbers in Java


I’ve believed in myself that I could easily implement the Fibonacci number and I found I’ve been wrong so long.

Fibonacci number

What an easy formula here we can see.

f(0) = 0
f(1) = 1
f(n) = f(n-2) + f(n-1)
----------------------------------------
n:    0 1 2 3 4 5 6  7  8  9 ...
f(n): 0 1 1 2 3 5 8 13 21 34 ...

f0(n)

I instantly typed as it defined.

public static long f0(final int n) {

    if (n < 0) {
        throw new IllegalArgumentException("n(" + n + ") < 0");
    }

    switch (n) {
        case 0:
            return 0L;
        case 1:
            return 1L;
        default:
            return f0(n - 2) + f0(n - 1);
    }
}

Piece of cake, huh? I honestly thought that I didn’t even need to run it.

private static void m0(final String[] args) {

    final int m = 50;
    for (int n = 0; n < m; n++) {
        System.out.printf("f(%1$d) = %2$d\n", n, f0(n));
    }
}

You know what? I couldn’t help but pressing CTRL-C even before the console prints f(40)=....

f1(n)

So, we can store previous results in an array, right?

private static long f1(final int n, final Long[] s) {

    if (n < 0) {
        throw new IllegalArgumentException("n(" + n + ") < 0");
    }

    if (s == null) {
        throw new NullPointerException("null s");
    }

    if (n >= s.length) {
        throw new IllegalArgumentException(
            "n(" + n + ") >= s.length(" + s.length + ")");
    }

    switch (n) {
        case 0:
            if (s[0] == null) {
                s[0] = 0L;
            }
            return s[0];
        case 1:
            if (s[1] == null) {
                s[1] = 1L;
            }
            return s[1];
        default:
            if (s[n] == null) {
                s[n] = f1(n - 2, s) + f1(n - 1, s);
            }
            return s[n];
    }
}

Seems nice, doesn’t it?

private static void m1(final String[] args) {

    final int m = 100;
    final Long[] s = new Long[m];
    for (int n = 0; n < m; n++) {
        System.out.printf("f(%1$d) = %2$d\n", n, f1(n, s));
    }
}
f(0) = 0
f(1) = 1
f(2) = 1
f(3) = 2
f(4) = 3
f(5) = 5
f(6) = 8
...
f(92) = 7540113804746346429
f(93) = -6246583658587674878
f(94) = 1293530146158671551
f(95) = -4953053512429003327
f(96) = -3659523366270331776
f(97) = -8612576878699335103
f(98) = 6174643828739884737
f(99) = -2437933049959450366

What’w going on here? The 93rd result is definitely bigger than the maximum value of long type.

f2(n)

It is high time to put BigInteger in action.

public static BigInteger f2(final int n, final BigInteger[] s) {

    if (n < 0) {
        throw new IllegalArgumentException("n(" + n + ") < 0");
    }

    if (s == null) {
        throw new NullPointerException("null s");
    }

    if (n >= s.length) {
        throw new IllegalArgumentException(
            "n(" + n + ") >= s.length(" + s.length + ")");
    }

    switch (n) {
        case 0:
            if (s[0] == null) {
                s[0] = BigInteger.ZERO;
            }
            return s[0];
        case 1:
            if (s[1] == null) {
                s[1] = BigInteger.ONE;
            }
            return s[1];
        default:
            if (s[n] == null) {
                s[n] = f2(n - 2, s).add(f2(n - 1, s));
            }
            return s[n];
    }
}

f3(n)

Wait, do we really have to store all previous results? Can’t we use Tail call?

private static BigInteger f3(final int n, final BigInteger fn_1,
                             final BigInteger fn_2) {

    if (n < 0) {
        throw new IllegalArgumentException("n(" + n + ") < 0");
    }

    if (fn_1 == null) {
        throw new NullPointerException("null fn_1");
    }

    if (fn_2 == null) {
        throw new NullPointerException("null fn_2");
    }

    if (n == 0) {
        return fn_2;
    }

    return f3(n - 1, fn_1.add(fn_2), fn_1);
}


public static BigInteger f3(final int n) {

    return f3(n, BigInteger.ONE, BigInteger.ZERO);
}

Is this really a tail recursion? See following links.

f4(n)

Note that, for given n, we actually need two previous results, f(n-2) and f(n-1).

public static BigInteger f4(final int n) {

    if (n < 0) {
        throw new IllegalArgumentException("n(" + n + ") < 0");
    }

    final BigInteger[] s = new BigInteger[2];
    s[0] = BigInteger.ONE;
    s[1] = BigInteger.ZERO;

    for (int i = 2; i < n; i++) {
        final BigInteger f = s[0].add(s[1]);
        s[1] = s[0];
        s[0] = f;
    }

    return s[0].add(s[1]);
}

Here comes f(10000).

3364476487643178326662161200510754331030214846068006390656476997468008
1442166662368155595513633734025582065332680836159373734790483865268263
0408924630564318873545443695598274916066020998841839338646527313000888
3026923567361313511757929743785441375213052050434770160226475831890652
7890855154366159582987279682987510631200575428783453215515103870818298
9697916131278562650331954871402142875326981879620469360978799003509623
0229102636813149319527563022783762844154036058440257211433496118002309
1208287046088923962328835461505776583271252546093591128203925285393434
6209042452489294039017062338889910858410651831733604374707379085526317
6432573399371287193758774689747992630583706574283016163740896917842637
8624212835258112820516370298089332099905707920064367426202389783111470
0540749984592503606335609338838319233867830561364353518921332797329081
3373264265263398976392272340788292817795358057099369104917547080893184
1056146322338217465637321248226383092103297701648054726243842374862411
4530938122065649140327510866433945175121615265453613331113140424368548
0510676584349352383695965342807176877532834823434555736671973139274627
3629108210679280784718035329131176778924659089938635459327894523777674
4061922403376386740040213303432974969020283281459334188268176838930720
0363479562311710310129195316979460763273758925353077255237594378843450
4067715555779056450443016640119462580972216729758615026968443146952034
6149322911059706762432685159928347098912847067408620085871350162603120
7190317208609408129832158107728207635318662461127824553720853236530577
5956430072517744315051539600905168603220349163222640885248852433158051
5348496224348482993809050704834824493274537326245677558790891871908036
6205800959474315005240253270974699531877072437682590741993963226598414
7498193609285223945039707165443156421328157688908058783183404917434556
2705202235648464951961124602683139709750693826487066132645076650746115
1267752274862159864253071129844118262266105716351506926002986170494542
5047491378115154139941550671256271197133252763631939606902895650288268
608362241082050562430701794976171121233066073310059947366875

Further read

FileChannel#size()


I recently wrote a method which uses FileChannel#size() internally.

public static void doSomethingLikeABoss(final FileChannel channel)
    throws IOException {

    final long size = channel.size();
    // TODO: find the reason why the size is always 0L.
}

And I found that the size() always returns 0L. The problem was the way I creating FileChannel instances with a given File. I used FileInputStream#getChannel() which seems lost information about the file.

public static void doSomethingLikeABoss(final File file)
    throws IOException {

    // open channels like a boss!
    try (final FileChannel channel = new FileInputStream(file).getChannel()) {
        doSomethingLikeABoss(channel);
    }
}

I had to use the new method introduced with Java 1.7 .

public static void doSomethingLikeABoss(final File file)
    throws IOException {

    // open channels like a REAL boss!
    try (final FileChannel channel = FileChannel.open(file.toPath())) {
        doSomethingLikeABoss(channel);
    }
}