diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/AccelerationMode.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/AccelerationMode.java index 836d32eab..bc0035a99 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/AccelerationMode.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/AccelerationMode.java @@ -1,11 +1,24 @@ package jp.hiroshiba.voicevoxcore; /** ハードウェアアクセラレーションモード。 */ -public enum AccelerationMode { +public class AccelerationMode { /** 実行環境に合わせて自動的に選択する。 */ - AUTO, + public static final AccelerationMode AUTO = new AccelerationMode("AUTO"); + /** CPUに設定する。 */ - CPU, + public static final AccelerationMode CPU = new AccelerationMode("CPU"); + /** GPUに設定する。 */ - GPU, + public static final AccelerationMode GPU = new AccelerationMode("GPU"); + + private final String identifier; + + private AccelerationMode(String identifier) { + this.identifier = identifier; + } + + @Override + public String toString() { + return identifier; + } } diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/StyleType.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/StyleType.java index e0eb699fb..b70bf0e82 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/StyleType.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/StyleType.java @@ -1,27 +1,67 @@ package jp.hiroshiba.voicevoxcore; -import com.google.gson.annotations.Expose; -import com.google.gson.annotations.SerializedName; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; /** スタイル(style)に対応するモデルの種類。 */ -public enum StyleType { +public class StyleType { /** 音声合成クエリの作成と音声合成が可能。 */ - @SerializedName("talk") - @Expose - TALK, + public static final StyleType TALK = new StyleType("talk"); /** 歌唱音声合成用のクエリの作成が可能。 */ - @SerializedName("singing_teacher") - @Expose - SINGING_TEACHER, + public static final StyleType SINGING_TEACHER = new StyleType("singing_teacher"); /** 歌唱音声合成が可能。 */ - @SerializedName("frame_decode") - @Expose - FRAME_DECODE, + public static final StyleType FRAME_DECODE = new StyleType("frame_decode"); /** 歌唱音声合成用のクエリの作成と歌唱音声合成が可能。 */ - @SerializedName("sing") - @Expose - SING, + public static final StyleType SING = new StyleType("sing"); + + public static final class Serializer implements JsonSerializer { + @Override + public JsonElement serialize(StyleType src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src.toString()); + } + } + + public static final class Deserializer implements JsonDeserializer { + @Override + public StyleType deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + String value = json.getAsString(); + switch (value) { + case "talk": + return TALK; + case "singing_teacher": + return SINGING_TEACHER; + case "frame_decode": + return FRAME_DECODE; + case "sing": + return SING; + default: + throw new JsonParseException( + String.format( + "Invalid variant: `%s`, expected one of " + + "`talk`, `singing_teacher`, `frame_decode`, `sing`", + value)); + } + } + } + + private final String identifier; + + private StyleType(String identifier) { + this.identifier = identifier; + } + + @Override + public String toString() { + return identifier; + } } diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/UserDictWord.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/UserDictWord.java index 8b1e93457..f5ccfd3de 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/UserDictWord.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/UserDictWord.java @@ -1,5 +1,12 @@ package jp.hiroshiba.voicevoxcore; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; import jakarta.annotation.Nonnull; @@ -114,30 +121,66 @@ public UserDictWord priority(int priority) { private static native void rsValidatePronunciation(String pronunciation); /** 単語の種類。 */ - public static enum Type { + public static class Type { /** 固有名詞。 */ - @SerializedName("PROPER_NOUN") - @Expose - PROPER_NOUN, + public static final Type PROPER_NOUN = new Type("PROPER_NOUN"); /** 一般名詞。 */ - @SerializedName("COMMON_NOUN") - @Expose - COMMON_NOUN, + public static final Type COMMON_NOUN = new Type("COMMON_NOUN"); /** 動詞。 */ - @SerializedName("VERB") - @Expose - VERB, + public static final Type VERB = new Type("VERB"); /** 形容詞。 */ - @SerializedName("ADJECTIVE") - @Expose - ADJECTIVE, + public static final Type ADJECTIVE = new Type("ADJECTIVE"); /** 語尾。 */ - @SerializedName("SUFFIX") - @Expose - SUFFIX, + public static final Type SUFFIX = new Type("SUFFIX"); + + public static final class Serializer implements JsonSerializer { + @Override + public JsonElement serialize( + Type src, java.lang.reflect.Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src.toString()); + } + } + + public static final class Deserializer implements JsonDeserializer { + @Override + public Type deserialize( + JsonElement json, java.lang.reflect.Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + String value = json.getAsString(); + switch (value) { + case "PROPER_NOUN": + return PROPER_NOUN; + case "COMMON_NOUN": + return COMMON_NOUN; + case "VERB": + return VERB; + case "ADJECTIVE": + return ADJECTIVE; + case "SUFFIX": + return SUFFIX; + default: + throw new JsonParseException( + String.format( + "Invalid variant `%s`, expected one of " + + "`PROPER_NOUN`, `COMMON_NOUN`, `VERB`, `ADJECTIVE`, `SUFFIX`", + value)); + } + } + } + + private final String identifier; + + private Type(String identifier) { + this.identifier = identifier; + } + + @Override + public String toString() { + return identifier; + } } } diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/blocking/Synthesizer.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/blocking/Synthesizer.java index 8f5e9f49c..9cd385b98 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/blocking/Synthesizer.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/blocking/Synthesizer.java @@ -1,6 +1,7 @@ package jp.hiroshiba.voicevoxcore.blocking; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import jakarta.annotation.Nonnull; import java.util.ArrayList; import java.util.Arrays; @@ -11,6 +12,7 @@ import jp.hiroshiba.voicevoxcore.AccentPhrase; import jp.hiroshiba.voicevoxcore.AudioQuery; import jp.hiroshiba.voicevoxcore.CharacterMeta; +import jp.hiroshiba.voicevoxcore.StyleType; import jp.hiroshiba.voicevoxcore.exceptions.InvalidModelDataException; import jp.hiroshiba.voicevoxcore.exceptions.RunModelException; import jp.hiroshiba.voicevoxcore.internal.Dll; @@ -64,7 +66,9 @@ public boolean isGpuMode() { */ @Nonnull public CharacterMeta[] metas() { - Gson gson = new Gson(); + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(StyleType.class, new StyleType.Deserializer()); + Gson gson = gsonBuilder.create(); String metasJson = rsGetMetasJson(); CharacterMeta[] rawMetas = gson.fromJson(metasJson, CharacterMeta[].class); if (rawMetas == null) { diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/blocking/UserDict.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/blocking/UserDict.java index e9819959a..1469a002e 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/blocking/UserDict.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/blocking/UserDict.java @@ -1,6 +1,7 @@ package jp.hiroshiba.voicevoxcore.blocking; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.google.gson.internal.LinkedTreeMap; import jakarta.annotation.Nonnull; import java.io.File; @@ -37,7 +38,9 @@ protected void finalize() throws Throwable { */ @Nonnull public String addWord(UserDictWord word) { - Gson gson = new Gson(); + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(UserDictWord.Type.class, new UserDictWord.Type.Serializer()); + Gson gson = gsonBuilder.create(); String wordJson = gson.toJson(word); return rsAddWord(wordJson); @@ -50,7 +53,9 @@ public String addWord(UserDictWord word) { * @param word 新しい単語のデータ。 */ public void updateWord(String uuid, UserDictWord word) { - Gson gson = new Gson(); + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(UserDictWord.Type.class, new UserDictWord.Type.Serializer()); + Gson gson = gsonBuilder.create(); String wordJson = gson.toJson(word); rsUpdateWord(uuid, wordJson); @@ -142,7 +147,9 @@ public void save(String path) throws SaveUserDictException { @Nonnull public HashMap toHashMap() { String json = rsGetWords(); - Gson gson = new Gson(); + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(UserDictWord.Type.class, new UserDictWord.Type.Deserializer()); + Gson gson = gsonBuilder.create(); @SuppressWarnings("unchecked") HashMap> rawWords = gson.fromJson(json, HashMap.class); if (rawWords == null) { diff --git a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/blocking/VoiceModelFile.java b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/blocking/VoiceModelFile.java index ebe6ac4ed..86e02425e 100644 --- a/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/blocking/VoiceModelFile.java +++ b/crates/voicevox_core_java_api/lib/src/main/java/jp/hiroshiba/voicevoxcore/blocking/VoiceModelFile.java @@ -1,10 +1,12 @@ package jp.hiroshiba.voicevoxcore.blocking; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import jakarta.annotation.Nonnull; import java.io.Closeable; import java.util.UUID; import jp.hiroshiba.voicevoxcore.CharacterMeta; +import jp.hiroshiba.voicevoxcore.StyleType; import jp.hiroshiba.voicevoxcore.internal.Dll; /** 音声モデルファイル。 */ @@ -33,7 +35,9 @@ public VoiceModelFile(String modelPath) { rsOpen(modelPath); id = rsGetId(); String metasJson = rsGetMetasJson(); - Gson gson = new Gson(); + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(StyleType.class, new StyleType.Deserializer()); + Gson gson = gsonBuilder.create(); CharacterMeta[] rawMetas = gson.fromJson(metasJson, CharacterMeta[].class); if (rawMetas == null) { throw new RuntimeException("Failed to parse metasJson"); diff --git a/crates/voicevox_core_java_api/src/common.rs b/crates/voicevox_core_java_api/src/common.rs index 22e10c2dc..65ce4ad3a 100644 --- a/crates/voicevox_core_java_api/src/common.rs +++ b/crates/voicevox_core_java_api/src/common.rs @@ -23,13 +23,13 @@ macro_rules! object_type { }; } #[macro_export] -macro_rules! enum_object { - ($env: ident, $name: literal, $variant: literal) => { - $env.get_static_field(object!($name), $variant, object_type!($name)) +macro_rules! static_field { + ($env: ident, $name: literal, $field: literal) => { + $env.get_static_field(object!($name), $field, object_type!($name)) .unwrap_or_else(|_| { panic!( "Failed to get field {}", - concat!($variant, "L", object!($name), ";") + concat!($field, "L", object!($name), ";") ) }) .l() diff --git a/crates/voicevox_core_java_api/src/synthesizer.rs b/crates/voicevox_core_java_api/src/synthesizer.rs index 2067d0c92..00318a3a2 100644 --- a/crates/voicevox_core_java_api/src/synthesizer.rs +++ b/crates/voicevox_core_java_api/src/synthesizer.rs @@ -1,6 +1,6 @@ use crate::{ common::{throw_if_err, JNIEnvExt as _, JavaApiError}, - enum_object, object, object_type, + object, object_type, static_field, }; use jni::{ @@ -31,9 +31,9 @@ unsafe extern "system" fn Java_jp_hiroshiba_voicevoxcore_blocking_Synthesizer_rs let acceleration_mode = if acceleration_mode.is_null() { Default::default() } else { - let auto = enum_object!(env, "AccelerationMode", "AUTO")?; - let cpu = enum_object!(env, "AccelerationMode", "CPU")?; - let gpu = enum_object!(env, "AccelerationMode", "GPU")?; + let auto = static_field!(env, "AccelerationMode", "AUTO")?; + let cpu = static_field!(env, "AccelerationMode", "CPU")?; + let gpu = static_field!(env, "AccelerationMode", "GPU")?; if env.is_same_object(&acceleration_mode, auto)? { voicevox_core::AccelerationMode::Auto } else if env.is_same_object(&acceleration_mode, cpu)? {