unmarshalledProperties = new HashMap<>();
+
+ Optional.ofNullable(properties)
.map(Arrays::asList)
.orElse(Collections.emptyList())
.stream()
- .filter(adaptedProp -> adaptedProp.getType() != null)
- .filter(adaptedProp -> xmlPropertyAdapters.containsKey((adaptedProp.getType())))
- .collect(Collectors.toMap(
- adaptedProp -> adaptedProp.getName(),
- adaptedProp -> {
- final XmlPropertyAdapter xmlPropertyAdapter = xmlPropertyAdapters.get(adaptedProp.getType());
- return xmlPropertyAdapter.unmarshallValues(adaptedProp);
- }));
+ .filter(adaptedProp -> adaptedProp.getType() == null || xmlPropertyAdapters.containsKey((adaptedProp.getType())))
+ .forEach(adaptedProp -> unmarshalledProperties.put(adaptedProp.getName(), unmarshalProperty(adaptedProp)));
+
+ // This was a better way to do it, but Collectors.toMap does not accept `null` values.
+ // See Collectors#153 for reference.
+ // .collect(Collectors.toMap(
+ // adaptedProp -> adaptedProp.getName(),
+ // adaptedProp -> {
+ // final XmlPropertyAdapter xmlPropertyAdapter = xmlPropertyAdapters.get(adaptedProp.getType());
+ // return xmlPropertyAdapter.unmarshallValues(adaptedProp);
+ // }));
+
+ return unmarshalledProperties;
+ }
+
+ /**
+ * It unmarshal the given {@link XmlPropertyAdapted}.
+ *
+ * If {@link XmlPropertyAdapted#getType()} is {@code null} it means that {@link XmlPropertyAdapted#getValues()} was {@code null}, so we can't determine its {@link XmlPropertyAdapted#getType()}.
+ * By the way, if original value was {@code null} we can safely return {@code null}.
+ *
+ * @param adaptedProp The {@link XmlPropertyAdapted} to unmarshal
+ * @return The unmarshalled {@link XmlPropertyAdapted}
+ * @since 2.1.0
+ */
+ public Object unmarshalProperty(V adaptedProp) {
+ if (adaptedProp.getType() != null) {
+ XmlPropertyAdapter xmlPropertyAdapter = xmlPropertyAdapters.get(adaptedProp.getType());
+ return xmlPropertyAdapter.unmarshallValues(adaptedProp);
+ }
+ else {
+ return null;
+ }
}
@Override
@@ -57,23 +85,28 @@ public V[] marshal(Map props) {
.orElse(Collections.emptyMap())
.entrySet()
.stream()
- .filter(nameAndValue -> nameAndValue.getValue() != null)
.map(nameAndValue -> {
- final Object value = nameAndValue.getValue();
final V resEntry = adaptedPropertyFactory.get();
resEntry.setName(nameAndValue.getKey());
- xmlPropertyAdapters
- .entrySet()
- .stream()
- .filter(pa -> pa.getValue().canMarshall(value.getClass()))
- .findFirst()
- .ifPresent(typeToAdapter -> {
- resEntry.setType(typeToAdapter.getKey());
- typeToAdapter.getValue().marshallValues(resEntry, value);
- });
+
+ // Some properties can be sent as `null` so we cannot determine the type by the value.
+ if (nameAndValue.getValue() != null) {
+ final Object value = nameAndValue.getValue();
+ xmlPropertyAdapters
+ .entrySet()
+ .stream()
+ .filter(pa -> pa.getValue().canMarshall(value.getClass()))
+ .findFirst()
+ .ifPresent(typeToAdapter -> {
+ resEntry.setType(typeToAdapter.getKey());
+ typeToAdapter.getValue().marshallValues(resEntry, value);
+ });
+ }
+
return resEntry;
})
.collect(Collectors.toList());
+
return adaptedProperties.toArray((V[]) Array.newInstance(propertyClass, adaptedProperties.size()));
}
}
diff --git a/service/api/src/test/java/org/eclipse/kapua/service/config/ServiceXmlConfigPropertiesAdapterTest.java b/service/api/src/test/java/org/eclipse/kapua/service/config/ServiceXmlConfigPropertiesAdapterTest.java
index 5e52e31f768..21b48305b6b 100644
--- a/service/api/src/test/java/org/eclipse/kapua/service/config/ServiceXmlConfigPropertiesAdapterTest.java
+++ b/service/api/src/test/java/org/eclipse/kapua/service/config/ServiceXmlConfigPropertiesAdapterTest.java
@@ -90,6 +90,7 @@ public void unmarshalTest() throws Exception {
ServiceXmlConfigPropertiesAdapter instance = new ServiceXmlConfigPropertiesAdapter();
+ Map expectedProperty0 = new HashMap<>();
Map expectedProperty1 = new HashMap<>();
Map expectedProperty2 = new HashMap<>();
Map expectedProperty3 = new HashMap<>();
@@ -98,33 +99,37 @@ public void unmarshalTest() throws Exception {
Map expectedProperty6 = new HashMap<>();
Map expectedProperty7 = new HashMap<>();
Map expectedProperty8 = new HashMap<>();
- Map expectedProperty9 = new HashMap<>();
- Map expectedProperty10 = new HashMap<>();
- expectedProperty2.put("name1", new String[]{"47", "10"});
- expectedProperty3.put("name2", new Long[]{47l, 10l});
- expectedProperty4.put("name3", new Double[]{47d, 10d});
- expectedProperty5.put("name4", new Float[]{47f, 10f});
- expectedProperty6.put("name5", new Integer[]{47, 10});
- expectedProperty7.put("name6", new Byte[]{(byte) 47, (byte) 10});
- expectedProperty8.put("name7", new Character[]{'4', '1'});
- expectedProperty9.put("name8", new Boolean[]{false, false});
- expectedProperty10.put("name9", new Short[]{(short) 47, (short) 10});
- expectedProperties = new Map[]{expectedProperty1, expectedProperty2, expectedProperty3, expectedProperty4, expectedProperty5, expectedProperty6, expectedProperty7, expectedProperty8, expectedProperty9, expectedProperty10};
+ expectedProperty0.put("name0", new String[]{"47", "10"});
+ expectedProperty1.put("name1", new Long[]{47l, 10l});
+ expectedProperty2.put("name2", new Double[]{47d, 10d});
+ expectedProperty3.put("name3", new Float[]{47f, 10f});
+ expectedProperty4.put("name4", new Integer[]{47, 10});
+ expectedProperty5.put("name5", new Byte[]{(byte) 47, (byte) 10});
+ expectedProperty6.put("name6", new Character[]{'4', '1'});
+ expectedProperty7.put("name7", new Boolean[]{false, false});
+ expectedProperty8.put("name8", new Short[]{(short) 47, (short) 10});
+ expectedProperties = new Map[]{expectedProperty0, expectedProperty1, expectedProperty2, expectedProperty3, expectedProperty4, expectedProperty5, expectedProperty6, expectedProperty7, expectedProperty8};
String name = "name";
String stringValue1 = "47";
String stringValue2 = "10";
String[] stringValue = {stringValue1, stringValue2};
- ConfigPropertyType[] configPropertyType = {null, ConfigPropertyType.stringType, ConfigPropertyType.longType,
- ConfigPropertyType.doubleType, ConfigPropertyType.floatType, ConfigPropertyType.integerType,
- ConfigPropertyType.byteType, ConfigPropertyType.charType, ConfigPropertyType.booleanType,
+ ConfigPropertyType[] configPropertyType = {
+ ConfigPropertyType.stringType,
+ ConfigPropertyType.longType,
+ ConfigPropertyType.doubleType,
+ ConfigPropertyType.floatType,
+ ConfigPropertyType.integerType,
+ ConfigPropertyType.byteType,
+ ConfigPropertyType.charType,
+ ConfigPropertyType.booleanType,
ConfigPropertyType.shortType};
ServiceXmlConfigPropertiesAdapted serviceXmlConfigPropertiesAdapted = new ServiceXmlConfigPropertiesAdapted();
for (int i = 0; i < configPropertyType.length; i++) {
ServiceXmlConfigPropertyAdapted serviceXmlConfigPropertyAdapted1 = new ServiceXmlConfigPropertyAdapted();
ServiceXmlConfigPropertyAdapted serviceXmlConfigPropertyAdapted2 = new ServiceXmlConfigPropertyAdapted(name + i, configPropertyType[i], stringValue);
- ServiceXmlConfigPropertyAdapted[] properties1 = new ServiceXmlConfigPropertyAdapted[]{serviceXmlConfigPropertyAdapted1, serviceXmlConfigPropertyAdapted2};
+ ServiceXmlConfigPropertyAdapted[] properties1 = new ServiceXmlConfigPropertyAdapted[]{serviceXmlConfigPropertyAdapted2};
Assert.assertThat("Instance of Map expected.", instance.unmarshal(serviceXmlConfigPropertiesAdapted), IsInstanceOf.instanceOf(Map.class));
diff --git a/service/device/call/kura/src/main/java/org/eclipse/kapua/service/device/call/kura/model/configuration/xml/KuraPasswordPropertyAdapter.java b/service/device/call/kura/src/main/java/org/eclipse/kapua/service/device/call/kura/model/configuration/xml/KuraPasswordPropertyAdapter.java
index dc4130380ce..c0304bcf36f 100644
--- a/service/device/call/kura/src/main/java/org/eclipse/kapua/service/device/call/kura/model/configuration/xml/KuraPasswordPropertyAdapter.java
+++ b/service/device/call/kura/src/main/java/org/eclipse/kapua/service/device/call/kura/model/configuration/xml/KuraPasswordPropertyAdapter.java
@@ -12,6 +12,7 @@
*******************************************************************************/
package org.eclipse.kapua.service.device.call.kura.model.configuration.xml;
+import com.google.common.base.Strings;
import org.eclipse.kapua.commons.crypto.CryptoUtil;
import org.eclipse.kapua.model.xml.XmlPropertyAdapted;
import org.eclipse.kapua.model.xml.adapters.ClassBasedXmlPropertyAdapterBase;
@@ -43,19 +44,61 @@ public String marshallValue(Object value) {
return cryptoUtil.encodeBase64(value.toString());
}
+ @Override
+ public boolean canUnmarshallEmptyString() {
+ return true;
+ }
+
@Override
public KuraPassword unmarshallValue(String value) {
return new KuraPassword(cryptoUtil.decodeBase64(value));
}
+
+ /**
+ * Unmarshalls the given value according to {@link XmlPropertyAdapted#isEncrypted()}.
+ *
+ * @param value The value to unmarshall.
+ * @param isEncrypted The {@link XmlPropertyAdapted#isEncrypted()}.
+ * @return The unmarshalled {@link KuraPassword}
+ * @since 2.1.0
+ */
+ public KuraPassword unmarshallValue(String value, boolean isEncrypted) {
+ return isEncrypted ? unmarshallValue(value) : new KuraPassword(value);
+ }
+
@Override
public Object unmarshallValues(XmlPropertyAdapted> property) {
if (!property.getArray()) {
- return property.isEncrypted() ? unmarshallValue(property.getValues()[0]) : new KuraPassword(property.getValues()[0]);
+ String[] values = property.getValues();
+
+ // Values might not have been defined
+ // ie:
+ //
+ //
+ //
+ if (values == null || values.length == 0) {
+ return null;
+ }
+
+ String value = property.getValues()[0];
+ return unmarshallValue(value, property.isEncrypted() && !Strings.isNullOrEmpty(value));
+
} else {
+ String[] values = property.getValues();
+
+ // Values might not have been defined
+ // ie:
+ //
+ //
+ //
+ if (values == null) {
+ return null;
+ }
+
return Arrays
.stream(property.getValues())
- .map(value -> property.isEncrypted() ? unmarshallValue(value) : new KuraPassword(value))
+ .map(value -> unmarshallValue(value, property.isEncrypted() && !Strings.isNullOrEmpty(value)))
.collect(Collectors.toList()).toArray();
}
}