diff --git a/src/main/java/org/gcube/informationsystem/types/PropertyTypeName.java b/src/main/java/org/gcube/informationsystem/types/PropertyTypeName.java index b97e567..c48caf3 100644 --- a/src/main/java/org/gcube/informationsystem/types/PropertyTypeName.java +++ b/src/main/java/org/gcube/informationsystem/types/PropertyTypeName.java @@ -122,6 +122,7 @@ public class PropertyTypeName { protected static final Map,BaseType> BASE_PROPERTY_TYPES_BY_CLASS; protected static final Map,String> REGEX_BY_CLASS_MAPPED_AS_STRING; + protected static final Map REGEX_BY_CLASS_MAPPED_AS_STRING_BY_CLASS_NAME; static { BASE_PROPERTY_TYPES_BY_CLASS = new HashMap<>(); @@ -180,6 +181,13 @@ public class PropertyTypeName { REGEX_BY_CLASS_MAPPED_AS_STRING.put(UUID.class,PropertyTypeName.UUID_REGEX); REGEX_BY_CLASS_MAPPED_AS_STRING.put(Version.class, Version.VERSION_REGEX); + REGEX_BY_CLASS_MAPPED_AS_STRING_BY_CLASS_NAME = new HashMap<>(); + for(Class clz : REGEX_BY_CLASS_MAPPED_AS_STRING.keySet()) { + String className = clz.getSimpleName(); + String regex = REGEX_BY_CLASS_MAPPED_AS_STRING.get(clz); + REGEX_BY_CLASS_MAPPED_AS_STRING_BY_CLASS_NAME.put(className, regex); + } + } public final static String URI_REGEX = null; @@ -203,6 +211,10 @@ public class PropertyTypeName { return REGEX_BY_CLASS_MAPPED_AS_STRING.get(clz); } + public static String getRegexByClassname(String className) { + return REGEX_BY_CLASS_MAPPED_AS_STRING_BY_CLASS_NAME.get(className); + } + /** * Return the correspondent type by checking the "assignability" of the * class received as parameter. @@ -235,10 +247,34 @@ public class PropertyTypeName { protected BaseType genericBaseType; protected String genericClassName; + protected Class clz; + public PropertyTypeName(String type) { setType(type); } + public PropertyTypeName(Class clz) { + baseType = null; + genericType = false; + genericBaseType = null; + genericClassName = null; + + logger.trace("The type is {}", clz); + + baseType = PropertyTypeName.getBaseTypeByClass(clz); + + if(baseType == BaseType.PROPERTY){ + if(clz != PropertyElement.class){ + @SuppressWarnings("unchecked") + Class type = (Class) clz; + genericType = true; + genericClassName = TypeMapper.getType(type); + return; + } + } + + } + public PropertyTypeName(Method method) { baseType = null; genericType = false; @@ -265,13 +301,13 @@ public class PropertyTypeName { genericType = true; java.lang.reflect.Type genericReturnType = method.getGenericReturnType(); - logger.trace("Generic Return Type for method {} is {}", method, genericReturnType); + logger.trace("Generic Type for method {} is {}", method, genericReturnType); java.lang.reflect.Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); java.lang.reflect.Type genericType = null; for(java.lang.reflect.Type t : actualTypeArguments){ - logger.trace("Generic Return Type {} for method {} - Actual Type Argument : {}", genericReturnType, method, t); + logger.trace("Generic Type {} for method {} - Actual Type Argument : {}", genericReturnType, method, t); genericType = t; } diff --git a/src/main/java/org/gcube/informationsystem/types/annotations/GetReturnType.java b/src/main/java/org/gcube/informationsystem/types/annotations/GetReturnType.java new file mode 100644 index 0000000..3a5b253 --- /dev/null +++ b/src/main/java/org/gcube/informationsystem/types/annotations/GetReturnType.java @@ -0,0 +1,17 @@ +package org.gcube.informationsystem.types.annotations; + +import org.gcube.informationsystem.types.PropertyTypeName.BaseType; + +/** + * This is a facade class. + * {@link ISProperty} has the possibility to specify the type. + * If we don't specify a default in the annotation definition the type is mandatory. + * We need a way to specify a default which means get the return of the annotated method. + * This avoid to the developer to specify something which can be get from the annotated method. + * We can't use Object as default because Object is mapped as {@link BaseType#ANY} + * + * This interface has been defined for this reason. + */ +public interface GetReturnType { + +} diff --git a/src/main/java/org/gcube/informationsystem/types/annotations/ISProperty.java b/src/main/java/org/gcube/informationsystem/types/annotations/ISProperty.java index 7910180..7967e83 100644 --- a/src/main/java/org/gcube/informationsystem/types/annotations/ISProperty.java +++ b/src/main/java/org/gcube/informationsystem/types/annotations/ISProperty.java @@ -8,6 +8,7 @@ import java.lang.annotation.Target; import org.gcube.informationsystem.model.reference.entities.Entity; import org.gcube.informationsystem.types.TypeMapper; +import org.gcube.informationsystem.types.PropertyTypeName.BaseType; import org.gcube.informationsystem.types.reference.properties.PropertyDefinition; /** @@ -24,6 +25,17 @@ import org.gcube.informationsystem.types.reference.properties.PropertyDefinition public @interface ISProperty { String name() default ""; + /** + * If we don't specify a default in the annotation definition, the type becomes mandatory. + * We wanted a way to specify a default that means using the return type of the annotated method. + * This avoids the need for developers to specify something that can be obtained from the annotated method itself. + * We can't use Object as the default because Object is mapped as {@link BaseType#ANY}. + * For this reason, the type {@link GetReturnType} has been set as the default. + * + * Please note that you can't use this functionality for generic types + * like List because it is not accepted by the annotation. + */ + Class type() default GetReturnType.class; String description() default ""; boolean mandatory() default false; boolean readonly() default false; diff --git a/src/main/java/org/gcube/informationsystem/types/impl/properties/PropertyDefinitionImpl.java b/src/main/java/org/gcube/informationsystem/types/impl/properties/PropertyDefinitionImpl.java index f1680f2..73fcccb 100644 --- a/src/main/java/org/gcube/informationsystem/types/impl/properties/PropertyDefinitionImpl.java +++ b/src/main/java/org/gcube/informationsystem/types/impl/properties/PropertyDefinitionImpl.java @@ -12,6 +12,7 @@ import org.gcube.com.fasterxml.jackson.annotation.JsonTypeName; import org.gcube.informationsystem.model.impl.properties.AttributeUtility; import org.gcube.informationsystem.types.PropertyTypeName; import org.gcube.informationsystem.types.annotations.ISProperty; +import org.gcube.informationsystem.types.annotations.GetReturnType; import org.gcube.informationsystem.types.reference.properties.PropertyDefinition; import org.gcube.informationsystem.utils.TypeUtility; import org.gcube.informationsystem.utils.Version; @@ -82,19 +83,25 @@ public final class PropertyDefinitionImpl implements PropertyDefinition { this.min = propertyAnnotation.min(); } - this.propertyTypeName = new PropertyTypeName(method); - this.propertyTypeName = new PropertyTypeName(method); + Class clz = propertyAnnotation.type(); + if(clz==GetReturnType.class) { + // We have to read the return of the method + this.propertyTypeName = new PropertyTypeName(method); + clz = method.getReturnType(); + logger.trace("Return Type for method {} is {}", method, clz); + }else { + this.propertyTypeName = new PropertyTypeName(clz); + } + String defaultValueAsString = propertyAnnotation.defaultValue(); defaultValueAsString = AttributeUtility.evaluateNullForDefaultValue(defaultValueAsString); // The default value is evaluated to test if compliant with the declared type this.defaultValue = AttributeUtility.evaluateDefaultValueStringAccordingBaseType(propertyTypeName.getBaseType(), defaultValueAsString); - Class clz = method.getReturnType(); - logger.trace("Return Type for method {} is {}", method, clz); - - if(!propertyAnnotation.regexpr().isEmpty()) this.regexp = propertyAnnotation.regexpr(); - if(this.regexp==null || this.regexp.compareTo("")==0 ){ + if(!propertyAnnotation.regexpr().isEmpty()) { + this.regexp = propertyAnnotation.regexpr(); + }else { if(Enum.class.isAssignableFrom(clz)){ Object[] constants = clz.getEnumConstants(); StringBuilder stringBuilder = new StringBuilder("^("); @@ -119,7 +126,6 @@ public final class PropertyDefinitionImpl implements PropertyDefinition { if(Version.class.isAssignableFrom(clz)){ this.regexp = Version.VERSION_REGEX; } - } } diff --git a/src/main/java/org/gcube/informationsystem/utils/Version.java b/src/main/java/org/gcube/informationsystem/utils/Version.java index aeb5eea..199c892 100644 --- a/src/main/java/org/gcube/informationsystem/utils/Version.java +++ b/src/main/java/org/gcube/informationsystem/utils/Version.java @@ -13,7 +13,7 @@ import org.gcube.com.fasterxml.jackson.annotation.JsonIgnore; * * @author Luca Frosini (ISTI - CNR) */ -public class Version implements Comparable { +public final class Version implements Comparable { /** * Regex validating the version