Skip to content

Commit 4a95760

Browse files
committed
Refactor a bit to have fields declared the same way.
Renamed ConstructingObjectParser -> ObjectFactory (shorter name, felt more appropriate) Fields (setters, etc) are now declared using a fluent interface on ObjectFactory and don't need to be done in a `static { ... }` block anymore Also added back deprecated and obsolete fields.
1 parent 8a7637b commit 4a95760

File tree

15 files changed

+169
-260
lines changed

15 files changed

+169
-260
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.logstash.common.parser;
2+
3+
import org.apache.logging.log4j.LogManager;
4+
import org.apache.logging.log4j.Logger;
5+
6+
import java.util.function.Function;
7+
8+
public class DeprecatedField<Value> extends FieldDefinition<Value> {
9+
private static final Logger logger = LogManager.getLogger();
10+
private final String details;
11+
12+
DeprecatedField(String name, Function<Object, Value> transform, String details) {
13+
super(name, transform);
14+
this.details = details;
15+
}
16+
17+
@Override
18+
public Value apply(Object object) {
19+
if (object != null) {
20+
logger.warn("The field '" + getName() + "' is deprecated and will be removed soon: " + details);
21+
}
22+
return super.apply(object);
23+
}
24+
}

logstash-core/src/main/java/org/logstash/common/parser/Field.java

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@
55
import java.util.function.Function;
66

77
public interface Field<Value> extends Function<Object, Value> {
8-
Field setDeprecated(String details);
8+
static <V> Field<V> declareObject(String name, ObjectFactory<V> parser) {
9+
return declareField(name, (config) -> parser.apply(ObjectTransforms.transformMap(config)));
10+
}
11+
12+
String getName();
13+
14+
String getDetails();
915

1016
static Field<String> declareString(String name) {
1117
return declareField(name, ObjectTransforms::transformString);
1218
}
13-
Field setObsolete(String details);
1419

1520
static Field<Float> declareFloat(String name) {
1621
return declareField(name, ObjectTransforms::transformFloat);
@@ -36,8 +41,8 @@ static Field<Map<String, Object>> declareMap(String name) {
3641
return declareField(name, ObjectTransforms::transformMap);
3742
}
3843

39-
static <V> Field<V> declareObject(String name, ConstructingObjectParser<V> parser) {
40-
return declareField(name, (config) -> parser.apply(ObjectTransforms.transformMap(config)));
44+
default Value apply(Map<String, Object> map) {
45+
return apply(map.get(getName()));
4146
}
4247

4348
static <V> Field<List<V>> declareList(String name, Function<Object, V> transform) {
@@ -48,12 +53,4 @@ static <V> Field<V> declareField(String name, Function<Object, V> transform) {
4853
return new FieldDefinition<>(name, transform);
4954
}
5055

51-
String getName();
52-
53-
String getDetails();
54-
55-
default Value apply(Map<String, Object> map) {
56-
return apply(map.get(getName()));
57-
}
58-
5956
}

logstash-core/src/main/java/org/logstash/common/parser/FieldDefinition.java

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ class FieldDefinition<Value> implements Field<Value> {
1111

1212
private final String name;
1313

14-
// This is only set if deprecated or obsolete
15-
// XXX: Move this concept separately to DeprecatedFieldDefinition and ObsoleteFieldDefinition
14+
// XXX: Should Field definitions be separated in Field, DeprecatedField, ObsoleteField ?
1615
private FieldStatus status = FieldStatus.Supported;
1716
private String details;
1817

@@ -21,43 +20,15 @@ class FieldDefinition<Value> implements Field<Value> {
2120
this.transform = transform;
2221
}
2322

24-
@Override
25-
public Field setDeprecated(String details) {
26-
setStatus(FieldStatus.Deprecated, details);
27-
return this;
28-
}
29-
30-
@Override
31-
public Field setObsolete(String details) {
32-
setStatus(FieldStatus.Obsolete, details);
33-
return this;
34-
}
35-
36-
private void setStatus(FieldStatus status, String details) {
37-
this.status = status;
38-
this.details = details;
39-
}
40-
4123
@Override
4224
public Value apply(Object object) {
4325
if (object == null) {
4426
throw new NullPointerException("The '" + name + "' field is required and no value was provided.");
4527
}
46-
switch (status) {
47-
// XXX: use Structured logging + localization lookups.
48-
case Deprecated:
49-
logger.warn("The field '" + getName() + "' is deprecated and will be removed soon: " + getDetails());
50-
break;
51-
case Obsolete:
52-
logger.fatal("The field '" + getName() + "' is obsolete and has been removed: " + getDetails());
53-
break;
54-
case Supported:
55-
break;
56-
}
57-
5828
return transform.apply(object);
5929
}
6030

31+
@Override
6132
public String getName() {
6233
return name;
6334
}

logstash-core/src/main/java/org/logstash/common/parser/FieldUsage.java

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
package org.logstash.common.parser;
22

33
class Functions {
4-
public interface Function3<Arg0, Arg1, Arg2, Value> {
4+
interface Function3<Arg0, Arg1, Arg2, Value> {
55
Value apply(Arg0 arg0, Arg1 arg1, Arg2 arg2);
66
}
77

8-
public interface Function4<Arg0, Arg1, Arg2, Arg3, Value> {
8+
interface Function4<Arg0, Arg1, Arg2, Arg3, Value> {
99
Value apply(Arg0 arg0, Arg1 arg1, Arg2 arg2, Arg3 arg3);
1010
}
1111

12-
public interface Function5<Arg0, Arg1, Arg2, Arg3, Arg4, Value> {
12+
interface Function5<Arg0, Arg1, Arg2, Arg3, Arg4, Value> {
1313
Value apply(Arg0 arg0, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4);
1414
}
1515

16-
public interface Function6<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Value> {
16+
interface Function6<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Value> {
1717
Value apply(Arg0 arg0, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5);
1818
}
1919

20-
public interface Function7<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Value> {
20+
interface Function7<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Value> {
2121
Value apply(Arg0 arg0, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6);
2222
}
2323

24-
public interface Function8<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Value> {
24+
interface Function8<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Value> {
2525
Value apply(Arg0 arg0, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6, Arg7 arg7);
2626
}
2727

28-
public interface Function9<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Value> {
28+
interface Function9<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Value> {
2929
Value apply(Arg0 arg0, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6, Arg7 arg7, Arg8 arg8);
3030
}
3131
}

logstash-core/src/main/java/org/logstash/common/parser/ConstructingObjectParser.java renamed to logstash-core/src/main/java/org/logstash/common/parser/ObjectFactory.java

Lines changed: 36 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,18 @@
2727
*
2828
* @param <Value> The object type to construct when `parse` is called.
2929
*/
30-
public class ConstructingObjectParser<Value> implements ObjectParser<Value> {
30+
public class ObjectFactory<Value> implements Function<Map<String, Object>, Value> {
3131
private final Map<String, BiConsumer<Value, Object>> parsers = new HashMap<>();
32-
private List<Field<?>> constructorFields = null;
32+
private List<Field<?>> constructorFields;
3333
private final Function<Map<String, Object>, Value> builder;
34+
3435
/**
3536
* Zero-argument object constructor (A Supplier)
37+
*
3638
* @param supplier The supplier which produces an object instance.
3739
*/
3840
@SuppressWarnings("WeakerAccess") // Public Interface
39-
public ConstructingObjectParser(Supplier<Value> supplier) {
41+
public ObjectFactory(Supplier<Value> supplier) {
4042
this(config -> supplier.get());
4143
constructorFields = Collections.emptyList();
4244
}
@@ -45,7 +47,7 @@ public ConstructingObjectParser(Supplier<Value> supplier) {
4547
* One-argument object constructor
4648
*/
4749
@SuppressWarnings("WeakerAccess") // Public Interface
48-
public <Arg0> ConstructingObjectParser(Function<Arg0, Value> function, Field<Arg0> arg0) {
50+
public <Arg0> ObjectFactory(Function<Arg0, Value> function, Field<Arg0> arg0) {
4951
this(config -> function.apply(arg0.apply(config)));
5052
constructorFields = Collections.singletonList(arg0);
5153
}
@@ -54,7 +56,7 @@ public <Arg0> ConstructingObjectParser(Function<Arg0, Value> function, Field<Arg
5456
* Two-argument object constructor
5557
*/
5658
@SuppressWarnings("WeakerAccess") // Public Interface
57-
public <Arg0, Arg1> ConstructingObjectParser(BiFunction<Arg0, Arg1, Value> function, Field<Arg0> arg0, Field<Arg1> arg1) {
59+
public <Arg0, Arg1> ObjectFactory(BiFunction<Arg0, Arg1, Value> function, Field<Arg0> arg0, Field<Arg1> arg1) {
5860
this(config -> function.apply(arg0.apply(config), arg1.apply(config)));
5961
constructorFields = Arrays.asList(arg0, arg1);
6062
}
@@ -63,110 +65,55 @@ public <Arg0, Arg1> ConstructingObjectParser(BiFunction<Arg0, Arg1, Value> funct
6365
* Three-argument object constructor
6466
*/
6567
@SuppressWarnings("WeakerAccess") // Public Interface
66-
public <Arg0, Arg1, Arg2> ConstructingObjectParser(Function3<Arg0, Arg1, Arg2, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2) {
68+
public <Arg0, Arg1, Arg2> ObjectFactory(Function3<Arg0, Arg1, Arg2, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2) {
6769
this(config -> function.apply(arg0.apply(config), arg1.apply(config), arg2.apply(config)));
6870
constructorFields = Arrays.asList(arg0, arg1, arg2);
6971
}
7072

7173

7274
@SuppressWarnings("WeakerAccess") // Public Interface
73-
public <Arg0, Arg1, Arg2, Arg3> ConstructingObjectParser(Function4<Arg0, Arg1, Arg2, Arg3, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2, Field<Arg3> arg3) {
75+
public <Arg0, Arg1, Arg2, Arg3> ObjectFactory(Function4<Arg0, Arg1, Arg2, Arg3, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2, Field<Arg3> arg3) {
7476
this(config -> function.apply(arg0.apply(config), arg1.apply(config), arg2.apply(config), arg3.apply(config)));
7577
constructorFields = Arrays.asList(arg0, arg1, arg2, arg3);
7678
}
7779

7880
@SuppressWarnings("WeakerAccess") // Public Interface
79-
public <Arg0, Arg1, Arg2, Arg3, Arg4> ConstructingObjectParser(Function5<Arg0, Arg1, Arg2, Arg3, Arg4, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2, Field<Arg3> arg3, Field<Arg4> arg4) {
81+
public <Arg0, Arg1, Arg2, Arg3, Arg4> ObjectFactory(Function5<Arg0, Arg1, Arg2, Arg3, Arg4, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2, Field<Arg3> arg3, Field<Arg4> arg4) {
8082
this(config -> function.apply(arg0.apply(config), arg1.apply(config), arg2.apply(config), arg3.apply(config), arg4.apply(config)));
8183
constructorFields = Arrays.asList(arg0, arg1, arg2, arg3, arg4);
8284
}
8385

8486
@SuppressWarnings("WeakerAccess") // Public Interface
85-
public <Arg0, Arg1, Arg2, Arg3, Arg4, Arg5> ConstructingObjectParser(Function6<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2, Field<Arg3> arg3, Field<Arg4> arg4, Field<Arg5> arg5) {
87+
public <Arg0, Arg1, Arg2, Arg3, Arg4, Arg5> ObjectFactory(Function6<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2, Field<Arg3> arg3, Field<Arg4> arg4, Field<Arg5> arg5) {
8688
this(config -> function.apply(arg0.apply(config), arg1.apply(config), arg2.apply(config), arg3.apply(config), arg4.apply(config), arg5.apply(config)));
8789
constructorFields = Arrays.asList(arg0, arg1, arg2, arg3, arg4, arg5);
8890
}
8991

9092
@SuppressWarnings("WeakerAccess") // Public Interface
91-
public <Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6> ConstructingObjectParser(Function7<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2, Field<Arg3> arg3, Field<Arg4> arg4, Field<Arg5> arg5, Field<Arg6> arg6) {
93+
public <Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6> ObjectFactory(Function7<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2, Field<Arg3> arg3, Field<Arg4> arg4, Field<Arg5> arg5, Field<Arg6> arg6) {
9294
this(config -> function.apply(arg0.apply(config), arg1.apply(config), arg2.apply(config), arg3.apply(config), arg4.apply(config), arg5.apply(config), arg6.apply(config)));
9395
constructorFields = Arrays.asList(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
9496
}
9597

9698
@SuppressWarnings("WeakerAccess") // Public Interface
97-
public <Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7> ConstructingObjectParser(Function8<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2, Field<Arg3> arg3, Field<Arg4> arg4, Field<Arg5> arg5, Field<Arg6> arg6, Field<Arg7> arg7) {
99+
public <Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7> ObjectFactory(Function8<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2, Field<Arg3> arg3, Field<Arg4> arg4, Field<Arg5> arg5, Field<Arg6> arg6, Field<Arg7> arg7) {
98100
this(config -> function.apply(arg0.apply(config), arg1.apply(config), arg2.apply(config), arg3.apply(config), arg4.apply(config), arg5.apply(config), arg6.apply(config), arg7.apply(config)));
99101
constructorFields = Arrays.asList(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
100102
}
101103

102104
@SuppressWarnings("WeakerAccess") // Public Interface
103-
public <Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8> ConstructingObjectParser(Function9<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2, Field<Arg3> arg3, Field<Arg4> arg4, Field<Arg5> arg5, Field<Arg6> arg6, Field<Arg7> arg7, Field<Arg8> arg8) {
105+
public <Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8> ObjectFactory(Function9<Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Value> function, Field<Arg0> arg0, Field<Arg1> arg1, Field<Arg2> arg2, Field<Arg3> arg3, Field<Arg4> arg4, Field<Arg5> arg5, Field<Arg6> arg6, Field<Arg7> arg7, Field<Arg8> arg8) {
104106
this(config -> function.apply(arg0.apply(config), arg1.apply(config), arg2.apply(config), arg3.apply(config), arg4.apply(config), arg5.apply(config), arg6.apply(config), arg7.apply(config), arg8.apply(config)));
105107
constructorFields = Arrays.asList(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
106108
}
107109

108-
private ConstructingObjectParser(Function<Map<String, Object>, Value> builder) {
110+
private ObjectFactory(Function<Map<String, Object>, Value> builder) {
109111
this.builder = builder;
110112
}
111113

112-
private static <Value> Value construct(Map<String, Object> config, Function<Object[], Value> builder, Field<?>... constructorFields) throws IllegalArgumentException {
113-
Object[] builderArgs = new Object[constructorFields.length];
114-
int i = 0;
115-
for (Field<?> field : constructorFields) {
116-
final String name = field.getName();
117-
118-
if (config.containsKey(name)) {
119-
builderArgs[i] = field.apply(config.get(name));
120-
} else {
121-
throw new IllegalArgumentException("Missing required argument '" + name + "'");
122-
}
123-
124-
i++;
125-
}
126-
127-
return builder.apply(builderArgs);
128-
}
129-
130-
/**
131-
* Declare a field. Field ordering does not matter.
132-
* <p>
133-
* A field is intended to call a Setter on an Object.
134-
* <p>
135-
* When calling `apply`, all fields are considered optional and may be absent from the config map.
136-
* <p>
137-
* <code>{@code
138-
* ConstructingObjectParser<SocketServer> c = new ConstructingObjectParser<>(SocketServer::new)
139-
* c.declareBoolean("reuseAddress", SocketServer::setReuseAddress);
140-
* c.declareInteger("receiveBufferSize", SocketServer::setReceiveBufferSize);
141-
* <p>
142-
* Map<String, Object> config = new HashMap<>();
143-
* config.put("reuseAddress", true);
144-
* config.put("receiveBufferSize", 65536);
145-
* SocketServer server = c.apply(config);
146-
* }</code>
147-
*
148-
* @param name
149-
* @param consumer
150-
* @param transform
151-
* @param <T>
152-
* @return
153-
*/
154-
@Override
155-
@SuppressWarnings("WeakerAccess") // Public Interface
156-
public <T> Field declareField(String name, BiConsumer<Value, T> consumer, Function<Object, T> transform) {
157-
if (isKnownField(name)) {
158-
throw new IllegalArgumentException("Duplicate field defined '" + name + "'");
159-
}
160-
161-
BiConsumer<Value, Object> objConsumer = (value, object) -> consumer.accept(value, transform.apply(object));
162-
FieldDefinition<T> field = new FieldDefinition<>(name, transform);
163-
parsers.put(name, (value, input) -> consumer.accept(value, transform.apply(input)));
164-
return field;
165-
}
166-
167114
/**
168115
* Use the given config to produce the Value object.
169-
*
116+
* <p>
170117
* Contract:
171118
* 1) All declared constructor arguments are required. If any are missing, an IllegalArgumentException is thrown.
172119
* 2) All declared fields are optional.
@@ -176,6 +123,7 @@ public <T> Field declareField(String name, BiConsumer<Value, T> consumer, Functi
176123
* @param config the configuration
177124
* @return the configured object
178125
*/
126+
@SuppressWarnings("WeakerAccess") // Public Interface
179127
public Value apply(Map<String, Object> config) {
180128
rejectUnknownFields(config.keySet());
181129

@@ -219,4 +167,23 @@ private void rejectUnknownFields(Set<String> configNames) throws IllegalArgument
219167
}
220168
}
221169

170+
@SuppressWarnings("WeakerAccess") // Public Interface
171+
public <T> ObjectFactory<Value> define(Field<T> field, BiConsumer<Value, T> consumer) {
172+
if (isKnownField(field.getName())) {
173+
throw new IllegalArgumentException("Duplicate field defined '" + field.getName() + "'");
174+
}
175+
176+
parsers.put(field.getName(), (value, input) -> consumer.accept(value, field.apply(input)));
177+
return this;
178+
}
179+
180+
@SuppressWarnings("WeakerAccess") // Public Interface
181+
public <T> ObjectFactory<Value> deprecate(Field<T> field, BiConsumer<Value, T> consumer, String details) {
182+
return define(new DeprecatedField<>(field.getName(), field, details), consumer);
183+
}
184+
185+
@SuppressWarnings("WeakerAccess") // Public Interface
186+
public <T> ObjectFactory<Value> obsolete(Field<T> field, BiConsumer<Value, T> consumer, String details) {
187+
return define(new ObsoleteField<>(field.getName(), field, details), consumer);
188+
}
222189
}

0 commit comments

Comments
 (0)