Skip to content

Commit 58b81f3

Browse files
committed
Added FieldFilter
If your configuration has a lot of fields and you want to exclude some of these fields without making them final, static or transient, you can configure your properties object to use additional FieldFilters. A FieldFilter filters the fields of a configuration class by a specified criterion. For example, if you only want to include fields whose names don't start with 'ignore', you would add the following filter: YamlProperties properties = YamlProperties.builder() .addFilter(field -> !field.getName().startsWith("ignore")) // ... .build();
1 parent b8caedc commit 58b81f3

File tree

20 files changed

+252
-210
lines changed

20 files changed

+252
-210
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: ConfigLib
22
author: Exlll
33

4-
version: 2.0.3
4+
version: 2.1.0
55
main: de.exlll.configlib.ConfigLib
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: ConfigLib
22
author: Exlll
33

4-
version: 2.0.3
4+
version: 2.1.0
55
main: de.exlll.configlib.ConfigLib

ConfigLib-Core/src/main/java/de/exlll/configlib/Configuration.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package de.exlll.configlib;
22

3+
import de.exlll.configlib.filter.FieldFilter;
4+
import de.exlll.configlib.filter.FieldFilters;
35
import de.exlll.configlib.format.FieldNameFormatter;
46
import de.exlll.configlib.format.FieldNameFormatters;
57

68
import java.io.IOException;
7-
import java.util.*;
9+
import java.util.Map;
10+
import java.util.Objects;
811

912
/**
1013
* Parent class of all configurations.
@@ -103,6 +106,7 @@ protected void postLoad() {}
103106
*/
104107
protected static class Properties {
105108
private final FieldNameFormatter formatter;
109+
private final FieldFilter filter;
106110

107111
/**
108112
* Constructs a new {@code Properties} object.
@@ -112,6 +116,7 @@ protected static class Properties {
112116
*/
113117
protected Properties(Builder<?> builder) {
114118
this.formatter = builder.formatter;
119+
this.filter = builder.filter;
115120
}
116121

117122
static Builder<?> builder() {
@@ -132,13 +137,23 @@ public final FieldNameFormatter getFormatter() {
132137
return formatter;
133138
}
134139

140+
/**
141+
* Returns the {@code FieldFilter} of a configuration
142+
*
143+
* @return {@code FieldFilter} of a configuration
144+
*/
145+
public final FieldFilter getFilter() {
146+
return filter;
147+
}
148+
135149
/**
136150
* Builder classes are used for constructing {@code Properties}.
137151
*
138152
* @param <B> type of the builder
139153
*/
140154
protected static abstract class Builder<B extends Builder<B>> {
141155
private FieldNameFormatter formatter = FieldNameFormatters.IDENTITY;
156+
private FieldFilter filter = FieldFilters.DEFAULT;
142157

143158
protected Builder() {}
144159

@@ -154,13 +169,30 @@ protected Builder() {}
154169
*
155170
* @param formatter formatter for configuration
156171
* @return this {@code Builder}
157-
* @throws NullPointerException if {@code formatter ist null}
172+
* @throws NullPointerException if {@code formatter} is null
158173
*/
159174
public final B setFormatter(FieldNameFormatter formatter) {
160175
this.formatter = Objects.requireNonNull(formatter);
161176
return getThis();
162177
}
163178

179+
/**
180+
* Composes the given {@link FieldFilter} with the
181+
* {@code FieldFilters.DEFAULT} instance and any other
182+
* previously added filters.
183+
* <p>
184+
* The added filter is not evaluated for a field if the field has
185+
* already been filtered or by some other {@code FieldFilter}.
186+
*
187+
* @param filter field filter that is added
188+
* @return this {@code Builder}
189+
* @throws NullPointerException if {@code filter} is null
190+
*/
191+
public final B addFilter(FieldFilter filter) {
192+
this.filter = this.filter.and(filter);
193+
return getThis();
194+
}
195+
164196
/**
165197
* Builds a new {@code Properties} instance using the values set.
166198
*

ConfigLib-Core/src/main/java/de/exlll/configlib/FieldMapper.java

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
package de.exlll.configlib;
22

33
import de.exlll.configlib.Converter.ConversionInfo;
4+
import de.exlll.configlib.filter.FieldFilter;
45
import de.exlll.configlib.format.FieldNameFormatter;
56

67
import java.lang.reflect.Field;
7-
import java.lang.reflect.Modifier;
8-
import java.util.Arrays;
98
import java.util.LinkedHashMap;
10-
import java.util.List;
119
import java.util.Map;
12-
import java.util.function.Predicate;
1310

1411
import static de.exlll.configlib.Validator.*;
15-
import static java.util.stream.Collectors.toList;
1612

1713
enum FieldMapper {
1814
;
@@ -21,7 +17,8 @@ static Map<String, Object> instanceToMap(
2117
Object inst, Configuration.Properties props
2218
) {
2319
Map<String, Object> map = new LinkedHashMap<>();
24-
for (Field field : FieldFilter.filterFields(inst.getClass())) {
20+
FieldFilter filter = props.getFilter();
21+
for (Field field : filter.filterDeclaredFieldsOf(inst.getClass())) {
2522
Object val = toConvertibleObject(field, inst, props);
2623
FieldNameFormatter fnf = props.getFormatter();
2724
String fn = fnf.fromFieldName(field.getName());
@@ -45,7 +42,8 @@ static void instanceFromMap(
4542
Object inst, Map<String, Object> instMap,
4643
Configuration.Properties props
4744
) {
48-
for (Field field : FieldFilter.filterFields(inst.getClass())) {
45+
FieldFilter filter = props.getFilter();
46+
for (Field field : filter.filterDeclaredFieldsOf(inst.getClass())) {
4947
FieldNameFormatter fnf = props.getFormatter();
5048
String fn = fnf.fromFieldName(field.getName());
5149
Object mapValue = instMap.get(fn);
@@ -79,27 +77,4 @@ private static void checkDefaultValueNull(Field field, Object instance) {
7977
Object val = Reflect.getValue(field, instance);
8078
checkNotNull(val, field.getName());
8179
}
82-
83-
enum FieldFilter implements Predicate<Field> {
84-
DEFAULT;
85-
86-
static List<Field> filterFields(Class<?> cls) {
87-
Field[] fields = cls.getDeclaredFields();
88-
return Arrays.stream(fields)
89-
.filter(DEFAULT)
90-
.collect(toList());
91-
}
92-
93-
@Override
94-
public boolean test(Field field) {
95-
if (field.isSynthetic()) {
96-
return false;
97-
}
98-
99-
int mods = field.getModifiers();
100-
return !(Modifier.isFinal(mods) ||
101-
Modifier.isStatic(mods) ||
102-
Modifier.isTransient(mods));
103-
}
104-
}
10580
}

ConfigLib-Core/src/main/java/de/exlll/configlib/Validator.java

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,9 @@ static void checkTypeHasNoArgsConstructor(ConversionInfo info) {
266266
}
267267
}
268268

269-
static void checkConverterHasNoArgsConstructor(Class<?> convClass, String fn) {
270-
if (!Reflect.hasNoArgConstructor(convClass)) {
271-
String msg = "Converter '" + convClass.getSimpleName() + "' used " +
269+
static void checkConverterHasNoArgsConstructor(Class<?> converterClass, String fn) {
270+
if (!Reflect.hasNoArgConstructor(converterClass)) {
271+
String msg = "Converter '" + converterClass.getSimpleName() + "' used " +
272272
"on field '" + fn + "' doesn't have a no-args constructor.";
273273
throw new ConfigurationException(msg);
274274
}
@@ -284,14 +284,6 @@ static void checkEnumValueIsString(ConversionInfo info) {
284284
}
285285
}
286286

287-
static boolean isTypeMap(Map<?, ?> map) {
288-
return map.entrySet().stream().allMatch(entry -> {
289-
Class<?> keyCls = entry.getKey().getClass();
290-
Class<?> valCls = entry.getValue().getClass();
291-
return (String.class == keyCls) && Reflect.isSimpleType(valCls);
292-
});
293-
}
294-
295287
static void checkFieldTypeAssignableFrom(Class<?> type, ConversionInfo info) {
296288
Class<?> fieldType = info.getFieldType();
297289
if (!fieldType.isAssignableFrom(type)) {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package de.exlll.configlib.filter;
2+
3+
import java.lang.reflect.Field;
4+
import java.util.Arrays;
5+
import java.util.List;
6+
import java.util.Objects;
7+
import java.util.function.Predicate;
8+
9+
import static java.util.stream.Collectors.toList;
10+
11+
@FunctionalInterface
12+
public interface FieldFilter extends Predicate<Field> {
13+
14+
@Override
15+
default FieldFilter and(Predicate<? super Field> other) {
16+
Objects.requireNonNull(other);
17+
return (t) -> test(t) && other.test(t);
18+
}
19+
20+
default List<? extends Field> filterDeclaredFieldsOf(Class<?> cls) {
21+
Field[] fields = cls.getDeclaredFields();
22+
return Arrays.stream(fields)
23+
.filter(this)
24+
.collect(toList());
25+
}
26+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package de.exlll.configlib.filter;
2+
3+
import java.lang.reflect.Field;
4+
import java.lang.reflect.Modifier;
5+
6+
public enum FieldFilters implements FieldFilter {
7+
DEFAULT {
8+
@Override
9+
public boolean test(Field field) {
10+
if (field.isSynthetic()) {
11+
return false;
12+
}
13+
14+
int mods = field.getModifiers();
15+
return !(Modifier.isFinal(mods) ||
16+
Modifier.isStatic(mods) ||
17+
Modifier.isTransient(mods));
18+
}
19+
}
20+
}

ConfigLib-Core/src/test/java/de/exlll/configlib/ConfigurationTest.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import de.exlll.configlib.configs.mem.InSharedMemoryConfiguration;
44
import org.junit.jupiter.api.Test;
55

6-
import java.io.IOException;
7-
86
import static org.hamcrest.Matchers.is;
97
import static org.junit.Assert.assertThat;
108

@@ -14,7 +12,7 @@ private static class TestHook extends InSharedMemoryConfiguration {
1412
}
1513

1614
@Test
17-
void configExecutesPreSaveHook() throws IOException {
15+
void configExecutesPreSaveHook() {
1816
class A extends TestHook {
1917
int i = 0;
2018

@@ -31,7 +29,7 @@ class A extends TestHook {
3129
}
3230

3331
@Test
34-
void configExecutesPostLoadHook() throws IOException {
32+
void configExecutesPostLoadHook() {
3533
class A extends TestHook {
3634
int i = 0;
3735

ConfigLib-Core/src/test/java/de/exlll/configlib/FieldMapperHelpers.java

Lines changed: 5 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import java.util.Map;
66

7-
import static de.exlll.configlib.Configuration.Properties;
87
import static de.exlll.configlib.configs.yaml.YamlConfiguration.YamlProperties.DEFAULT;
98
import static org.hamcrest.Matchers.is;
109
import static org.junit.Assert.assertThat;
@@ -43,44 +42,20 @@ public static void assertItmCfgExceptionMessage(Object o, String msg) {
4342
assertThat(ex.getMessage(), is(msg));
4443
}
4544

46-
public static void assertItmCfgExceptionMessage(
47-
Object o, Properties props, String msg
48-
) {
49-
ConfigurationException ex = assertItmThrowsCfgException(o, props);
50-
assertThat(ex.getMessage(), is(msg));
51-
}
52-
53-
5445
public static void assertIfmCfgExceptionMessage(
5546
Object o, Map<String, Object> map, String msg
5647
) {
5748
ConfigurationException ex = assertIfmThrowsCfgException(o, map);
5849
assertThat(ex.getMessage(), is(msg));
5950
}
6051

61-
public static void assertIfmCfgExceptionMessage(
62-
Object o, Map<String, Object> map, Properties props, String msg
63-
) {
64-
ConfigurationException ex = assertIfmThrowsCfgException(o, map, props);
65-
assertThat(ex.getMessage(), is(msg));
66-
}
67-
6852
public static ConfigurationException assertItmThrowsCfgException(Object o) {
6953
return assertThrows(
7054
ConfigurationException.class,
7155
() -> instanceToMap(o)
7256
);
7357
}
7458

75-
public static ConfigurationException assertItmThrowsCfgException(
76-
Object o, Configuration.Properties props
77-
) {
78-
return assertThrows(
79-
ConfigurationException.class,
80-
() -> instanceToMap(o, props)
81-
);
82-
}
83-
8459
public static ConfigurationException assertIfmThrowsCfgException(
8560
Object o, Map<String, Object> map
8661
) {
@@ -90,31 +65,23 @@ public static ConfigurationException assertIfmThrowsCfgException(
9065
);
9166
}
9267

93-
public static ConfigurationException assertIfmThrowsCfgException(
94-
Object o, Map<String, Object> map, Configuration.Properties props
95-
) {
96-
return assertThrows(
97-
ConfigurationException.class,
98-
() -> instanceFromMap(o, map, props)
99-
);
100-
}
101-
10268
public static Map<String, Object> instanceToMap(Object o) {
10369
return instanceToMap(o, DEFAULT);
10470
}
10571

10672
public static Map<String, Object> instanceToMap(
107-
Object o, Configuration.Properties props) {
73+
Object o, Configuration.Properties props
74+
) {
10875
return FieldMapper.instanceToMap(o, props);
10976
}
11077

11178
public static <T> T instanceFromMap(T o, Map<String, Object> map) {
112-
FieldMapper.instanceFromMap(o, map, DEFAULT);
113-
return o;
79+
return instanceFromMap(o, map, DEFAULT);
11480
}
11581

11682
public static <T> T instanceFromMap(
117-
T o, Map<String, Object> map, Configuration.Properties props) {
83+
T o, Map<String, Object> map, Configuration.Properties props
84+
) {
11885
FieldMapper.instanceFromMap(o, map, props);
11986
return o;
12087
}

0 commit comments

Comments
 (0)