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.
Meaning a way to easily lay a filter/view over a
JsonValuetree. For example based on annotations.Now a tree should be filtered
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 aJsonUserFieldthat is based on the data in aJsonUserFieldvalue, like aisConfidential()boolean property.There are two variants of views:
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.
The model would then using structure like this
This would be a dynamic model that might remove the
$.userfrom aUserGrouproot object based on the actual usersisInternal()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.