Adding a way to support to specify which implementation to use

This commit is contained in:
Luca Frosini 2024-07-01 17:36:24 +02:00
parent bfeaeacc40
commit 0931af85ed
5 changed files with 94 additions and 18 deletions

View File

@ -0,0 +1,19 @@
package org.gcube.informationsystem.contexts.reference;
public enum ContextState {
CREATED("created"),
ACTIVE("active"),
DELETED("deleted");
protected String state;
ContextState(String state) {
this.state = state;
}
public String getState() {
return state;
}
}

View File

@ -13,7 +13,6 @@ import org.gcube.com.fasterxml.jackson.annotation.JsonGetter;
import org.gcube.com.fasterxml.jackson.annotation.JsonIgnore;
import org.gcube.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.gcube.com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.gcube.com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.gcube.com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.gcube.informationsystem.base.reference.Element;
import org.gcube.informationsystem.base.reference.IdentifiableElement;
@ -23,6 +22,7 @@ import org.gcube.informationsystem.contexts.impl.entities.ContextImpl;
import org.gcube.informationsystem.contexts.reference.relations.IsParentOf;
import org.gcube.informationsystem.model.reference.relations.Relation;
import org.gcube.informationsystem.serialization.AdditionalPropertiesSerializer;
import org.gcube.informationsystem.types.annotations.Deserialize;
import org.gcube.informationsystem.types.annotations.Final;
import org.gcube.informationsystem.types.annotations.ISProperty;
import org.gcube.informationsystem.types.reference.Change;
@ -34,7 +34,8 @@ import org.gcube.informationsystem.utils.Version;
*
* @author Luca Frosini (ISTI - CNR)
*/
@JsonDeserialize(as = ContextImpl.class)
//@JsonDeserialize(as = ContextImpl.class)
@Deserialize(as = ContextImpl.class)
@JsonPropertyOrder({ Element.TYPE_PROPERTY, IdentifiableElement.ID_PROPERTY, IdentifiableElement.METADATA_PROPERTY})
@TypeMetadata(name = Context.NAME, description = "This type is the used to define a Context", version = Version.MINIMAL_VERSION_STRING)
@Change(version = Version.MINIMAL_VERSION_STRING, description = Version.MINIMAL_VERSION_DESCRIPTION)

View File

@ -8,6 +8,7 @@ import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
@ -24,6 +25,8 @@ import org.gcube.com.fasterxml.jackson.databind.JsonNode;
import org.gcube.com.fasterxml.jackson.databind.ObjectMapper;
import org.gcube.com.fasterxml.jackson.databind.SerializationFeature;
import org.gcube.com.fasterxml.jackson.databind.exc.InvalidTypeIdException;
import org.gcube.com.fasterxml.jackson.databind.module.SimpleAbstractTypeResolver;
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;
import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode;
@ -43,7 +46,7 @@ import org.slf4j.LoggerFactory;
* @author Luca Frosini (ISTI - CNR)
*/
@SuppressWarnings("unchecked")
public abstract class ElementMapper {
public class ElementMapper {
private static Logger logger = LoggerFactory.getLogger(ElementMapper.class);
@ -51,6 +54,8 @@ public abstract class ElementMapper {
protected static final Map<String, Class<? extends Element>> knownTypes;
protected static final Map<Class<? extends Element>, Class<? extends Element>> interfaceToImplementation;
/**
* @return the ObjectMapper
*/
@ -70,8 +75,9 @@ public abstract class ElementMapper {
mapper.setDateFormat(sdf);
knownTypes = new HashMap<>();
interfaceToImplementation = new HashMap<>();
List<Package> packages = new ArrayList<Package>();
Set<Package> packages = new HashSet<Package>();
Class<Type> tdClz = Type.class;
ElementMapper.registerSubtype(tdClz);
@ -82,14 +88,18 @@ public abstract class ElementMapper {
@SuppressWarnings("rawtypes")
Class clz = accessType.getTypeClass();
if(!Type.class.isAssignableFrom(clz)) {
Class<Element> dummyClz = accessType.getDummyImplementationClass();
if(dummyClz != null) {
// ElementMapper.registerSubtypes(clz, dummyClz);
ElementMapper.registerSubtype(dummyClz);
Class<? extends Element> dynamicImplementationClz = TypeMapper.getDynamicImplementation(clz);
if(dynamicImplementationClz!=null) {
ElementMapper.addDynamicAssociation(clz, dynamicImplementationClz);
}else {
ElementMapper.registerSubtype(clz);
Class<Element> dummyClz = accessType.getDummyImplementationClass();
if(dummyClz != null) {
ElementMapper.registerSubtype(dummyClz);
}else {
ElementMapper.registerSubtype(clz);
}
packages.add(clz.getPackage());
}
packages.add(clz.getPackage());
}
}
@ -117,16 +127,26 @@ public abstract class ElementMapper {
throw new RuntimeException(e);
}
for(@SuppressWarnings("rawtypes") Class clz : interfaceToImplementation.keySet()) {
Class<? extends Element> implClz = interfaceToImplementation.get(clz);
registerSubtypes(clz, implClz);
}
}
public static <El extends Element, ELImpl extends El> void addDynamicAssociation(Class<El> interfaceClz, Class<ELImpl> implementationClass) {
interfaceToImplementation.put(interfaceClz, implementationClass);
}
// This add the ElementDeserializer which has been deprecated thank to the fix in
// public static <El extends Element> void registerSubtypes(Class<El> clz, Class<El> implementationClass) {
// String typeName = TypeMapper.getType(clz);
// SimpleModule isModule = new SimpleModule(typeName);
// isModule.addDeserializer(clz, new ElementDeserializer<>(clz, mapper));
// mapper.registerModule(isModule);
// registerSubtype(implementationClass);
// }
protected static <El extends Element, ELImpl extends El> void registerSubtypes(Class<El> interfaceClz, Class<ELImpl> implementationClass) {
String typeName = TypeMapper.getType(interfaceClz);
SimpleModule module = new SimpleModule(typeName);
SimpleAbstractTypeResolver resolver = new SimpleAbstractTypeResolver();
resolver.addMapping(interfaceClz, implementationClass);
module.setAbstractTypes(resolver);
mapper.registerModule(module);
}
public static <El extends Element> void registerSubtype(Class<El> clz) {
String typeName = TypeMapper.getType(clz);

View File

@ -11,6 +11,7 @@ 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.annotations.Deserialize;
import org.gcube.informationsystem.types.impl.TypeImpl;
import org.gcube.informationsystem.types.reference.Change;
import org.gcube.informationsystem.types.reference.Changelog;
@ -92,6 +93,19 @@ public class TypeMapper {
return getType(e.getClass());
}
public static <E extends Element, EImpl extends E> Class<EImpl> getDynamicImplementation(Class<E> clz){
if(clz.isInterface() && clz.isAnnotationPresent(Deserialize.class)) {
Deserialize deserialize = clz.getAnnotation(Deserialize.class);
Class<?> annotatedClass = deserialize.as();
if(clz.isAssignableFrom(annotatedClass) && !annotatedClass.isInterface()) {
@SuppressWarnings("unchecked")
Class<EImpl> implementationClz = (Class<EImpl>) annotatedClass;
return implementationClz;
}
}
return null;
}
public static String getType(Class<? extends Element> clz){
String classSimpleName = clz.getSimpleName();
String name = null;

View File

@ -0,0 +1,22 @@
package org.gcube.informationsystem.types.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.gcube.informationsystem.base.reference.Element;
/**
* It indicates that the {@link Element} is final and cannot be extended/derived.
* This is needed because the type definition is made with interface.
* @author Luca Frosini (ISTI - CNR)
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Deserialize {
public Class<?> as() default Void.class;
}