Skip to content

Commit

Permalink
represent arrays from JSON as arrays in map representation
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanseifert committed Jan 10, 2024
1 parent 5dfa38d commit 886af8b
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Dictionary;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand All @@ -37,8 +38,8 @@
import org.apache.sling.provisioning.model.Section;
import org.jetbrains.annotations.Nullable;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.MapType;

import io.wcm.devops.conga.plugins.sling.postprocessor.JsonOsgiConfigPostProcessor;

Expand All @@ -48,9 +49,7 @@
public final class JsonOsgiConfigUtil {

private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final TypeReference<Map<String, Object>> MAP_TYPE_REFERENCE = new TypeReference<Map<String, Object>>() {
// default implementation
};
private static final MapType MAP_TYPE = OBJECT_MAPPER.getTypeFactory().constructMapType(Map.class, String.class, Object.class);

private static final Pattern KEY_PATTERN_CONFIGURATIONS = Pattern.compile("^configurations(:(.*))?$");
private static final Pattern KEY_PATTERN_REPOINIT = Pattern.compile("^repoinit(:(.*))?$");
Expand All @@ -68,7 +67,29 @@ private JsonOsgiConfigUtil() {
*/
static Map<String, Object> readToMap(File file) throws IOException {
String jsonString = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
return OBJECT_MAPPER.readValue(jsonString, MAP_TYPE_REFERENCE);
Map<String, Object> result = OBJECT_MAPPER.readValue(jsonString, MAP_TYPE);
return convertListsToArrays(result);
}

/**
* Jackson converts arrays in JSON to lists. We want to keep them represented as arrays for conversion
* to OSGi configuration, so we convert them recursively back to Object[] arrays.
*/
@SuppressWarnings("unchecked")
private static Map<String, Object> convertListsToArrays(Map<String, Object> map) {
Map<String, Object> result = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof Collection) {
value = ((Collection)value).toArray();
}
else if (value instanceof Map) {
value = convertListsToArrays((Map<String, Object>)value);
}
result.put(key, value);
}
return result;
}

/**
Expand Down Expand Up @@ -108,9 +129,9 @@ private static void processEntry(Feature feature, String key, Object value) thro
else {
Matcher repoinitKeyMatcher = KEY_PATTERN_REPOINIT.matcher(key);
if (repoinitKeyMatcher.matches()) {
if (value instanceof Collection) {
if (value.getClass().isArray()) {
String[] runModes = toRunModes(repoinitKeyMatcher.group(RUNMODES_INDEX));
processRepoInit(feature, runModes, (Collection<String>)value);
processRepoInit(feature, runModes, (Object[])value);
}
else {
throw new IOException("Unexpected data for key " + key + ": " + value.getClass().getName());
Expand Down Expand Up @@ -155,7 +176,7 @@ private static void processOsgiConfiguration(Feature feature, String[] runModes,
/**
* Convert repoinit statements to Provisioning model additional sections with associated run modes.
*/
private static void processRepoInit(Feature feature, String[] runModes, Collection<String> repoinits) {
private static void processRepoInit(Feature feature, String[] runModes, Object[] repoinits) {
Section section = new Section(ProvisioningUtil.REPOINIT_SECTION);
feature.getAdditionalSections().add(section);
if (runModes != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Dictionary;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.felix.cm.json.io.Configurations;
Expand Down Expand Up @@ -72,7 +71,9 @@ void testJsonFile() throws Exception {
// validate generated configs
Dictionary<?, ?> config = readConfig("my.pid.cfg.json");
assertEquals("value1", config.get("stringProperty"));
assertEquals(List.of("v1", "v2", "v3"), config.get("stringArrayProperty"));
assertArrayEquals(new String[] {
"v1", "v2", "v3"
}, (String[])config.get("stringArrayProperty"));
assertEquals(true, config.get("booleanProperty"));
assertEquals(999999999999L, config.get("longProperty"));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,29 @@
*/
package io.wcm.devops.conga.plugins.sling.util;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.Test;

class JsonOsgiConfigUtilTest {

@Test
@SuppressWarnings("unchecked")
void testReadToMap() throws IOException {
Map<String, Object> content = JsonOsgiConfigUtil.readToMap(new File("src/test/resources/osgi-config-json/sample.osgiconfig.json"));
assertEquals(List.of("create service user mode1"), content.get("repoinit:mode1"));
assertArrayEquals(new Object[] { "create service user mode1" }, (Object[])content.get("repoinit:mode1"));

// assert JSON arrays are represented as array in map instead of list
Map<String, Object> configurations = (Map<String, Object>)content.get("configurations");
Map<String, Object> my_pid = (Map<String, Object>)configurations.get("my.pid");
Object stringArrayProperty = my_pid.get("stringArrayProperty");
assertTrue(stringArrayProperty.getClass().isArray());
assertArrayEquals(new Object[] { "v1", "v2", "v3" }, (Object[])stringArrayProperty);
}

}

0 comments on commit 886af8b

Please sign in to comment.