Bug 574565 - NPE in ContextService if some attributes are not set Signed-off-by: Matthias Koller <m.koller@peak-solution.de>
diff --git a/api/base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntityFactory.java b/api/base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntityFactory.java index 6d78c47..2c64c42 100644 --- a/api/base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntityFactory.java +++ b/api/base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntityFactory.java
@@ -116,7 +116,7 @@ return channelGroup; } - + /** * Creates a new {@link Measurement}. *
diff --git a/nucleus/businessobjects/src/main/java/org/eclipse/mdm/businessobjects/service/ContextService.java b/nucleus/businessobjects/src/main/java/org/eclipse/mdm/businessobjects/service/ContextService.java index 91de510..195bf38 100644 --- a/nucleus/businessobjects/src/main/java/org/eclipse/mdm/businessobjects/service/ContextService.java +++ b/nucleus/businessobjects/src/main/java/org/eclipse/mdm/businessobjects/service/ContextService.java
@@ -50,6 +50,8 @@ import org.eclipse.mdm.businessobjects.utils.Serializer; import org.eclipse.mdm.businessobjects.utils.ServiceUtils; import org.eclipse.mdm.connector.boundary.ConnectorService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.Strings; @@ -58,6 +60,8 @@ import io.vavr.collection.HashMap; import io.vavr.collection.List; import io.vavr.collection.Map; +import io.vavr.control.Option; +import io.vavr.control.Option.None; import io.vavr.control.Option.Some; import io.vavr.control.Try; @@ -70,6 +74,8 @@ @Stateless public class ContextService { + private static final Logger LOGGER = LoggerFactory.getLogger(ContextService.class); + @Inject private ConnectorService connectorService; @@ -380,7 +386,7 @@ private DescribableContexts updateContext(TestStep testStep, Try<Map<String, Object>> contextMap, ContextType[] contextTypes) { - Map<ContextType, Object> orderedMap = contextMap.get().get(ContextActivity.CONTEXT_GROUP_ORDERED) + Map<ContextType, Object> orderedMap = convertNullValueToNone(contextMap.get().get(ContextActivity.CONTEXT_GROUP_ORDERED)) .map(this::transformMap).getOrElse(HashMap.empty()) .mapKeys(t -> ServiceUtils.getContextTypeSupplier(t).get()) .filterKeys(t -> Arrays.asList(contextTypes).contains(t)); @@ -389,7 +395,7 @@ ec.setTestStep(testStep); ec.setOrdered(updateContextDescribableContext(testStep, orderedMap, contextTypes)); - Map<ContextType, Object> measuredMap = contextMap.get().get(ContextActivity.CONTEXT_GROUP_MEASURED) + Map<ContextType, Object> measuredMap = convertNullValueToNone(contextMap.get().get(ContextActivity.CONTEXT_GROUP_MEASURED)) .map(this::transformMap).getOrElse(HashMap.empty()) .mapKeys(t -> ServiceUtils.getContextTypeSupplier(t).get()) .filterKeys(t -> Arrays.asList(contextTypes).contains(t)); @@ -558,24 +564,52 @@ public MDMContextEntity transformToMDMEntity(Map<String, Object> component) { return new MDMContextEntity( - component.get("name").map(Object::toString) - .getOrElseThrow(() -> new MDMEntityAccessException("Missing attribute 'name' in MDMEntity")), - component.get("id").map(Object::toString).getOrElse(""), - component.get("type").map(Object::toString).getOrElse(""), - component.get("sourceType").map(Object::toString).getOrElse(""), - component.get("sourceName").map(Object::toString).getOrElse(""), - transformList(component.get("attributes").getOrElseThrow( + getValueOrException(component, "name"), + getValue(component, "id"), + getValue(component, "type"), + getValue(component, "sourceType"), + getValue(component, "sourceName"), + transformList(convertNullValueToNone(component.get("attributes")).getOrElseThrow( () -> new MDMEntityAccessException("Missing attribute 'attributes' in MDMEntity"))) .map(this::transformMap) .map(m -> new MDMContextAttribute( - m.get("name").map(Object::toString) - .getOrElseThrow(() -> new MDMEntityAccessException( - "Missing attribute 'name' in MDMAttribute")), - m.get("value").map(Object::toString) - .getOrElseThrow(() -> new MDMEntityAccessException( - "Missing attribute 'value' in MDMAttribute")), - m.get("unit").map(Object::toString).getOrElse(""), - m.get("datatype").map(Object::toString).getOrElse(""), null, null, null, null)) + getValueOrException(m, "name"), + getValueOrException(m, "value"), + getValue(m, "unit"), + getValue(m, "datatype"), null, null, null, null)) .toJavaList()); } + + /** + * Check if the option contains null an converts the option to None. Else returns the given option + * @param <T> + * @param option + * @return None if Some(null) is given else option + */ + private <T> Option<T> convertNullValueToNone(Option<T> option) { + if (option.contains(null)) { + return Option.none(); + } else { + return option; + } + } + + private String getValue(Map<String, Object> component, String attributeName) { + if (component.get(attributeName).contains(null)) { + LOGGER.debug("{} is null.", attributeName); + return ""; + } else { + return component.get(attributeName).map(Object::toString).getOrElse(""); + } + } + + private String getValueOrException(Map<String, Object> component, String attributeName) { + if (component.get(attributeName).contains(null)) { + LOGGER.debug("{} is null.", attributeName); + throw new MDMEntityAccessException("Attribute '" + attributeName + "' in " + component + " is null."); + } else { + return component.get(attributeName).map(Object::toString).getOrElseThrow(() -> new MDMEntityAccessException( + "Missing attribute '" + attributeName + "' in " + component)); + } + } }