package org.gcube.informationsystem.types; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import org.gcube.com.fasterxml.jackson.annotation.JsonTypeName; import org.gcube.com.fasterxml.jackson.databind.DeserializationFeature; import org.gcube.com.fasterxml.jackson.databind.JavaType; import org.gcube.com.fasterxml.jackson.databind.ObjectMapper; import org.gcube.informationsystem.base.reference.Element; import org.gcube.informationsystem.types.impl.TypeImpl; import org.gcube.informationsystem.types.reference.Change; import org.gcube.informationsystem.types.reference.Changelog; import org.gcube.informationsystem.types.reference.Type; import org.gcube.informationsystem.types.reference.TypeMetadata; import org.gcube.informationsystem.types.reference.entities.EntityType; import org.gcube.informationsystem.types.reference.entities.FacetType; import org.gcube.informationsystem.types.reference.entities.ResourceType; import org.gcube.informationsystem.types.reference.properties.LinkedEntity; import org.gcube.informationsystem.types.reference.properties.PropertyDefinition; import org.gcube.informationsystem.types.reference.properties.PropertyType; import org.gcube.informationsystem.types.reference.relations.ConsistsOfType; import org.gcube.informationsystem.types.reference.relations.IsRelatedToType; import org.gcube.informationsystem.types.reference.relations.RelationType; import org.gcube.informationsystem.utils.Version; /** * @author Luca Frosini (ISTI - CNR) */ public class TypeMapper { protected static final ObjectMapper mapper; static { mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.configure(DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES, false); mapper.registerSubtypes(Type.class); mapper.registerSubtypes(EntityType.class); mapper.registerSubtypes(ResourceType.class); mapper.registerSubtypes(FacetType.class); mapper.registerSubtypes(RelationType.class); mapper.registerSubtypes(IsRelatedToType.class); mapper.registerSubtypes(ConsistsOfType.class); mapper.registerSubtypes(PropertyType.class); mapper.registerSubtypes(PropertyDefinition.class); mapper.registerSubtypes(LinkedEntity.class); } public static String serializeTypeDefinition(Type type) throws Exception{ String json = mapper.writeValueAsString(type); return json; } public static Type deserializeTypeDefinition(String json) throws Exception { Type type = mapper.readValue(json, Type.class); return type; } public static String serializeTypeDefinitions(List typeDefinitions) throws Exception{ JavaType javaType = mapper.getTypeFactory().constructCollectionType(List.class, Type.class); return mapper.writerFor(javaType).writeValueAsString(typeDefinitions); } public static List deserializeTypeDefinitions(String json) throws Exception{ JavaType javaType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, Type.class); return mapper.readValue(json, javaType); } // TODO move somewhere else, probably in Element public static Type createTypeDefinition(Class clz) { Type type = TypeImpl.getInstance(clz); return type; } public static String serializeType(Class clz) throws Exception{ Type type = createTypeDefinition(clz); return serializeTypeDefinition(type); } public static String getType(E e){ return getType(e.getClass()); } public static String getType(Class clz){ String classSimpleName = clz.getSimpleName(); String name = null; if(!clz.isInterface()) { if(clz.isAnnotationPresent(JsonTypeName.class)) { JsonTypeName jsonTypeName = clz.getAnnotation(JsonTypeName.class); name = jsonTypeName.value(); if(name==null || name.compareTo("")==0) { throw new RuntimeException("Invalid annotation @JsonTypeName for type " + classSimpleName); } return name; } } if(clz.isAnnotationPresent(TypeMetadata.class)) { TypeMetadata typeMetadata = clz.getAnnotation(TypeMetadata.class); String typeMetadataName = typeMetadata.name(); if(typeMetadataName!=null && typeMetadataName.compareTo("")!=0) { /* if(name!=null && typeMetadataName.compareTo(name)!=0) { throw new RuntimeException("Name in annotation @TypeMetadata differ from annotation in @JsonTypeName for type " + classSimpleName + ". Please be coerent"); } */ return typeMetadataName; }else { throw new RuntimeException("Invalid Name in annotation @TypeMetadata for type " + classSimpleName); } }else { throw new RuntimeException("You must provide @TypeMetadata for " + classSimpleName); } } public static String getTypeDescription(Class clz){ String classSimpleName = clz.getSimpleName(); if(clz.isAnnotationPresent(TypeMetadata.class)) { TypeMetadata typeMetadata = clz.getAnnotation(TypeMetadata.class); String description = typeMetadata.description(); if(description!=null && description.compareTo("")!=0) { return description; }else { throw new RuntimeException("Invalid Description in annotation @TypeMetadata for type " + classSimpleName); } }else { throw new RuntimeException("You must provide @TypeMetadata for " + classSimpleName); } } public static Version getTypeVersion(Class clz){ String classSimpleName = clz.getSimpleName(); if(clz.isAnnotationPresent(TypeMetadata.class)) { TypeMetadata typeMetadata = clz.getAnnotation(TypeMetadata.class); return new Version(typeMetadata.version()); }else { throw new RuntimeException("You must provide @TypeMetadata for " + classSimpleName); } } public static Map getTypeChangelog(Class clz){ Map map = new HashMap<>(); if(clz.isAnnotationPresent(Changelog.class)) { Changelog changelog = clz.getAnnotation(Changelog.class); Change[] changes = changelog.value(); for(Change change : changes) { String version = change.version(); Version typeVersion = new Version(version); if(map.containsKey(typeVersion)) { throw new RuntimeException("Duplicated version " + version +" in @Change annotation"); } String description = change.description(); if(description==null || description.compareTo("")==0) { throw new RuntimeException("A valid description for version " + version +" must be provided in @Change annotation"); } map.put(typeVersion, description); } } if(!map.containsKey(Version.MINIMAL_VERSION)) { map.putAll(TypeImpl.DEFAULT_CHANGELOG_MAP); } Version typeVersion = getTypeVersion(clz); if (!map.containsKey(typeVersion)) { throw new RuntimeException("The Type " + clz.getSimpleName() + " does not provided the appropriated changelog Map"); } List versions = new ArrayList<>(map.keySet()); versions.sort(new Comparator() { @Override public int compare(Version o1, Version o2) { /* o2.compareTo(o1) and not vice-versa * because we want descending order */ return o2.compareTo(o1); } }); if(versions.get(0).compareTo(typeVersion)!=0) { throw new RuntimeException("The Type declared version (i.e."+ typeVersion.toString() +") does not match the highest version declared in changelog (i.e. "+ versions.get(0) + "). Please fix your type."); } return map; } }