Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit da54300

Browse files
committedFeb 15, 2024
Document post-processing
1 parent d88c584 commit da54300

File tree

2 files changed

+142
-1
lines changed

2 files changed

+142
-1
lines changed
 

‎README.md

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,133 @@ constructor with one parameter of type `SerializerContext`. If such a
816816
constructor exists, a context object is passed to it when the serializer is
817817
instantiated by this library.
818818

819+
### Post-processing
820+
821+
There are two ways to apply some post-processing to your configurations:
822+
823+
- The first is to annotate a method in your configuration type with the
824+
`@PostProcess` annotation.
825+
- The second is to add post-processor functions to a `ConfigurationProperties`
826+
object. These functions are then applied to some set of configuration elements
827+
that is defined by a `ConfigurationElementFilter`.
828+
829+
Both ways of post-processing can be applied at the same time. In this case,
830+
the post-processor functions added to a `ConfigurationProperties` object run
831+
first.
832+
833+
#### Post-process configurations via annotated method
834+
835+
One way to apply post-processing to your configuration is to annotate some
836+
method of your configuration type with the `@PostProcess` annotation.
837+
838+
```java
839+
@Configuration
840+
public final class Config {
841+
private int i = 10;
842+
private String s = "abc";
843+
844+
@PostProcess
845+
private void postProcess() {
846+
this.i = this.i * 2;
847+
this.s = this.s.repeat(2);
848+
}
849+
}
850+
```
851+
852+
The return type of the `@PostProcess` method must either be `void` or the same
853+
type as the type in which that method is defined. In the first case, the method
854+
is simply executed. In the latter case, the return value of the method replaces
855+
the current instance when initializing a configuration. This is, in particular,
856+
useful for Java records whose fields are final and cannot be modified.
857+
858+
```java
859+
public record Config(int i, String s) {
860+
@PostProcess
861+
private Config postProcess() {
862+
return new Config(i * 2, s.repeat(2));
863+
}
864+
}
865+
```
866+
867+
The name of the `@PostProcess` method can be any valid Java method name.
868+
However, your configuration type is allowed to define at most one such method
869+
and `@PostProcess` methods of parent classes are _not_ executed.
870+
871+
#### Post-process configuration elements by condition
872+
873+
The second way to apply post-processing to your configuration is to define
874+
a `ConfigurationElementFilter`. Such a filter implicitly defines a set of
875+
configuration elements to which some post-processing function should be applied.
876+
Both, filters and post-processing functions, can be added via
877+
the `ConfigurationProperties#addPostProcessor` method at the same time and the
878+
function is then applied to all configuration elements that are defined by the
879+
filter.
880+
881+
For example, to double the values of _all_ configuration elements of type `int`,
882+
you would add the following filter and post-processing function:
883+
884+
```java
885+
ConfigurationProperties.newBuilder()
886+
.addPostProcessor(
887+
// Predicate<? super ConfigurationElement<?>> filter
888+
element -> element.type().equals(int.class),
889+
// UnaryOperator<?> postProcessor
890+
(Integer value) -> value * 2
891+
)
892+
.build();
893+
```
894+
895+
Note that it is your responsibility to make sure that the filter only selects
896+
configuration elements whose type matches the type the post-processing function
897+
expects.
898+
899+
Also note, that the post-processing function will be applied regardless of
900+
whether a configuration file contained a value for some specific element.
901+
This means that your post-processing function should properly handle `null`
902+
input values if, for example, you allow the input of such values.
903+
904+
The `ConfigurationElementFilter` interface defines static factories to
905+
facilitate the creation of common filters:
906+
907+
```java
908+
ConfigurationElementFilter.byType(Class<?> type)
909+
ConfigurationElementFilter.byPostProcessKey(String key)
910+
```
911+
912+
The second factory creates a filter that selects all configuration elements that
913+
are annotated with `@PostProcess` and where the `key()` method of that
914+
annotation returns the given `key`.
915+
916+
In the following example, the values of `a` and `b` are doubled, the value
917+
of `c` is tripled, `d` is set to zero, and no post-processing is applied
918+
to `e` and `f`.
919+
920+
```java
921+
record Config(
922+
@PostProcess(key = "double") int a,
923+
@PostProcess(key = "double") int b,
924+
@PostProcess(key = "tripple") int c,
925+
@PostProcess int d,
926+
@PostProcess(key = "missing processor") int e,
927+
int f
928+
) {}
929+
930+
ConfigurationProperties.newBuilder()
931+
.addPostProcessor(
932+
ConfigurationElementFilter.byPostProcessKey("double"),
933+
(Integer value) -> value * 2
934+
)
935+
.addPostProcessor(
936+
ConfigurationElementFilter.byPostProcessKey("tripple"),
937+
(Integer value) -> value * 3
938+
)
939+
.addPostProcessor(
940+
ConfigurationElementFilter.byPostProcessKey(""),
941+
(Integer value) -> 0
942+
)
943+
.build();
944+
```
945+
819946
### Changing the type of configuration elements
820947

821948
Changing the type of configuration elements is not supported. If you change the
@@ -1002,7 +1129,6 @@ please [open an issue](https://github.com/Exlll/ConfigLib/issues/new) where we
10021129
can discuss the details.
10031130

10041131
- JSON, TOML, XML support
1005-
- Post-load/Pre-save hooks
10061132
- More features and control over updating/versioning
10071133
- More control over the ordering of fields, especially in parent/child class
10081134
scenarios

‎configlib-core/src/test/java/de/exlll/configlib/RecordSerializerTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,5 +559,20 @@ void postProcessorCanPreventExceptionsThatHappenWhenTryingToSetPrimitiveFieldsTo
559559
);
560560
R16 primI = serializer.deserialize(asMap("primI", null));
561561
assertThat(primI.primI, is(76));
562+
563+
ConfigurationProperties.newBuilder()
564+
.addPostProcessor(
565+
ConfigurationElementFilter.byPostProcessKey("doubleMe"),
566+
(Integer value) -> value * 2
567+
)
568+
.addPostProcessor(
569+
ConfigurationElementFilter.byPostProcessKey("trippleMe"),
570+
(Integer value) -> value * 3
571+
)
572+
.addPostProcessor(
573+
ConfigurationElementFilter.byPostProcessKey(""),
574+
(Integer value) -> 0
575+
)
576+
.build();
562577
}
563578
}

0 commit comments

Comments
 (0)
Please sign in to comment.