public static byte[] unhex(final byte[] bytes) {
        final byte[] out = new byte[(bytes.length + 1) >> 1];

        int i = bytes.length - 2;
        int j = out.length - 1;
        while (i >= 0) {
            int l = Character.digit(bytes[i], 16);
            int r = Character.digit(bytes[i + 1], 16);
            if (l == -1 || r == -1) {
                return null;
            }
            i -= 2;
            out[j--] = (byte) (((l << 4) | r) & 0xFF);
        }

        // length is odd and first byte is invalid
        if (i == -1 && Character.digit(bytes[0], 16) == -1) {
            return null;
        }

        return out;
    }
@Test
    void testUnhex() {
        assertThat(EncodingUtils.unhex("".getBytes())).isEqualTo(new byte[0]);
        assertThat(EncodingUtils.unhex("1".getBytes())).isEqualTo(new byte[] {0});
        assertThat(EncodingUtils.unhex("146".getBytes())).isEqualTo(new byte[] {0, 0x46});
        assertThat(EncodingUtils.unhex("z".getBytes())).isEqualTo(null);
        assertThat(EncodingUtils.unhex("1-".getBytes())).isEqualTo(null);
        assertThat(EncodingUtils.unhex("466C696E6B".getBytes()))
                .isEqualTo(new byte[] {0x46, 0x6c, 0x69, 0x6E, 0x6B});
        assertThat(EncodingUtils.unhex("4D7953514C".getBytes()))
                .isEqualTo(new byte[] {0x4D, 0x79, 0x53, 0x51, 0x4C});
        assertThat(EncodingUtils.unhex("\uD83D\uDE00".getBytes())).isEqualTo(null);
        assertThat(EncodingUtils.unhex(EncodingUtils.hex("\uD83D\uDE00").getBytes()))
                .isEqualTo("\uD83D\uDE00".getBytes());
    }