Fix required config validation 20/84320/1
authoremartin <ephraim.martin@est.tech>
Fri, 5 Apr 2019 09:51:13 +0000 (09:51 +0000)
committeremartin <ephraim.martin@est.tech>
Fri, 5 Apr 2019 09:51:13 +0000 (09:51 +0000)
*Nested objects and list validation

Change-Id: Icf615a610dd6e669d66ae07adc1316ca167a671b
Issue-ID: DCAEGEN2-1327
Signed-off-by: emartin <ephraim.martin@est.tech>
src/main/java/org/onap/dcaegen2/services/pmmapper/model/MeasFilterConfig.java
src/main/java/org/onap/dcaegen2/services/pmmapper/utils/RequiredFieldDeserializer.java
src/test/java/org/onap/dcaegen2/pmmapper/config/ConfigHandlerTests.java
src/test/resources/incomplete_mapper_config.json [deleted file]

index 0f1aaa9..a7d211f 100644 (file)
@@ -33,6 +33,7 @@ import org.onap.dcaegen2.services.pmmapper.utils.GSONRequired;
 @NoArgsConstructor\r
 public class MeasFilterConfig {\r
 \r
+  @GSONRequired\r
   @SerializedName("filters")\r
   public List<Filter> filters;\r
 \r
index e956398..258b831 100644 (file)
@@ -25,8 +25,13 @@ import com.google.gson.JsonDeserializer;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonParseException;
 
+import lombok.NonNull;
+
 import java.lang.reflect.Field;
 import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
 
 
 /**
@@ -38,20 +43,35 @@ public class RequiredFieldDeserializer<T> implements JsonDeserializer<T> {
     @Override
     public T deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
         T obj = new Gson().fromJson(jsonElement, type);
-        for (Field field : obj.getClass().getDeclaredFields()) {
-            if (field.getAnnotation(GSONRequired.class) != null) {
-                field.setAccessible(true);
-                try {
-                    if (field.get(obj) == null) {
-                        throw new JsonParseException(String.format("Field: '%s', is required but not found.", field.getName()));
-                    }
-                } catch (Exception exception) {
-                    throw new JsonParseException("Failed to check fields.", exception);
-                }
+        validateRequiredFields(obj.getClass().getDeclaredFields(), obj);
+        return obj;
+    }
+
+    private void validateRequiredFields(@NonNull Field[] fields, @NonNull Object pojo) {
+        if (pojo instanceof List) {
+            final List<?> pojoList = (List<?>) pojo;
+            for (final Object pojoListPojo : pojoList) {
+                validateRequiredFields(pojoListPojo.getClass().getDeclaredFields(), pojoListPojo);
             }
         }
 
-        return obj;
+        Stream.of(fields)
+            .filter(field -> field.getAnnotation(GSONRequired.class) != null)
+            .forEach(field -> {
+                try {
+                    field.setAccessible(true);
+                    Object fieldObj = Optional.ofNullable(field.get(pojo))
+                        .orElseThrow(()-> new JsonParseException(
+                            String.format("Field '%s' in class '%s' is required but not found.",
+                            field.getName(), pojo.getClass().getSimpleName())));
+
+                    Field[] declaredFields = fieldObj.getClass().getDeclaredFields();
+                    validateRequiredFields(declaredFields, fieldObj);
+                }
+                catch (Exception exception) {
+                    throw new JsonParseException("Failed to check fields.", exception);
+                }
+            });
     }
 
 }
index f6aa2a8..e2bb4f5 100644 (file)
@@ -25,6 +25,8 @@ import java.io.BufferedReader;
 import java.io.IOException;\r
 import java.io.InputStreamReader;\r
 import java.net.UnknownHostException;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
 \r
 import static org.junit.Assert.assertEquals;\r
 import static org.junit.Assert.assertTrue;\r
@@ -48,6 +50,8 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;\r
 \r
 import com.google.gson.Gson;\r
+import com.google.gson.JsonObject;\r
+import com.google.gson.JsonParser;\r
 \r
 import ch.qos.logback.classic.spi.ILoggingEvent;\r
 import ch.qos.logback.core.read.ListAppender;\r
@@ -114,8 +118,24 @@ public class ConfigHandlerTests {
 \r
     @Test\r
     public void mapper_parse_valid_json_missing_attributes() throws Exception {\r
-        when(sender.send(anyString())).thenReturn(getFileContents("incomplete_mapper_config.json"));\r
-        assertThrows(MapperConfigException.class, this::getMapperConfig);\r
+        Map<String,String> invalidConfigs = new HashMap<>();\r
+        invalidConfigs.put("streams_subscribes", "{}");\r
+        invalidConfigs.put("streams_publishes", "{}");\r
+        invalidConfigs.put("streams_publishes", null);\r
+        invalidConfigs.remove("streams_publishes");\r
+        invalidConfigs.put("pm-mapper-filter", null);\r
+        invalidConfigs.put("pm-mapper-filter", "{}");\r
+        invalidConfigs.put("pm-mapper-filter", "{ \"filters\": null},");\r
+        invalidConfigs.put("pm-mapper-filter", "{ \"filters\": [{\"pmDefVsn\": \"V9\"}] },");\r
+\r
+        invalidConfigs.forEach( (k,v) -> {\r
+            try {\r
+                when(sender.send(anyString())).thenReturn( getInvalidConfig(k,v));\r
+                assertThrows(MapperConfigException.class, this::getMapperConfig);\r
+            } catch (Exception e) {\r
+                e.printStackTrace();\r
+            }\r
+        });\r
     }\r
 \r
     private MapperConfig getMapperConfig()\r
@@ -136,4 +156,10 @@ public class ConfigHandlerTests {
         return fileAsString;\r
     }\r
 \r
+    private String getInvalidConfig(String validKey, String invalidValue) {\r
+        JsonObject invalidConfigJson = new JsonParser().parse(validMapperConfig).getAsJsonObject();\r
+        invalidConfigJson.addProperty(validKey, invalidValue);\r
+        return invalidConfigJson.toString();\r
+    }\r
+\r
 }\r
diff --git a/src/test/resources/incomplete_mapper_config.json b/src/test/resources/incomplete_mapper_config.json
deleted file mode 100644 (file)
index ed4ebd7..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-{\r
-    "_comment": "This mapper config is missing streams_subscribes",\r
-    "pm-mapper-filter": {\r
-        "filters": "{[]}"\r
-    },\r
-    "3GPP.schema.file": "{\"3GPP_Schema\":\"./etc/3GPP_relaxed_schema.xsd\"}",\r
-    "streams_subscribes": null,\r
-    "streams_publishes": {\r
-        "pm_mapper_handle_out": {\r
-            "type": "message_router",\r
-            "aaf_password": null,\r
-            "dmaap_info": {\r
-                "topic_url": "https://we-are-message-router.us:3905/events/some-topic",\r
-                "client_role": null,\r
-                "location": null,\r
-                "client_id": null\r
-            },\r
-            "aaf_username": null\r
-        }\r
-    },\r
-    "some parameter": "unauthenticated.PM_VES_OUTPUT",\r
-    "some field": "1",\r
-    "services_calls": {}\r
-}
\ No newline at end of file