Вы пропускаете, чтобы присвоить значение для чтения к экземпляру конфигурации. Java не может ничего поддерживать, как this = gson.fromJson(...)
и Gson может возвращать только новых значения и не может исправить существующие. ниже - это своего рода взлом Gson, и, пожалуйста, используйте его, только если это действительно должно быть. Опять же, я настоятельно рекомендую вам переконфигурировать ваш код и разделить ваши объекты конфигурации и устройства чтения/чтения конфигурации - это всего лишь два разные вещи, которые противоречат техническим аспектам. В результате рефакторинга вы могли бы, скажем так, получить экземпляр своей конфигурации, просто передайте его автору, чтобы он оставался в другом месте. Если вам это нужно b извед, то просто получить экземпляр читателя прочитать значение конфигурации и присвоить его конфигурации (конфигурации одиночек, я помню), как:
final ConfigurationWriter writer = getConfigurationWriter();
writer.write(ExampleConfig.get());
...
final ConfigurationReader reader = getConfigurationReader();
ExampleConfig.set(reader.read(ExampleConfig.class));
По крайней мере, этот код не смешивает две разные вещи, и делает результат reader.read
явно прочитал и присвоен вашей конфигурации singleton.
Если вы хорошо, чтобы открыть ворота зла и сделать код работу из-за взломов, то вы можете использовать Gson TypeAdapterFactory
для того, чтобы обмануть Gson и залатать текущий экземпляр конфигурации.
abstract class Configuration {
private static final Gson saveGson = new Gson();
public final void load()
throws IOException {
try (final FileReader reader = new FileReader(getTargetName())) {
// You have to instantiate Gson every time (unless you use caching strategies) in order to let it be *specifically* be aware of the current
// Configuration instance class. Thus you cannot make it a static field.
final Gson loadGson = new GsonBuilder()
.registerTypeAdapterFactory(new TypeAdapterFactory() {
// A Gson way to denote a type since Configuration.class may not be enough and it also works with generics
private final TypeToken<Configuration> configurationTypeToken = new TypeToken<Configuration>() {
};
@Override
@SuppressWarnings("deprecation") // isAssignableFrom is deprecated
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
// Checking if the type token represents a parent class for the given configuration
// If yes, then we cheat...
if (configurationTypeToken.isAssignableFrom(typeToken)) {
// The map that's artificially bound as great cheating to a current configuration instance
final Map<Type, InstanceCreator<?>> instanceCreators = bindInstance(typeToken.getType(), Configuration.this);
// A factory used by Gson internally, we're intruding into its heart
final ConstructorConstructor constructorConstructor = new ConstructorConstructor(instanceCreators);
final TypeAdapterFactory delegatedTypeAdapterFactory = new ReflectiveTypeAdapterFactory(
constructorConstructor,
gson.fieldNamingStrategy(),
gson.excluder(),
new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor)
);
// Since the only thing necessary here is to define how to instantiate an object
// (and we just give it an already-existing instance)
// ... just delegate the job to Gson -- it would think as if it's creating a new instance.
// Actually it won't create one, but would "patch" the current instance
return delegatedTypeAdapterFactory.create(gson, typeToken);
}
// Otherwise returning a null means looking up for an existing type adapter from how Gson is configured
return null;
}
})
.create();
// The value is still loaded to nowhere, however.
// The type adapter factory is tightly bound to an existing configuration instance via ConstructorConstructor
// This is actually another code smell...
loadGson.fromJson(reader, getClass());
}
}
public final void save()
throws IOException {
try (final FileWriter writer = new FileWriter(getTargetName())) {
saveGson.toJson(this, writer);
}
}
private String getTargetName() {
return getClass().getSimpleName() + ".json";
}
private static Map<Type, InstanceCreator<?>> bindInstance(final Type type, final Configuration existingConfiguration) {
return singletonMap(type, new InstanceCreator<Object>() {
@Override
public Object createInstance(final Type t) {
return t.equals(type) ? existingConfiguration : null; // don't know if null is allowed here though
}
});
}
}
Надеюсь, что комментарии в приведенном выше коде являются исчерпывающими. Как я сказал выше, я сомневаюсь, что вам это нужно просто из-за намерения иметь более приятный код. Вы можете утверждать, что java.util.Properties
может загружать и сохранять себя. Да, это правда, но java.util.Properties
открыт для перебора своих свойств по дизайну и всегда может читать и писать свойства из любого места в любом месте. Gson использует отражение, способ подглядывать поля под капотом, и это потрясающе для хорошо продуманных объектов. Вам нужно некоторое рефакторинг и отдельные два понятия: данные и запись/чтение данных.
'gson.fromJson (reader, this.getClass());' - здесь теряется ваше значение. Метод 'fromJson' возвращает значение _new_, которое вы должны назначить где-нибудь. –
Имеет смысл, как бы я это сделал с моим текущим примером? –