-
Notifications
You must be signed in to change notification settings - Fork 16
Custom property types
You can implement your own Property or PropertyType if you require additional types or custom behavior. This page shows you the different ways in which you can implement specific types for ConfigMe.
If you need something like a custom array type or a "fluent" API to define custom values, it's worth having a look
at the PropertyBuilder
class.
Examples:
Property<Long[]> property = new PropertyBuilder.ArrayPropertyBuilder<>(PrimitivePropertyType.LONG, Long[]::new)
.path("given.path")
.defaultValue(5L, 11L, 23L)
.build();
Creates a Property which holds a Long array. The default value is an array with the values {5, 11, 23}
.
MapProperty<Double> result = new PropertyBuilder.MapPropertyBuilder<>(PrimitivePropertyType.DOUBLE)
.path("the.path")
.defaultEntry("leet", 1337.0)
.defaultEntry("all", 411.0)
.build();
Creates a Property<Map<String, Double>>
whose default value is a map with entries {"leet" -> 1337.0, "all" -> 411.0}
The easiest way to implement a custom type is to implement your own PropertyType
. The property type has two methods
which define how the value is converted from and to the property resource. For example, if we want to have a Byte type:
public class ByteType implements PropertyType<Byte> {
@Override
public Byte convert(Object object, ConvertErrorRecorder errorRecorder) {
if (object instanceof Number) {
return ((Number) object).byteValue();
}
return null;
}
@Override
public Object toExportValue(Byte value) {
return value.intValue();
}
}
Then, create a TypeBasedProperty
with it:
new TypeBasedProperty<>("my.path", (byte) 3, new ByteType());
Or, for convenience, create an extension of this class like IntegerProperty
etc. for easier use.
You can also directly extend BaseProperty
. In this case, two methods have to be implemented which are almost identical
to the PropertyType
methods we've seen above. The difference is that you get the PropertyReader
directly instead
of the value at the property's path, and you can override other methods of BaseProperty
if so desired.
Typically, this approach should be chosen if your new property has a collection type or is otherwise more complicated to construct.
public class ByteProperty extends BaseProperty<Byte> {
public ByteProperty(String path, Byte defaultValue) {
super(path, defaultValue);
}
@Override
protected Byte getFromReader(PropertyReader reader,
ConvertErrorRecorder errorRecorder) {
Object value = reader.getObject(getPath());
if (value instanceof Number) {
return ((Number) value).byteValue();
}
return null;
}
@Override
public Object toExportValue(Byte value) {
return value.intValue();
}
}
Alternatively, if you want to restrict the range of values that are admissible for a property, consider implementing validation where you use the property, or implement the logic in the migration service. This would also allow you to log some meaningful error.
For example, if we implemented a ByteProperty
but then kept having to cast it to an integer everywhere it's used,
it would be a more elegant approach to declare an integer property and to have a check in the migration service that
ensures that the value could be represented with a Byte. Since the migration service is always called, it is
guaranteed that we'll never retrieve any invalid value from the SettingsManager.
Similar to the Custom validation approach, in certain cases if you want to map values to a very specific type or with specific rules where bean properties aren't satisfactory, it may make sense for you to perform this conversion outside of ConfigMe based on simpler properties that ConfigMe manages.
This way, you have full control on how simpler values are converted to your complicated structure. This can be especially interesting if you only need to use the complicated structure in one place in your code.
- In the export value methods, why is it OK to immediately call a method on the
value
without a null check? - In the export value methods, why is Byte#intValue called and not Byte#toString?
Navigation
« Bean properties | Custom property types | Technical documentation » |
Guide
- Introduction
- Getting started
- Migration service
- Bean properties
- Custom property types
- Technical documentation
Updating
Development (internal)