Some considerations on Beans...

Open
#396 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
35/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
java
Domain
tooling

Research direction

Start by reproducing the example with BeanProperty, SettingsManagerBuilder, and the temporary test.yml file. Trace how the bean is serialized, reloaded, and mapped when B2 is absent, then inspect the existing BeanProperty tests or implementation. Done means the intended handling of a missing nested bean field is agreed and covered by a regression test without unintended data loss.

Written by the indexing model from the issue text.

Description

beanmapper
Foreword

These days, I spend a lot of time testing the behavior of the BeanProperty.
As I read in the wiki:

ConfigMe will never return a bean in which a field is null. If it does not succeed to set a field's value, the mapping is considered to have failed and the default object is used. It is therefore important to initialize fields as shown with the country name above if you don't want the absence of one field to make ConfigMe ignore all fields and use the default bean object provided on initialization.

And

As with all other properties, bean properties never resolve to null, i.e. when you do settingsManager.getProperty(property) it is guaranteed to never return null.

But I think I broke these rules in a simple way, let me explain:
I have two bean classes called A and B, where B is used twice in A like the following code:

@Getter @Setter // lombok
public class A {
    private B b1;
    private B b2;
}
...
@Getter @Setter // lombok
public class B {
    private boolean enabled;
    private String value;
}

I have defined a SettingsHolder class that has only one property:

public class ConfigHolder implements SettingsHolder {
    private static final A DEF_VALUE;

    static {
        B b1 = new B();
        b1.setEnabled(true);
        b1.setValue("");

        B b2 = new B();
        b2.setEnabled(true);
        b2.setValue("");

        DEF_VALUE = new A();
        DEF_VALUE.setB1(b1);
        DEF_VALUE.setB2(b2);
    }

    public static final BeanProperty<A> TEST_PROP =
            newBeanProperty(A.class, "a", DEF_VALUE);
}

As you can see, the DEF_VALUE has no null references.

The tests

So, I have created the following unit test to put under pressure the BeanProperty.

@Test
void test() {
    // first file load
    File yamlFile = new File(tempDir.toFile(), "test.yml");
    SettingsManager settingsManager =
            SettingsManagerBuilder
                    .withYamlFile(yamlFile)
                    .configurationData(ConfigHolder.class)
                    .useDefaultMigrationService()
                    .create();

    B b1 = new B();
    b1.setEnabled(true);
    b1.setValue("test1");

    // I don't set B2, so the Bean will be serialized without B2.
    A a = new A();
    a.setB1(b1);

    // At this time, ConfigMe should not save the Bean that has
    // a null reference, but ok it is serialized without that null field.
    settingsManager.setProperty(ConfigHolder.TEST_PROP, a);
    settingsManager.save();

    // Read A from the current settings manager
    a = settingsManager.getProperty(ConfigHolder.TEST_PROP);

    Assertions.assertNotNull(a); // Ok
    Assertions.assertNotNull(a.getB1()); // Ok
    Assertions.assertEquals("test1", a.getB1().getValue()); // Ok
    Assertions.assertNull(a.getB2()); // Ok as I expected.

    // Now try to reload the configuration by recreating the new settings manager instance.
    settingsManager =
            SettingsManagerBuilder
                    .withYamlFile(yamlFile)
                    .configurationData(ConfigHolder.class)
                    .useDefaultMigrationService()
                    .create();

    // Read again A but this time from the new settings manager instance.
    a = settingsManager.getProperty(ConfigHolder.TEST_PROP);

    // What is expected: The reader won't recognize 
    // the Bean (A), and it will set the default value.
    Assertions.assertNotNull(a); // Ok
    Assertions.assertNotNull(a.getB1()); // Ok
    Assertions.assertEquals("", a.getB1().getValue()); // Ok
    Assertions.assertNotNull(a.getB2()); // Ok
    Assertions.assertEquals("", a.getB2().getValue()); // Ok
} 
Considerations

So, did I lose all the data just because of a missing field? Is that correct?
Imagine a user who misses a simple detail while setting up the bean. Will he lose all the data due to that mistake? Perhaps this should be revisited.

Thanks a lot ljacqu 💯

Dominant language
Java
Stars
44
Forks
21
Avg merge
2d 2h
Merged PRs (30d)
3

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from AuthMe/ConfigMe

All issues in AuthMe/ConfigMe

Similar issues

More Java issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.