From e5afa918341bea046b59479f1d1269b8272e11bd Mon Sep 17 00:00:00 2001 From: Pyrofab Date: Sun, 14 Jun 2020 12:15:06 +0200 Subject: [PATCH 01/11] Bump version to 0.23.0 --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index e5452ff..cceb45b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ major = 0 -minor = 22 -patch = 1 \ No newline at end of file +minor = 23 +patch = 0 \ No newline at end of file From 7ea8e405e52abf9ce676a0827725022f591d3d03 Mon Sep 17 00:00:00 2001 From: Pyrofab Date: Sun, 14 Jun 2020 12:15:52 +0200 Subject: [PATCH 02/11] Bump version to 0.24.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index cceb45b..270db81 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ major = 0 -minor = 23 +minor = 24 patch = 0 \ No newline at end of file From 38e97fd71fddb17dc26d9501e32daf2a9825ba3d Mon Sep 17 00:00:00 2001 From: Ridan Vandenbergh Date: Mon, 6 Jul 2020 16:27:20 +0200 Subject: [PATCH 03/11] Added DeferredConfigLeaf --- .../fiber/annotation/BackedConfigLeaf.java | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java diff --git a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java new file mode 100644 index 0000000..e9b5232 --- /dev/null +++ b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java @@ -0,0 +1,161 @@ +package io.github.fablabsmc.fablabs.impl.fiber.annotation; + +import java.lang.reflect.Field; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiConsumer; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import io.github.fablabsmc.fablabs.api.fiber.v1.FiberId; +import io.github.fablabsmc.fablabs.api.fiber.v1.exception.IllegalTreeStateException; +import io.github.fablabsmc.fablabs.api.fiber.v1.exception.RuntimeFiberException; +import io.github.fablabsmc.fablabs.api.fiber.v1.schema.type.SerializableType; +import io.github.fablabsmc.fablabs.api.fiber.v1.schema.type.derived.ConfigType; +import io.github.fablabsmc.fablabs.api.fiber.v1.tree.ConfigAttribute; +import io.github.fablabsmc.fablabs.api.fiber.v1.tree.ConfigBranch; +import io.github.fablabsmc.fablabs.api.fiber.v1.tree.ConfigLeaf; + +/** + * A config leaf backed by a field, {@linkplain ConfigType}, and deferred leaf. + * + *

It is used to fetch the backing field's values on each {@link #getValue()} call, to make sure a leaf and its corresponding POJO field are always synchronised. + * + * @param + * @param + */ +public class BackedConfigLeaf implements ConfigLeaf { + final ConfigLeaf backing; + final ConfigType type; + final Object pojo; + final Field backingField; + private R cachedValue = null; + private ConfigBranch parent; + + public BackedConfigLeaf(ConfigLeaf backing, ConfigType type, Object pojo, Field backingField) { + this.backing = backing; + this.type = type; + this.pojo = pojo; + this.backingField = backingField; + } + + @Override + public String getName() { + return backing.getName(); + } + + @Override + public Map> getAttributes() { + return backing.getAttributes(); + } + + @Override + public Optional getAttributeValue(FiberId id, ConfigType type) { + return backing.getAttributeValue(id, type); + } + + @Override + public Optional getAttributeValue(FiberId id, SerializableType expectedType) { + return backing.getAttributeValue(id, expectedType); + } + + @Override + public ConfigAttribute getOrCreateAttribute(FiberId id, SerializableType attributeType, @Nullable A defaultValue) { + return backing.getOrCreateAttribute(id, attributeType, defaultValue); + } + + @Nullable + @Override + public ConfigBranch getParent() { + return parent; + } + + @Override + public void attachTo(ConfigBranch parent) throws IllegalTreeStateException { + // Attaching/detaching requires careful inspection of whether or not the parent's items contains `this`. + // In the case of deferred leaves, the leaf in the parent's items is the deferred leaf and not the backing leaf. + // Thus, we can't defer attaching/detaching to the backing leaf, as it will think it's not part of the parent's items. + if (this.parent != null && this.parent != parent) { + throw new IllegalTreeStateException(this + " needs to be detached before changing the parent"); + } + + // this node may have already been added by the collection + if (parent != null && !parent.getItems().contains(this)) { + parent.getItems().add(this); + } + + this.parent = parent; + } + + @Override + public void detach() { + // Note: infinite recursion between ConfigNode#detach() and NodeCollection#remove() could occur here, + // but the latter performs the actual collection removal before detaching + if (this.parent != null) { + // here, we also need to avoid triggering a ConcurrentModificationException + // thankfully, remove does not cause a CME if it's a no-op + this.parent.getItems().remove(this); + } + + this.parent = null; + } + + @Override + public boolean setValue(@Nonnull S value) { + return backing.setValue(value); + } + + @Nonnull + @Override + @SuppressWarnings("unchecked") + public S getValue() { + try { + backingField.setAccessible(true); + R fieldValue = (R) backingField.get(pojo); + + if (!Objects.equals(fieldValue, cachedValue)) { + this.setValue(type.toSerializedType(fieldValue)); + cachedValue = fieldValue; + } + } catch (IllegalAccessException e) { + // Because this exception might appear to happen 'at random' to the user, we wrap it to at least provide more information about what just happened + (new RuntimeFiberException("Couldn't fetch setting value from POJO", e)).printStackTrace(); + } + + return backing.getValue(); + } + + @Override + public SerializableType getConfigType() { + return backing.getConfigType(); + } + + @Nonnull + @Override + public BiConsumer getListener() { + return backing.getListener(); + } + + @Override + public void addChangeListener(BiConsumer listener) { + backing.addChangeListener(listener); + } + + @Nullable + @Override + public S getDefaultValue() { + return backing.getDefaultValue(); + } + + @Override + public String getComment() { + return backing.getComment(); + } + + @Override + public boolean accepts(@Nonnull S rawValue) { + return backing.accepts(rawValue); + } +} From 44b70c9212671ab3c1037d4726ea78ea31d2f268 Mon Sep 17 00:00:00 2001 From: Ridan Vandenbergh Date: Mon, 6 Jul 2020 16:29:28 +0200 Subject: [PATCH 04/11] Replace built leaves with a BackedConfigLeaf while constructing config from POJO Also removed an outdated comment in ConfigLeafBuilder: the backing collection should always be a NodeCollection, which we assume to be safe. --- .../api/fiber/v1/builder/ConfigLeafBuilder.java | 3 --- .../impl/fiber/annotation/AnnotatedSettingsImpl.java | 11 ++++++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/github/fablabsmc/fablabs/api/fiber/v1/builder/ConfigLeafBuilder.java b/src/main/java/io/github/fablabsmc/fablabs/api/fiber/v1/builder/ConfigLeafBuilder.java index 027065e..30735db 100644 --- a/src/main/java/io/github/fablabsmc/fablabs/api/fiber/v1/builder/ConfigLeafBuilder.java +++ b/src/main/java/io/github/fablabsmc/fablabs/api/fiber/v1/builder/ConfigLeafBuilder.java @@ -189,9 +189,6 @@ public ConfigLeaf build() { built.getAttributes().putAll(this.attributes); if (parent != null) { - // We don't know what kind of evil collection we're about to add a node to. - // Though, we don't really want to throw an exception on this method because no developer likes try-catching every setting they build. - // Let's tread with caution. try { parent.getItems().add(built); } catch (RuntimeFiberException e) { diff --git a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java index 0206986..5a2bbc9 100644 --- a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java +++ b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java @@ -46,6 +46,7 @@ import io.github.fablabsmc.fablabs.api.fiber.v1.schema.type.derived.ConfigType; import io.github.fablabsmc.fablabs.api.fiber.v1.schema.type.derived.ConfigTypes; import io.github.fablabsmc.fablabs.api.fiber.v1.tree.ConfigBranch; +import io.github.fablabsmc.fablabs.api.fiber.v1.tree.ConfigLeaf; import io.github.fablabsmc.fablabs.api.fiber.v1.tree.ConfigTree; import io.github.fablabsmc.fablabs.impl.fiber.annotation.magic.TypeMagic; @@ -157,12 +158,16 @@ public void processSetting(Object pojo, Field setting) throws ProcessingMemberEx private void processSetting(Object pojo, Field setting, ConfigType type) throws FiberException { String name = this.findName(setting); List listeners = this.listenerMap.getOrDefault(name, Collections.emptyList()); - ConfigLeafBuilder leaf = this.builder + ConfigLeafBuilder leafBuilder = this.builder .beginValue(name, type, this.findDefaultValue(pojo, setting)) .withComment(this.findComment(setting)) .withListener(this.constructListener(pojo, setting, listeners, type)); - this.applyAnnotationProcessors(pojo, setting, leaf, AnnotatedSettingsImpl.this.valueSettingProcessors); - leaf.build(); + this.applyAnnotationProcessors(pojo, setting, leafBuilder, AnnotatedSettingsImpl.this.valueSettingProcessors); + ConfigLeaf leaf = leafBuilder.build(); + leaf.detach(); + builder.getItems().remove(leaf); + BackedConfigLeaf deferred = new BackedConfigLeaf<>(leaf, type, pojo, setting); + builder.getItems().add(deferred); // This will also attach deferred } @Nonnull From 09d0b5cab852f45215b405ded69992e30720ca8b Mon Sep 17 00:00:00 2001 From: Ridan Vandenbergh Date: Mon, 6 Jul 2020 16:33:37 +0200 Subject: [PATCH 05/11] Add test for picking up on direct POJO mutations --- .../fiber/v1/annotation/AnnotatedSettingsTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/test/java/io/github/fablabsmc/fablabs/api/fiber/v1/annotation/AnnotatedSettingsTest.java b/src/test/java/io/github/fablabsmc/fablabs/api/fiber/v1/annotation/AnnotatedSettingsTest.java index b28bead..9bd23b0 100644 --- a/src/test/java/io/github/fablabsmc/fablabs/api/fiber/v1/annotation/AnnotatedSettingsTest.java +++ b/src/test/java/io/github/fablabsmc/fablabs/api/fiber/v1/annotation/AnnotatedSettingsTest.java @@ -281,6 +281,16 @@ void testSuperPojo() { assertEquals(2, this.node.getItems().size(), "Node has two items"); } + @Test + @DisplayName("Directly mutated POJO") + void lateChangePojo() throws FiberException { + LateChangePojo pojo = new LateChangePojo(); + this.annotatedSettings.applyToNode(this.node, pojo); + ConfigLeaf a = this.node.lookupLeaf("a", ConfigTypes.INTEGER.getSerializedType()); + pojo.a = 10; + assertEquals(10, a.getValue().intValue()); + } + private static class FinalSettingPojo { private final int a = 5; } @@ -422,4 +432,8 @@ private static class SuperPojo { private static class ExtendingPojo extends SuperPojo { private int b = 5; } + + private static class LateChangePojo { + private int a = 5; + } } From e39d7950b6b0c36237d0e8d15596d6ed019ddd11 Mon Sep 17 00:00:00 2001 From: Ridan Vandenbergh Date: Mon, 6 Jul 2020 17:11:04 +0200 Subject: [PATCH 06/11] Throw exception instead of just printing its trace --- .../fablabs/impl/fiber/annotation/BackedConfigLeaf.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java index e9b5232..7f85d52 100644 --- a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java +++ b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java @@ -121,7 +121,7 @@ public S getValue() { } } catch (IllegalAccessException e) { // Because this exception might appear to happen 'at random' to the user, we wrap it to at least provide more information about what just happened - (new RuntimeFiberException("Couldn't fetch setting value from POJO", e)).printStackTrace(); + throw new RuntimeFiberException("Couldn't fetch setting value from POJO", e); } return backing.getValue(); From 2b5fe8c26f214d6d701171dc1f38647c8fd69297 Mon Sep 17 00:00:00 2001 From: Ridan Vandenbergh Date: Mon, 6 Jul 2020 17:30:36 +0200 Subject: [PATCH 07/11] Move hacky listener to BackedConfigLeaf --- .../annotation/AnnotatedSettingsImpl.java | 26 +++++++++++-------- .../fiber/annotation/BackedConfigLeaf.java | 16 ++++++++++-- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java index 5a2bbc9..44a50cc 100644 --- a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java +++ b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java @@ -161,7 +161,7 @@ private void processSetting(Object pojo, Field setting, ConfigType leafBuilder = this.builder .beginValue(name, type, this.findDefaultValue(pojo, setting)) .withComment(this.findComment(setting)) - .withListener(this.constructListener(pojo, setting, listeners, type)); + .withListener(this.constructListener(pojo, listeners, type)); this.applyAnnotationProcessors(pojo, setting, leafBuilder, AnnotatedSettingsImpl.this.valueSettingProcessors); ConfigLeaf leaf = leafBuilder.build(); leaf.detach(); @@ -185,19 +185,23 @@ private String findComment(Field field) { } @Nonnull - private BiConsumer constructListener(Object pojo, Field setting, List listeners, ConfigType type) throws FiberException { - BiConsumer ret = (t, newValue) -> { - try { - setting.setAccessible(true); - setting.set(pojo, newValue); - } catch (IllegalAccessException e) { - throw new RuntimeFiberException("Failed to update field value", e); - } - }; + private BiConsumer constructListener(Object pojo, List listeners, ConfigType type) throws FiberException { + BiConsumer ret = null; for (Member listener : listeners) { BiConsumer consumer = this.constructListenerFromMember(pojo, listener, type.getRuntimeType()); - if (consumer != null) ret = ret.andThen(consumer); + + if (consumer != null) { + if (ret == null) { + ret = consumer; + } else { + ret = ret.andThen(consumer); + } + } + } + + if (ret == null) { + ret = (r, r2) -> { }; } return ret; diff --git a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java index 7f85d52..41151dc 100644 --- a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java +++ b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java @@ -104,7 +104,19 @@ public void detach() { @Override public boolean setValue(@Nonnull S value) { - return backing.setValue(value); + if (this.backing.setValue(value)) { + try { + this.backingField.setAccessible(true); + value = backing.getValue(); // Might've changed after a type check + correction, so we fetch again + this.backingField.set(pojo, type.toRuntimeType(value)); + } catch (IllegalAccessException e) { + throw new RuntimeFiberException("Failed to update field value", e); + } + + return true; + } + + return false; } @Nonnull @@ -116,7 +128,7 @@ public S getValue() { R fieldValue = (R) backingField.get(pojo); if (!Objects.equals(fieldValue, cachedValue)) { - this.setValue(type.toSerializedType(fieldValue)); + this.backing.setValue(type.toSerializedType(fieldValue)); cachedValue = fieldValue; } } catch (IllegalAccessException e) { From 0c8cdeaf176cca1e0c1a6c13c349d7a094b8ba0e Mon Sep 17 00:00:00 2001 From: Ridan Vandenbergh Date: Fri, 10 Jul 2020 17:57:04 +0200 Subject: [PATCH 08/11] Make fields in BackedConfigLeaf private --- .../fablabs/impl/fiber/annotation/BackedConfigLeaf.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java index 41151dc..bf5c41d 100644 --- a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java +++ b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java @@ -27,10 +27,10 @@ * @param */ public class BackedConfigLeaf implements ConfigLeaf { - final ConfigLeaf backing; - final ConfigType type; - final Object pojo; - final Field backingField; + private final ConfigLeaf backing; + private final ConfigType type; + private final Object pojo; + private final Field backingField; private R cachedValue = null; private ConfigBranch parent; From e8eda28b3534857646f794e98180e351e61e9eb5 Mon Sep 17 00:00:00 2001 From: Ridan Vandenbergh Date: Fri, 10 Jul 2020 18:02:10 +0200 Subject: [PATCH 09/11] No longer excessively call setAccessible --- .../fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java | 4 +--- .../fablabs/impl/fiber/annotation/BackedConfigLeaf.java | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java index 44a50cc..701d535 100644 --- a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java +++ b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java @@ -158,6 +158,7 @@ public void processSetting(Object pojo, Field setting) throws ProcessingMemberEx private void processSetting(Object pojo, Field setting, ConfigType type) throws FiberException { String name = this.findName(setting); List listeners = this.listenerMap.getOrDefault(name, Collections.emptyList()); + setting.setAccessible(true); ConfigLeafBuilder leafBuilder = this.builder .beginValue(name, type, this.findDefaultValue(pojo, setting)) .withComment(this.findComment(setting)) @@ -315,8 +316,6 @@ private void applyAnnotationProcessors(Object pojo, Field field, C sub, Map< @SuppressWarnings("unchecked") private T findDefaultValue(Object pojo, Field field) throws FiberException { - boolean accessible = field.isAccessible(); - field.setAccessible(true); T value; try { @@ -329,7 +328,6 @@ private T findDefaultValue(Object pojo, Field field) throws FiberException { throw new FiberException("Couldn't get value for field '" + field.getName() + "'", e); } - field.setAccessible(accessible); return value; } diff --git a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java index bf5c41d..1efb05f 100644 --- a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java +++ b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java @@ -106,7 +106,6 @@ public void detach() { public boolean setValue(@Nonnull S value) { if (this.backing.setValue(value)) { try { - this.backingField.setAccessible(true); value = backing.getValue(); // Might've changed after a type check + correction, so we fetch again this.backingField.set(pojo, type.toRuntimeType(value)); } catch (IllegalAccessException e) { @@ -124,7 +123,6 @@ public boolean setValue(@Nonnull S value) { @SuppressWarnings("unchecked") public S getValue() { try { - backingField.setAccessible(true); R fieldValue = (R) backingField.get(pojo); if (!Objects.equals(fieldValue, cachedValue)) { From a3bf276e7e0153e2bdbf3c1b571adb9b8dd52a2d Mon Sep 17 00:00:00 2001 From: Ridan Vandenbergh Date: Fri, 10 Jul 2020 18:02:51 +0200 Subject: [PATCH 10/11] Remove unnecessary detach call --- .../fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java index 701d535..a4b72b4 100644 --- a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java +++ b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/AnnotatedSettingsImpl.java @@ -165,7 +165,6 @@ private void processSetting(Object pojo, Field setting, ConfigType leaf = leafBuilder.build(); - leaf.detach(); builder.getItems().remove(leaf); BackedConfigLeaf deferred = new BackedConfigLeaf<>(leaf, type, pojo, setting); builder.getItems().add(deferred); // This will also attach deferred From 041bfa5fb3dce9315b5d6f4490de7ecbec76bae0 Mon Sep 17 00:00:00 2001 From: Ridan Vandenbergh Date: Sun, 26 Jul 2020 11:33:51 +0200 Subject: [PATCH 11/11] Throw an exception if a BackedConfigLeaf is made with a non-accessible field --- .../fablabs/impl/fiber/annotation/BackedConfigLeaf.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java index 1efb05f..0358e28 100644 --- a/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java +++ b/src/main/java/io/github/fablabsmc/fablabs/impl/fiber/annotation/BackedConfigLeaf.java @@ -35,6 +35,8 @@ public class BackedConfigLeaf implements ConfigLeaf { private ConfigBranch parent; public BackedConfigLeaf(ConfigLeaf backing, ConfigType type, Object pojo, Field backingField) { + if (!backingField.isAccessible()) throw new RuntimeFiberException("A BackedConfigLeaf may only be made for an accessible field!"); + this.backing = backing; this.type = type; this.pojo = pojo;