mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2024-11-30 12:34:01 -06:00
automatically convert ParameterMap entries to JSON
This commit is contained in:
parent
308f26e220
commit
cce97d1c89
@ -16,13 +16,14 @@
|
||||
|
||||
package io.nosqlbench.engine.api.activityimpl;
|
||||
|
||||
import io.nosqlbench.nb.api.config.params.ParamsParser;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import io.nosqlbench.engine.api.util.Unit;
|
||||
|
||||
import io.nosqlbench.nb.api.config.params.ParamsParser;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.proxy.ProxyObject;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import java.util.*;
|
||||
@ -44,6 +45,7 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class ParameterMap extends ConcurrentHashMap<String,Object> implements Bindings, ProxyObject {
|
||||
private final static Logger logger = LogManager.getLogger("PARAMS");
|
||||
private final static Gson gson = new GsonBuilder().create();
|
||||
|
||||
|
||||
// private final ConcurrentHashMap<String, String> paramMap = new ConcurrentHashMap<>(10);
|
||||
@ -200,7 +202,15 @@ public class ParameterMap extends ConcurrentHashMap<String,Object> implements Bi
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends Object> toMerge) {
|
||||
for (Entry<? extends String, ? extends Object> entry : toMerge.entrySet()) {
|
||||
super.put(entry.getKey(),String.valueOf(entry.getValue()));
|
||||
|
||||
Object raw = entry.getValue();
|
||||
String value = null;
|
||||
if (raw instanceof Map || raw instanceof Set || raw instanceof List) {
|
||||
value = gson.toJson(raw);
|
||||
} else {
|
||||
value = raw.toString();
|
||||
}
|
||||
super.put(entry.getKey(), value);
|
||||
}
|
||||
markMutation();
|
||||
}
|
||||
|
@ -78,6 +78,9 @@ public interface Element {
|
||||
* defined at the root level, so it is what will be found first. All implementations
|
||||
* should ensure that this order is preserved.</p>
|
||||
*
|
||||
* <p>This method requires a type which will be given to the underlying {@link ElementData}
|
||||
* implementation for contextual type conversion.</p>
|
||||
*
|
||||
* @param name The simple or hierarchic variable name to resolve
|
||||
* @param classOfT The type of value which the resolved value is required to be assignable to
|
||||
* @param <T> The value type parameter
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
package io.nosqlbench.nb.api.config.params;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -28,6 +31,25 @@ import java.util.Set;
|
||||
*/
|
||||
public interface ElementData {
|
||||
String NAME = "name";
|
||||
List<Class<?>> COMMON_TYPES = List.of(
|
||||
String.class,
|
||||
byte.class, Byte.class,
|
||||
short.class, Short.class,
|
||||
int.class, Integer.class,
|
||||
long.class, Long.class,
|
||||
double.class, Double.class,
|
||||
float.class, Float.class,
|
||||
Map.class, Set.class, List.class
|
||||
);
|
||||
|
||||
static Optional<Object> asCommonType(Object src) {
|
||||
for (Class<?> commonType : COMMON_TYPES) {
|
||||
if (commonType.isAssignableFrom(src.getClass())) {
|
||||
return Optional.of(commonType.cast(src));
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Object get(String name);
|
||||
|
||||
@ -110,4 +132,23 @@ public interface ElementData {
|
||||
return get(name,type);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get the value for the key, but ensure that the type of value that is returned
|
||||
* is in one of the sanctioned {@link #COMMON_TYPES}.
|
||||
*
|
||||
* <p>If possible, the value provided should be a wrapper type around the actual backing
|
||||
* type, such that mutability is preserved.</p>
|
||||
*
|
||||
* <p>If the backing type is a structured type object graph which defies direct
|
||||
* conversion to one of the types above, then an error should be thrown.</p>
|
||||
*
|
||||
* <p>If the type is a collection type, then type conversion should be provided all the way
|
||||
* down to each primitive value.</p>
|
||||
*
|
||||
* <p>If no value by the given name exists, the null should be returned.</p>
|
||||
*
|
||||
* @param key The key of the value to retrieve
|
||||
* @return The value as a Java primitive, Boxed primitive, or Set, List, or Map of String to Object.
|
||||
*/
|
||||
Object getAsCommon(String key);
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ public class ElementImpl implements Element {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
|
||||
for (String key : keys) {
|
||||
Object value = this.data.get(key);
|
||||
Object value = this.data.getAsCommon(key);
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ package io.nosqlbench.nb.api.config.params;
|
||||
|
||||
import com.google.gson.*;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
public class JsonBackedConfigElement implements ElementData {
|
||||
|
||||
@ -62,6 +62,79 @@ public class JsonBackedConfigElement implements ElementData {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAsCommon(String key) {
|
||||
Object found = get(key);
|
||||
if (found==null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Optional<Object> converted = ElementData.asCommonType(found);
|
||||
if (converted.isPresent()) {
|
||||
return converted.get();
|
||||
}
|
||||
|
||||
if (found instanceof JsonObject jo) {
|
||||
Map<String,Object> values = new LinkedHashMap<>();
|
||||
for (String s : jo.keySet()) {
|
||||
values.put(s, toCommon(jo.get(s)));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
return toCommon(found);
|
||||
}
|
||||
|
||||
public Object toCommon(Object srcValue) {
|
||||
Optional<Object> standards = ElementData.asCommonType(srcValue);
|
||||
if (standards.isPresent()) {
|
||||
return Optional.of(standards);
|
||||
}
|
||||
|
||||
if (srcValue instanceof JsonElement e) {
|
||||
if (e.isJsonPrimitive()) {
|
||||
JsonPrimitive jp = e.getAsJsonPrimitive();
|
||||
if (jp.isBoolean()) {
|
||||
return jp.getAsBoolean();
|
||||
} else if (jp.isNumber()) {
|
||||
Number number = jp.getAsNumber();
|
||||
return number.doubleValue();
|
||||
} else if (jp.isString()) {
|
||||
return jp.getAsString();
|
||||
} else if (jp.isJsonNull()) {
|
||||
return null;
|
||||
} else {
|
||||
throw new RuntimeException("Unknown JSON primitive type for element: '" +
|
||||
e
|
||||
+ "' type:'"
|
||||
+e.getClass().getCanonicalName()+"'"
|
||||
);
|
||||
}
|
||||
} else if (e.isJsonObject()) {
|
||||
JsonObject jo = e.getAsJsonObject();
|
||||
Map<String,Object> valueMap = new LinkedHashMap<>();
|
||||
for (String s : jo.keySet()) {
|
||||
valueMap.put(s, toCommon(jo.get(s)));
|
||||
}
|
||||
return valueMap;
|
||||
} else if (e.isJsonArray()) {
|
||||
List<Object> valueList = new ArrayList<>();
|
||||
JsonArray ja = e.getAsJsonArray();
|
||||
for (JsonElement jsonElement : ja) {
|
||||
valueList.add(toCommon(jsonElement));
|
||||
}
|
||||
return valueList;
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Error traversing JSONElement structure. Unknown type: '"
|
||||
+ srcValue.getClass().getCanonicalName()
|
||||
+ "'");
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unable to convert value type from '"
|
||||
+ srcValue.getClass().getCanonicalName() + "' to a common type.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getGivenName() + "(" + (extractElementName()!=null ? extractElementName() : "null" ) +"):" + jsonObject.toString();
|
||||
@ -74,4 +147,6 @@ public class JsonBackedConfigElement implements ElementData {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
package io.nosqlbench.nb.api.config.params;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
public class MapBackedElement implements ElementData {
|
||||
@ -49,6 +50,20 @@ public class MapBackedElement implements ElementData {
|
||||
return this.elementName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAsCommon(String key) {
|
||||
Object found = get(key);
|
||||
if (found==null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Optional<Object> converted = ElementData.asCommonType(found);
|
||||
if (converted.isPresent()) {
|
||||
return converted.get();
|
||||
}
|
||||
throw new RuntimeException("Unable to convert type '" + found.getClass().getCanonicalName() + "' to a common type.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getGivenName() + "(" + (this.extractElementName() != null ? this.extractElementName() : "null") + "):" + map.toString();
|
||||
|
@ -122,5 +122,74 @@ public class NBParamsTest {
|
||||
assertThat(e.get("a5.b5")).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedJsonObjectsToCommonTypes() {
|
||||
String maxdouble = String.valueOf(Double.MAX_VALUE);
|
||||
String maxfloat = String.valueOf(Float.MAX_VALUE);
|
||||
|
||||
var json = """
|
||||
{
|
||||
"level1key1": {
|
||||
"level2key1": {
|
||||
"afloat": %s
|
||||
}
|
||||
}
|
||||
}
|
||||
""".formatted("thisisit");
|
||||
|
||||
Element elements = NBParams.one(json);
|
||||
Map<String, Object> commonform = elements.getMap();
|
||||
assertThat(commonform).isEqualTo(
|
||||
Map.of(
|
||||
"level1key1", Map.of(
|
||||
"level2key1", Map.of(
|
||||
"afloat", "thisisit"
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedJsonObjectsToCommonTypesDeep() {
|
||||
|
||||
var json = """
|
||||
{
|
||||
"level1key1": {
|
||||
"level2key1": {
|
||||
"anint": %s,
|
||||
"along": %s
|
||||
},
|
||||
"level2key2": {
|
||||
"alist": ["a","b","c"],
|
||||
"abool": true
|
||||
}
|
||||
},
|
||||
"level1key2": {
|
||||
"name": "myname"
|
||||
}
|
||||
}
|
||||
""".formatted(3,4L);
|
||||
|
||||
Element elements = NBParams.one(json);
|
||||
Map<String, Object> commonform = elements.getMap();
|
||||
assertThat(commonform).isEqualTo(
|
||||
Map.of(
|
||||
"level1key1", Map.of(
|
||||
"level2key1", Map.of(
|
||||
"anint", 3.0d,
|
||||
"along", 4.0d
|
||||
),
|
||||
"level2key2", Map.of(
|
||||
"alist",List.of("a","b","c"),
|
||||
"abool",true
|
||||
)
|
||||
),
|
||||
"level1key2", Map.of(
|
||||
"name","myname"
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user