Java のバイト配列を16進数表記の文字列に変換する

## 方法

JAXB の javax.xml.bind.DatatypeConverter クラスを利用する。

[DatatypeConverter \(Java Platform SE 8 \)](https://docs.oracle.com/javase/jp/8/docs/api/javax/xml/bind/DatatypeConverter.html#printHexBinary-byte:A-)

> public static String printHexBinary(byte[] val)
> バイト配列を文字列に変換します。

## JAXB は Java 11 から Java SE 標準ライブラリに入っていない

JAXB は Java SE 6 以降の標準ライブラリに入っていた。

[JAXB Release Documentation - Frequently Asked Questions](https://javaee.github.io/jaxb-v2/doc/user-guide/ch06.html)

> Q: Which version of J2SE does JAXB 2.0 require?
> A: Java SE 6 or higher.

JAXB は Java SE 11 以降の標準ライブラリからは削除されている。

[Java Platform, Standard Edition Oracle JDK 移行ガイド,リリース11](https://docs.oracle.com/javase/jp/11/migrate/)

> JDK 11では、Java EEおよびCORBAモジュールが削除されました。これらのモジュールはJDK 9で削除予定の非推奨となりました。

## サンプルコード

### ソースコード一覧

環境は Java 11 + Gradle 6.1 を想定。

```
├── build.gradle
└── src
    └── main
        └── java
            └── HexString.java
```

### build.gradle

JAXB を使うため dependencies に javax.xml.bind:jaxb-api:2.3.1 を追加している。

```build.gradle
plugins {
  id 'java'
  id 'application'
}

repositories {
  mavenCentral()
}

dependencies {
  // https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api
  implementation 'javax.xml.bind:jaxb-api:2.3.1'
}

application {
  mainClassName = 'HexString'
}
```

### src/main/java/HexString.java

ランダム生成した byte の配列を DatatypeConverter クラスで16進数表記の文字列に変換するサンプルコード。

```java
import java.security.SecureRandom;
import javax.xml.bind.DatatypeConverter;

public class HexString {

  public static void main(String[] args) {
    int num = 0;
    if (args.length > 0) {
      num = Integer.parseInt(args[0]);
    }
    var r = random(num);
    System.out.println("文字列: " + r);
    System.out.println("文字数: " + r.length());
    System.out.println("16進数字表記チェック: " + r.matches("\\p{XDigit}+")); // 正規表現でチェック
  }

  /**
   * ランダムな16進数表記の文字列を返します。
   * @param num 生成する文字数
   * @return ランダムな16進数表記文字列
   */
  public static String random(int num) {
    var random = new SecureRandom();
    byte[] bytes = new byte[num / 2];
    random.nextBytes(bytes);
    return DatatypeConverter.printHexBinary(bytes);
  }
}
```

## 実行例

Java 11 (AdoptOpenJDK) + Gradle 6.1 で実行。

```
$ gradle run --args=32

> Task :run
文字列: A01CCE3E4133D822CCBCA8247353C48F
文字数: 32
16進数字表記チェック: true

BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
```

## DatatypeConverter.printHexBinary の中身

実際の処理は DatatypeConverterImpl クラスの printHexBinary メソッドが担っている。

[Maven Repository: javax\.xml\.bind » jaxb\-api » 2\.3\.1](https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api/2.3.1) からダウンロードできる jaxb-api-2.3.1-sources.jar ファイルの中を見ると、 javax/xml/bind/DatatypeConverterImpl.java というファイルがある。

printHexBinary メソッドが byte 配列を16進数表記の文字列に変換している。

```java
private static final char[] hexCode = "0123456789ABCDEF".toCharArray();

public String printHexBinary(byte[] data) {
    StringBuilder r = new StringBuilder(data.length * 2);
    for (byte b : data) {
        r.append(hexCode[(b >> 4) & 0xF]);
        r.append(hexCode[(b & 0xF)]);
    }
    return r.toString();
}
```

## 参考資料

- [javax\.xml\.bind \(Java Platform SE 8 \)](https://docs.oracle.com/javase/jp/8/docs/api/javax/xml/bind/package-summary.html)
- [Maven Repository: javax\.xml\.bind » jaxb\-api » 2\.3\.1](https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api/2.3.1)
- [SecureRandom \(Java SE 11 & JDK 11 \)](https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/security/SecureRandom.html)
- [Pattern \(Java SE 11 & JDK 11 \)](https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/regex/Pattern.html)