ログ出力付きの例外処理を備えた EncodingUtils クラス（gzip対応)


## ✅ `EncodingUtils.java`（`@Component` 付き）

```java
package your.package.utils;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class EncodingUtils {

    private static final Logger logger = LoggerFactory.getLogger(EncodingUtils.class);

    public String bytesToString(byte[] bytes, Charset charset) {
        if (bytes == null) return null;
        return new String(bytes, charset);
    }

    public byte[] stringToBytes(String str, Charset charset) {
        if (str == null) return null;
        return str.getBytes(charset);
    }

    public String autoDecode(byte[] data, Charset charset) {
        if (data == null) return null;

        if (isGzipped(data)) {
            return decompress(data, charset);
        } else {
            return bytesToString(data, charset);
        }
    }

    public boolean isGzipped(byte[] data) {
        if (data == null || data.length < 2) return false;
        return (data[0] == (byte) 0x1f && data[1] == (byte) 0x8b);
    }

    public String decompress(byte[] gzippedData, Charset charset) {
        if (gzippedData == null || gzippedData.length == 0) return null;

        try (GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(gzippedData));
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {

            byte[] buffer = new byte[4096];
            int len;
            while ((len = gis.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            return baos.toString(charset.name());

        } catch (IOException e) {
            logger.warn("GZIP 解凍に失敗しました", e);
            return null;
        }
    }

    public byte[] compress(String str, Charset charset) {
        if (str == null) return null;

        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             GZIPOutputStream gos = new GZIPOutputStream(baos)) {

            gos.write(str.getBytes(charset));
            gos.finish();
            return baos.toByteArray();

        } catch (IOException e) {
            logger.warn("GZIP 圧縮に失敗しました", e);
            return null;
        }
    }
}
```

---

## ✅ 使用例（Spring 管理クラスから）

```java
@Service
@RequiredArgsConstructor
public class SampleService {

    private final EncodingUtils encodingUtils;

    public void handleResponse(byte[] response) {
        String decoded = encodingUtils.autoDecode(response, StandardCharsets.UTF_8);
        // 使う処理...
    }
}
```

または手動注入：

```java
@Autowired
private EncodingUtils encodingUtils;
```

---

## ✅ Bean 化するメリット

| 利点    | 説明                                        |
| ----- | ----------------------------------------- |
| 再利用性  | 各所で DI によって使い回せる                          |
| テスト容易 | モック化やスタブ化が可能                              |
| 設定注入  | 必要があれば、`@Value` や `Environment` 経由で設定も持てる |
| AOP対応 | 後でロギングやメトリクスを入れるのが楽                       |

---

## 🔚 まとめ

このように `@Component` 化すれば、DI で使えるようになり、他のサービスクラスからも共通的に安全に gzip 圧縮・解凍や文字列⇄バイト変換を呼び出せます。
必要であれば Singleton utility にもできますし、`@Configuration`＋`@Bean` にする選択肢もあります（設定注入したいときに便利）。

---

### 使用例1

gzip圧縮
gzipをStringに変換

```java
EncodingUtils encodingUtils = new EncodingUtils();
String original = "これはGZIP圧縮のテストです。";
byte[] compressed = encodingUtils.compress(original, Charset.forName("UTF-8"));
String decompressed = encodingUtils.autoDecode(compressed, Charset.forName("UTF-8"));

System.out.println("元データ: " + original);
System.out.println(compressed);
System.out.println("復元データ: " + decompressed);
```

```sh
元データ: これはGZIP圧縮のテストです。
[B@562cad08
復元データ: これはGZIP圧縮のテストです。
```

### 使用例2

Stringをbyte配列に変換
byte配列をStringに変換


```java
encodingUtils = new EncodingUtils();
String original = "これはGZIP圧縮のテストです。";
byte[] compressed = encodingUtils.stringToBytes(original, Charset.forName("UTF-8"));
String decompressed = encodingUtils.autoDecode(compressed, Charset.forName("UTF-8"));

System.out.println("元データ: " + original);
System.out.println(compressed);
System.out.println("復元データ: " + decompressed);
```

```sh
元データ: これはGZIP圧縮のテストです。
[B@562cad08
復元データ: これはGZIP圧縮のテストです。
```
### 使用例3

byte配列をStringに変換
再圧縮（gzip）

```java
// byte配列をStringに変換
String body = encodingUtils.bytesToString(byte配列の変数, Charset.forName("UTF-8"));

// 再圧縮（gzip）
byte[] gzipped = encodingUtils.compress(body, Charset.forName("UTF-8"));

// レスポンス構築（Content-Encoding: gzip を明示）
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add(HttpHeaders.CONTENT_ENCODING, "gzip");
headers.setContentLength(gzipped.length);

return new ResponseEntity<>(gzipped, headers, HttpStatus.OK);
```