Description
Meaning a way to easily lay a filter/view over a JsonValue
tree. For example based on annotations.
interface JsonUser extends JsonObject {
@SensitiveInformation
String getPassword();
}
Now a tree should be filtered
JsonUser user = ...
JsonUser userPublic = user.viewExclude(SensitiveInformation.class);
While this works with "static" information views should also allow to do data driven filtering.
For example, by passing a Predicate<JsonUserField>
so a logic can be added when to include a JsonUserField
that is based on the data in a JsonUserField
value, like a isConfidential()
boolean property.
There are two variants of views:
- a true view as a filter in the proxy - this is likely easy to implement in the proxy handler with some additional logic but it will only work for access via the proxy
- a mapped JSON view that filters the underlying - this requires a model of the interfaces to know which properties to affect when processing the JSON content, but this is much safer and once produced has no overhead
Filter Models
This is an idea that maybe has best of both worlds/variants (as described above).
In a first step a filter model would be created by some process. This is a tree of what values to look at in a tree.
record JsonFilter<T extends JsonValue>(
Class<T> as,
Predicate<T> test,
Map<String,JsonFilter<T>> itemsByPath) {}
The model would then using structure like this
new JsonFilter(JsonGroup.class, null,
Map.of("user", new JsonFilter(JsonUser.class, JsonUser::isInternal, Map.of()));
This would be a dynamic model that might remove the $.user
from a UserGroup
root object based on the actual users isInternal()
property.
From this model and an actual value one can compute the removal operations to do.
In some models the test may not be dynamic but already decided as model creation.
For such models it is possible to create a patch of remove operations without an actual value.
The key in the map for the items is a path segment with array indexes being encoded as [i]
.
A special index would be used [*]
to say "for all" items, similarly *
alone means for all members of an object.
To access the member named *
one uses the {*}
variant of the name.
Models can be created in many different ways, for example by making an annotation analysis where a marker annotation marks all properties that should be filtered.