diff --git a/src/main/java/org/gcube/informationsystem/types/TypeMapper.java b/src/main/java/org/gcube/informationsystem/types/TypeMapper.java index 83681b5..68b85f0 100644 --- a/src/main/java/org/gcube/informationsystem/types/TypeMapper.java +++ b/src/main/java/org/gcube/informationsystem/types/TypeMapper.java @@ -62,7 +62,7 @@ public class TypeMapper { return json; } - public static Type deserializeTypeDefinition(String json) throws Exception{ + public static Type deserializeTypeDefinition(String json) throws Exception { Type type = mapper.readValue(json, Type.class); return type; } diff --git a/src/main/java/org/gcube/informationsystem/utils/ElementMapper.java b/src/main/java/org/gcube/informationsystem/utils/ElementMapper.java index c0935a0..4b2c310 100644 --- a/src/main/java/org/gcube/informationsystem/utils/ElementMapper.java +++ b/src/main/java/org/gcube/informationsystem/utils/ElementMapper.java @@ -20,7 +20,6 @@ import org.gcube.com.fasterxml.jackson.databind.JavaType; import org.gcube.com.fasterxml.jackson.databind.JsonMappingException; import org.gcube.com.fasterxml.jackson.databind.JsonNode; import org.gcube.com.fasterxml.jackson.databind.ObjectMapper; -import org.gcube.com.fasterxml.jackson.databind.exc.InvalidTypeIdException; import org.gcube.com.fasterxml.jackson.databind.module.SimpleModule; import org.gcube.com.fasterxml.jackson.databind.node.ArrayNode; import org.gcube.com.fasterxml.jackson.databind.node.JsonNodeType; @@ -217,85 +216,71 @@ public abstract class ElementMapper { return mapper.readValue(stream, clz); } - public static JsonNode analizeJsonToReplaceType(JsonNode jsonNodeToAnalize, String typeIdToReplace) throws Exception { - boolean replaced = false; + protected static StringBuffer getError(String unknownType) { + StringBuffer stringBuffer = new StringBuffer(); + stringBuffer.append(unknownType); + stringBuffer.append(" is an unknown type. Please provide "); + stringBuffer.append(Element.SUPERCLASSES_PROPERTY); + stringBuffer.append(" property as string array to allow to instantiate the most appropriated class."); + return stringBuffer; + } + + protected static JsonNode setAvailableSuperclass(JsonNode jsonNode) { + String unknownType = jsonNode.get(Element.CLASS_PROPERTY).asText(); + ArrayNode arrayNode = (ArrayNode) jsonNode.get(Element.SUPERCLASSES_PROPERTY); + + // TODO save original class and superclasses + String candidatedSuperClass = null; - int index = 0; - - String typeId = null; - if(jsonNodeToAnalize.has(Element.CLASS_PROPERTY)) { - typeId = jsonNodeToAnalize.get(Element.CLASS_PROPERTY).asText(); - } - - if(typeId != null && typeIdToReplace.compareTo(typeId) == 0) { - JsonNode superClassesTreeNode = jsonNodeToAnalize.get(Element.SUPERCLASSES_PROPERTY); - if(superClassesTreeNode != null && superClassesTreeNode.isArray()) { - ArrayNode arrayNode = (ArrayNode) superClassesTreeNode; - for(int i = 0; i < arrayNode.size(); i++) { - try { - JsonNode jsonNode = arrayNode.get(i); - JsonNodeType jsonNodeType = jsonNode.getNodeType(); - switch(jsonNodeType) { - case STRING: - String superClass = jsonNode.asText(); - try { - Enum.valueOf(AccessType.class, superClass.toUpperCase()); - // It is one of the BaseType. Looking for - // another type because the base one - continue; - } catch(Exception ex) { - // can continue discovery - } - - if(knownTypes.containsKey(superClass)) { - candidatedSuperClass = superClass; - index = i; - } - - break; - - default: - break; - } - - if(candidatedSuperClass!=null) { - break; - } - } catch(Exception ex) { - // Trying the next one + for(int i = 0; i < arrayNode.size(); i++) { + String superClass = arrayNode.get(i).asText(); + if(knownTypes.containsKey(superClass)) { + candidatedSuperClass = superClass; + try { + // Checking if it is one of the base type. In some cases we need to use dummy + // implementation + AccessType accessType = Enum.valueOf(AccessType.class, superClass.toUpperCase()); + // It is one of the BaseType. + // Looking if we need to set the dummy implementation class + if(accessType.getDummyImplementationClass()!=null) { + // This should not happen because the type has been assigned already to the dummy class. + candidatedSuperClass = accessType.getDummyImplementationClass().getSimpleName(); } - + } catch(Exception ex) { + // can continue discovery } - arrayNode.remove(index); - - ((ObjectNode) jsonNodeToAnalize).set(Element.CLASS_PROPERTY, new TextNode(candidatedSuperClass)); - replaced = true; + break; } } + + if(candidatedSuperClass!=null) { + ((ObjectNode) jsonNode).set(Element.CLASS_PROPERTY, new TextNode(candidatedSuperClass)); + return jsonNode; + } - if(!replaced) { - // continue to search inside the object - Iterator iterator = jsonNodeToAnalize.fieldNames(); - while(iterator.hasNext()) { - String fieldName = iterator.next(); - JsonNode jn = jsonNodeToAnalize.get(fieldName); - if(jn.getNodeType() == JsonNodeType.OBJECT) { - try { - JsonNode newValue = analizeJsonToReplaceType(jn,typeIdToReplace); - replaced = true; - ((ObjectNode) jsonNodeToAnalize).set(fieldName, newValue); - break; - }catch (Exception e) { - continue; + StringBuffer stringBuffer = getError(unknownType); + logger.trace("Unable to unmarshall {}. {}", jsonNode.toString(), stringBuffer.toString()); + throw new RuntimeException(stringBuffer.toString()); + } + + + protected static JsonNode analizeFullJson(JsonNode jsonNode) { + Iterator iterator = jsonNode.fieldNames(); + while(iterator.hasNext()) { + String fieldName = iterator.next(); + JsonNode jn = jsonNode.get(fieldName); + if(jn.getNodeType() == JsonNodeType.OBJECT) { + if(jn.has(Element.CLASS_PROPERTY)) { + String cls = jn.get(Element.CLASS_PROPERTY).asText(); + if(!knownTypes.containsKey(cls)) { + jn = setAvailableSuperclass(jn); } } + jn = analizeFullJson(jn); + ((ObjectNode) jsonNode).set(fieldName, jn); } } - - if(!replaced) { - throw new Exception(); - } - return jsonNodeToAnalize; + return jsonNode; } /** @@ -311,40 +296,10 @@ public abstract class ElementMapper { throws JsonParseException, JsonMappingException, IOException { try { return mapper.readValue(string, clz); - } catch(InvalidTypeIdException e) { - String typeId = e.getTypeId(); - - /* An initial step to support the Jackson 2.11 - if(knownTypes.containsKey(typeId)) { - // problem of type is not subtype of itself - - Class superClass = null; - Class[] interfaces = clz.getInterfaces(); - for(Class interfaceClass : interfaces) { - if(Element.class.isAssignableFrom(interfaceClass)) { - try { - superClass = (Class) interfaceClass; - return (ISM) ElementMapper.unmarshal(superClass, string); - }catch (Exception ex) { - // Trying the next type - logger.error("", e); - } - } - } - - throw e; - } - */ - + } catch (JsonMappingException e) { JsonNode jsonNode = mapper.readTree(string); - try { - jsonNode = analizeJsonToReplaceType(jsonNode, typeId); - }catch (Exception ex) { - throw e; - } + jsonNode = analizeFullJson(jsonNode); return ElementMapper.unmarshal(clz, mapper.writeValueAsString(jsonNode)); - } catch (Exception e) { - throw e; } } diff --git a/src/test/java/org/gcube/informationsystem/model/impl/properties/PropagationConstraintTest.java b/src/test/java/org/gcube/informationsystem/model/impl/properties/PropagationConstraintTest.java index 9d8861a..06ebae8 100644 --- a/src/test/java/org/gcube/informationsystem/model/impl/properties/PropagationConstraintTest.java +++ b/src/test/java/org/gcube/informationsystem/model/impl/properties/PropagationConstraintTest.java @@ -4,6 +4,9 @@ import java.util.Calendar; import java.util.UUID; import org.gcube.informationsystem.base.reference.Element; +import org.gcube.informationsystem.model.impl.entities.DummyFacet; +import org.gcube.informationsystem.model.impl.entities.DummyResource; +import org.gcube.informationsystem.model.impl.relations.ConsistsOfImpl; import org.gcube.informationsystem.model.reference.entities.Facet; import org.gcube.informationsystem.model.reference.entities.Resource; import org.gcube.informationsystem.model.reference.properties.PropagationConstraint; @@ -85,6 +88,76 @@ public class PropagationConstraintTest { } + @Test + public void test() throws Exception { + Resource resource = new DummyResource(); + Facet facet = new DummyFacet(); + ConsistsOf consistsOf = new ConsistsOfImpl(resource, facet); + String json = ElementMapper.marshal(consistsOf); + logger.debug(json); + } + + @Test + public void testOk() throws Exception { + String ok ="{\n" + + " \"@class\": \"ConsistsOf\",\n" + + " \"propagationConstraint\": {\n" + + " \"@class\": \"PropagationConstraint\",\n" + + " \"@superClasses\": [\n" + + " \"Property\"\n" + + " ],\n" + + " \"add\": \"propagate\",\n" + + " \"remove\": \"cascade\"\n" + + " },\n" + + " \"header\": {\n" + + " \"@class\": \"Header\",\n" + + " \"uuid\": \"4fbb4aeb-9755-4b8f-b997-0bf21a8f56ff\",\n" + + " \"creator\": \"luca.frosini\",\n" + + " \"modifiedBy\": \"luca.frosini\",\n" + + " \"creationTime\": \"2021-02-11 15:07:46.887 +0000\",\n" + + " \"lastUpdateTime\": \"2021-02-11 15:07:46.887 +0000\"\n" + + " },\n" + + " \"source\": {\n" + + " \"@class\": \"DummyResource\",\n" + + " \"@superClasses\": [\n" + + " \"EService\",\n" + + " \"Service\",\n" + + " \"Resource\"\n" + + " ],\n" + + " \"header\": {\n" + + " \"@class\": \"Header\",\n" + + " \"uuid\": \"4a971915-ca90-48cf-9975-63ee2dd28605\",\n" + + " \"creator\": null,\n" + + " \"creationTime\": null,\n" + + " \"lastUpdateTime\": null\n" + + " }\n" + + " },\n" + + " \"target\": {\n" + + " \"@class\": \"DummyFacet\",\n" + + " \"@superClasses\": [\n" + + " \"SoftwareFacet\",\n" + + " \"Facet\"\n" + + " ],\n" + + " \"header\": {\n" + + " \"@class\": \"Header\",\n" + + " \"uuid\": \"3ace4bd0-e5cd-49a3-97a8-a0a9468ce6d4\",\n" + + " \"creator\": null,\n" + + " \"creationTime\": null,\n" + + " \"lastUpdateTime\": null\n" + + " },\n" + + " \"name\": \"WhnManager\",\n" + + " \"group\": \"VREManagement\",\n" + + " \"version\": \"2.0.0-SNAPSHOT\",\n" + + " \"description\": \"Web Hosting Node Service\",\n" + + " \"qualifier\": null,\n" + + " \"optional\": false\n" + + " }\n" + + "}"; + @SuppressWarnings("unchecked") + ConsistsOf consistsOf = ElementMapper.unmarshal(ConsistsOf.class, ok); + Assert.assertTrue(consistsOf instanceof ConsistsOf); + } + @Test public void testPropagationConstraintSpecilizationInside() throws Exception { AddConstraint addConstraint = AddConstraint.propagate; @@ -102,8 +175,9 @@ public class PropagationConstraintTest { String hString = ElementMapper.marshal(header); - // TODO This fails - String consistsOfString = "{\"" + Element.CLASS_PROPERTY + "\":\"" + ConsistsOf.NAME + "\",\"" + ConsistsOf.PROPAGATION_CONSTRAINT_PROPERTY + "\":"+ pcString + ",\"" + ConsistsOf.HEADER_PROPERTY + "\": " + hString + ",\"" + ConsistsOf.TARGET_PROPERTY + "\":{\"@superClasses\":[\"SoftwareFacet\", \"Facet\"],\"@class\":\"MySoftwareFacet\",\"header\":"+ "{\"@class\":\"Header\",\"uuid\":\"3ace4bd0-e5cd-49a3-97a8-a0a9468ce6d4\",\"creator\":null, \"creationTime\":null, \"lastUpdateTime\":null}" + ",\"name\":\"WhnManager\",\"group\":\"VREManagement\",\"version\":\"2.0.0-SNAPSHOT\",\"description\":\"Web Hosting Node Service\",\"qualifier\":null,\"optional\":false}" + "}"; + String consistsOfString = "{\"" + Element.CLASS_PROPERTY + "\":\"" + ConsistsOf.NAME + "\",\"" + ConsistsOf.PROPAGATION_CONSTRAINT_PROPERTY + "\":"+ pcString + ",\"" + ConsistsOf.HEADER_PROPERTY + "\": " + hString + "," + + "\"" + ConsistsOf.SOURCE_PROPERTY + "\":{\"@class\":\"MyEService\", \"@superClasses\":[\"EService\", \"Service\", \"Resource\"],\"header\":"+ "{\"@class\":\"Header\",\"uuid\":\"4a971915-ca90-48cf-9975-63ee2dd28605\",\"creator\":null, \"creationTime\":null, \"lastUpdateTime\":null}" + "}," + + "\"" + ConsistsOf.TARGET_PROPERTY + "\":{\"@class\":\"MySoftwareFacet\",\"@superClasses\":[\"SoftwareFacet\", \"Facet\"],\"header\":"+ "{\"@class\":\"Header\",\"uuid\":\"3ace4bd0-e5cd-49a3-97a8-a0a9468ce6d4\",\"creator\":null, \"creationTime\":null, \"lastUpdateTime\":null}" + ",\"name\":\"WhnManager\",\"group\":\"VREManagement\",\"version\":\"2.0.0-SNAPSHOT\",\"description\":\"Web Hosting Node Service\",\"qualifier\":null,\"optional\":false}" + "}"; logger.debug(consistsOfString); @SuppressWarnings("unchecked")