AuthMe / ConfigMe

A simple configuration management library for any Java project!
MIT License
37 stars 15 forks source link

Bean property as array/list and inner beans #395

Open gamerover98 opened 10 months ago

gamerover98 commented 10 months ago

The problem It is not easy to create a list or array of BeanProperty. At the moment, I have found this solution:

@Getter @Setter // Lombok
public class Country implements ParameterizedType {

    private static final Type[] TYPE_ARGUMENTS = {
            String.class, // name type
            Integer.TYPE, // total population type
    };

    private String name;
    private int totalPopulation;
    ...

    @Override
    public Type[] getActualTypeArguments() {
        return TYPE_ARGUMENTS;
    }

    @Override
    public Type getRawType() {
        return ItemProperty.class;
    }

    @Override
    public Type getOwnerType() {
        return null;
    }
}
public static final Property<Country[]> COUNTRIES =
            new PropertyBuilder.ArrayPropertyBuilder<>(
                    new BeanPropertyType<>(
                            new TypeInformation(new Country()), DefaultMapper.getInstance()),
                    Country[]::new)
                    .path("country.list")
                    .defaultValue(new Country[0])
                    .build();

Now, if you want to add other info like a bean list called "City", it won't be serialized:

@Getter @Setter // Lombok
public class City implements ParameterizedType {

    private static final Type[] TYPE_ARGUMENTS = {
            String.class, // city type
            Integer.TYPE, // population type
    };

    private String name;
    private int population;
    ...
}
@Getter @Setter // Lombok
public class Country implements ParameterizedType {

    private static final Type[] TYPE_ARGUMENTS = {
            String.class, // name type
            Integer.TYPE, // total population type
            City[].class, // the city array type
    };

    private String name;
    private int totalPopulation;
    private City[] cities;
    ...
}

The YAML result will be:

country.list:
  - name: United States
    totalPopulation: 331000000
    cities: {}

But what I want is:

country.list:
  - name: United States
    totalPopulation: 331000000
    cities:
    - name: New York
      population: 8400000
    - name: Las Vegas
      population: 646700

A solution (?) Maybe, define a BeanListProperty that extends ListPropery and grants an easy way to add beans without map field types.

gamerover98 commented 10 months ago

After conducting various tests, I have come to a conclusion. It is incorrect to serialize an array of Beans using the PropertyBuilder.ArrayPropertyBuilder(...) method. Instead, it is much easier to create a Bean class that encapsulates everything. Let me explain further by referring to the example of "Country":

The World Bean class:

@Getter @Setter
public class World {
    private List<Country> countries;
}

The property:

public static final Property<World> WORLD = 
            newBeanProperty(World.class, "world", new World());
ljacqu commented 10 months ago

This is probably the best solution since YAML sequences can look a bit weird without a property.

In ConfigMe 2.0, arrays or lists of a bean property type will become easier to maintain as ListPropertyType and ArrayPropertyType are based on an entry property type, which could be a bean property type (#230). I don't have any simple tests using a bean property so I might use this issue for adding some. Thanks!


Reminder not to implement ParameterizedType by yourself, as detailed in https://github.com/AuthMe/ConfigMe/issues/354#issuecomment-1681889202