Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Exclude defaults fix [DHIS2-17564](2.39) #18738

Merged
merged 1 commit into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
import org.hisp.dhis.eventchart.EventChart;
import org.hisp.dhis.eventreport.EventReport;
import org.hisp.dhis.eventvisualization.EventVisualization;
import org.hisp.dhis.fieldfilter.Defaults;
import org.hisp.dhis.fieldfiltering.FieldFilterParams;
import org.hisp.dhis.fieldfiltering.FieldFilterService;
import org.hisp.dhis.indicator.Indicator;
Expand Down Expand Up @@ -291,7 +292,8 @@ public void getMetadataAsObjectNodeStream(MetadataExportParams params, OutputStr

String plural = schemaService.getDynamicSchema(klass).getPlural();
generator.writeArrayFieldStart(plural);
fieldFilterService.toObjectNodesStream(fieldFilterParams, generator);
fieldFilterService.toObjectNodesStream(
fieldFilterParams, params.getDefaults().isExclude(), generator);
generator.writeEndArray();
}

Expand Down Expand Up @@ -430,6 +432,11 @@ public MetadataExportParams getParamsFromMap(Map<String, List<String>> parameter
parameters.remove("skipSharing");
}

if (parameters.containsKey("defaults")) {
params.setDefaults(Defaults.valueOf(parameters.get("defaults").get(0)));
parameters.remove("defaults");
}

for (String parameterKey : parameters.keySet()) {
String[] parameter = parameterKey.split(":");
Schema schema = schemaService.getSchemaByPluralName(parameter[0]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
Expand Down Expand Up @@ -207,11 +208,34 @@ private <T> List<ObjectNode> toObjectNodes(
return objectNodes;
}

/**
* Method allowing calls without an exclude defaults boolean parameter. This keeps current
* behaviour as is. If callers require different behaviour regarding excluding defaults, then they
* can call the toObjectNodes method which takes a value for excluding defaults. This method
* passes false as the default value for excluding defaults.
*
* @param objects objects to render
* @param filter filters
* @param user user
* @param isSkipSharing skip sharing
* @param consumer consumer action
* @param <T> type of objects
*/
private <T> void toObjectNodes(
List<T> objects,
List<FieldPath> filter,
User user,
boolean isSkipSharing,
Consumer<ObjectNode> consumer) {
toObjectNodes(objects, filter, user, isSkipSharing, false, consumer);
}

private <T> void toObjectNodes(
List<T> objects,
List<FieldPath> filter,
User user,
boolean isSkipSharing,
boolean excludeDefaults,
Consumer<ObjectNode> consumer) {
if (user == null) {
user = currentUserService.getCurrentUser();
Expand All @@ -223,7 +247,8 @@ private <T> void toObjectNodes(
List<FieldPath> paths =
fieldPathHelper.apply(filter, HibernateProxyUtils.getRealClass(firstObject));

SimpleFilterProvider filterProvider = getSimpleFilterProvider(paths, isSkipSharing);
SimpleFilterProvider filterProvider =
getSimpleFilterProvider(paths, isSkipSharing, excludeDefaults);

// only set filter provider on a local copy so that we don't affect
// other object mappers (running across other threads)
Expand All @@ -240,10 +265,45 @@ private <T> void toObjectNodes(
applyAttributeValueFields(object, objectNode, paths);
applyTransformers(objectNode, null, "", fieldTransformers);

if (excludeDefaults) removeEmptyObjects(objectNode);

consumer.accept(objectNode);
}
}

/**
* Method that removes empty objects from an ObjectNode, at root level.
*
* <p>e.g. json input: <br>
* <code>
* {
* "name": "dhis2",
* "system": {}
* }
* </code>
*
* <p><br>
*
* <p>resulting output: <br>
* <code>
* {
* "name": "dhis2"
* }
* </code>
*
* @param objectNode object node to process on
*/
private void removeEmptyObjects(ObjectNode objectNode) {
Iterator<JsonNode> elements = objectNode.elements();

while (elements.hasNext()) {
JsonNode next = elements.next();
if (next.isObject() && next.isEmpty()) {
elements.remove();
}
}
}

/**
* Streams filtered object nodes using given JsonGenerator.
*
Expand All @@ -253,7 +313,8 @@ private <T> void toObjectNodes(
* to the generator
*/
@Transactional(readOnly = true)
public void toObjectNodesStream(FieldFilterParams<?> params, JsonGenerator generator)
public void toObjectNodesStream(
FieldFilterParams<?> params, boolean excludeDefaults, JsonGenerator generator)
throws IOException {
if (params.getObjects().isEmpty()) {
return;
Expand All @@ -266,6 +327,7 @@ public void toObjectNodesStream(FieldFilterParams<?> params, JsonGenerator gener
fieldPaths,
params.getUser(),
params.isSkipSharing(),
excludeDefaults,
n -> {
try {
generator.writeObject(n);
Expand Down Expand Up @@ -370,10 +432,11 @@ private void applyTransformers(
}

private SimpleFilterProvider getSimpleFilterProvider(
List<FieldPath> fieldPaths, boolean skipSharing) {
List<FieldPath> fieldPaths, boolean skipSharing, boolean excludeDefaults) {
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider.addFilter(
"field-filter", new FieldFilterSimpleBeanPropertyFilter(fieldPaths, skipSharing));
"field-filter",
new FieldFilterSimpleBeanPropertyFilter(fieldPaths, skipSharing, excludeDefaults));

return filterProvider;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.hisp.dhis.common.SystemDefaultMetadataObject;
import org.hisp.dhis.scheduling.JobParameters;
import org.hisp.dhis.system.util.AnnotationUtils;

Expand All @@ -58,6 +59,7 @@ public class FieldFilterSimpleBeanPropertyFilter extends SimpleBeanPropertyFilte
private final List<FieldPath> fieldPaths;

private final boolean skipSharing;
private final boolean excludeDefaults;

/** Cache that contains true/false for classes that should always be expanded. */
private static final Map<Class<?>, Boolean> ALWAYS_EXPAND_CACHE = new ConcurrentHashMap<>();
Expand All @@ -72,7 +74,7 @@ protected boolean include(final PropertyWriter writer) {
return true;
}

protected boolean include(final PropertyWriter writer, final JsonGenerator jgen) {
protected boolean include(final PropertyWriter writer, final JsonGenerator jgen, Object object) {
PathContext ctx = getPath(writer, jgen);

if (ctx.getCurrentValue() == null) {
Expand All @@ -83,6 +85,11 @@ protected boolean include(final PropertyWriter writer, final JsonGenerator jgen)
log.debug(ctx.getCurrentValue().getClass().getSimpleName() + ": " + ctx.getFullPath());
}

if (excludeDefaults && (object instanceof SystemDefaultMetadataObject)) {
SystemDefaultMetadataObject sdmo = (SystemDefaultMetadataObject) object;
if (sdmo.isDefault()) return false;
}

if (skipSharing
&& StringUtils.equalsAny(
ctx.getFullPath(),
Expand Down Expand Up @@ -146,7 +153,7 @@ private PathContext getPath(PropertyWriter writer, JsonGenerator jgen) {
public void serializeAsField(
Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer)
throws Exception {
if (include(writer, jgen)) {
if (include(writer, jgen, pojo)) {
writer.serializeAsField(pojo, jgen, provider);
} else if (!jgen.canOmitFields()) { // since 2.3
writer.serializeAsOmittedField(pojo, jgen, provider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,9 @@ public enum Defaults {
* Remove defaults from nodes. Roots will not be included, collections which contains default will
* have them removed, 1-to-1 mappings will have them set to null.
*/
EXCLUDE
EXCLUDE;

public boolean isExclude() {
return this.name().equals("EXCLUDE");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,8 @@ default JsonList<JsonCategory> getCategories() {
default DimensionType getDimensionType() {
return getString("dimensionType").parsed(DimensionType::valueOf);
}

default JsonList<JsonCategoryOptionCombo> getCategoryOptionCombos() {
return getList("categoryOptionCombos", JsonCategoryOptionCombo.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,8 @@ default AggregationType getAggregationType() {
default JsonOptionSet getOptionSet() {
return get("optionSet", JsonOptionSet.class);
}

default JsonCategoryCombo getCategoryCombo() {
return has("categoryCombo") ? get("categoryCombo", JsonCategoryCombo.class) : null;
}
}
Loading
Loading