2016-06-09 10:56:14 +02:00
|
|
|
package org.gcube.informationsystem.types;
|
|
|
|
|
|
|
|
import java.lang.reflect.Field;
|
2016-07-04 12:05:47 +02:00
|
|
|
import java.lang.reflect.Method;
|
2016-07-05 12:34:13 +02:00
|
|
|
import java.lang.reflect.ParameterizedType;
|
2016-07-01 16:02:37 +02:00
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.Set;
|
2016-06-09 10:56:14 +02:00
|
|
|
|
2016-07-01 16:02:37 +02:00
|
|
|
import org.gcube.informationsystem.model.annotations.Abstract;
|
2016-07-04 12:05:47 +02:00
|
|
|
import org.gcube.informationsystem.model.annotations.ISProperty;
|
2016-07-01 16:02:37 +02:00
|
|
|
import org.gcube.informationsystem.model.embedded.Embedded;
|
2016-06-09 10:56:14 +02:00
|
|
|
import org.gcube.informationsystem.model.entity.Entity;
|
|
|
|
import org.gcube.informationsystem.model.entity.Facet;
|
2016-06-30 17:15:12 +02:00
|
|
|
import org.gcube.informationsystem.model.entity.Resource;
|
2016-07-04 15:26:54 +02:00
|
|
|
import org.gcube.informationsystem.model.relation.ConsistOf;
|
|
|
|
import org.gcube.informationsystem.model.relation.RelatedTo;
|
|
|
|
import org.gcube.informationsystem.model.relation.Relation;
|
2016-07-04 12:05:47 +02:00
|
|
|
import org.gcube.informationsystem.types.Type.OType;
|
2016-06-09 10:56:14 +02:00
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
|
|
|
public class TypeBinder {
|
|
|
|
|
|
|
|
private static Logger logger = LoggerFactory.getLogger(TypeBinder.class);
|
|
|
|
|
2016-07-05 16:04:18 +02:00
|
|
|
private static final String EDGE_CLASS_NAME = "E";
|
|
|
|
private static final String VERTEX_CLASS_NAME = "V";
|
|
|
|
|
|
|
|
|
2016-07-01 16:02:37 +02:00
|
|
|
public final static String NAME = "NAME";
|
|
|
|
public final static String DESCRIPTION = "DESCRIPTION";
|
|
|
|
|
|
|
|
private static String getStaticStringFieldByName(Class<?> type, String fieldName, String defaultValue){
|
|
|
|
Field field;
|
|
|
|
try {
|
2016-07-04 12:05:47 +02:00
|
|
|
field = type.getDeclaredField(fieldName);
|
2016-07-01 16:02:37 +02:00
|
|
|
return (String) field.get(null);
|
|
|
|
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
|
|
|
return defaultValue;
|
2016-06-30 17:15:12 +02:00
|
|
|
}
|
2016-06-09 10:56:14 +02:00
|
|
|
}
|
|
|
|
|
2016-07-01 16:02:37 +02:00
|
|
|
public static String serializeType(Class<?> type) throws Exception{
|
|
|
|
TypeDefinition def = createTypeDefinition(type);
|
2016-06-09 10:56:14 +02:00
|
|
|
ObjectMapper mapper = new ObjectMapper();
|
|
|
|
String json = mapper.writeValueAsString(def);
|
|
|
|
return json;
|
|
|
|
}
|
|
|
|
|
2016-07-01 16:02:37 +02:00
|
|
|
protected static TypeDefinition createTypeDefinition(Class<?> type) {
|
2016-06-09 10:56:14 +02:00
|
|
|
TypeDefinition typeDefinition = new TypeDefinition();
|
2016-06-30 17:15:12 +02:00
|
|
|
|
2016-07-01 16:02:37 +02:00
|
|
|
typeDefinition.name = getStaticStringFieldByName(type, NAME, type.getSimpleName());
|
|
|
|
typeDefinition.description = getStaticStringFieldByName(type, DESCRIPTION, "");
|
|
|
|
typeDefinition.abstractType = false;
|
|
|
|
|
|
|
|
if(type.isAnnotationPresent(Abstract.class)){
|
|
|
|
typeDefinition.abstractType = true;
|
|
|
|
}
|
|
|
|
|
2016-07-04 15:26:54 +02:00
|
|
|
if(Entity.class.isAssignableFrom(type)) {
|
|
|
|
if(Resource.class.isAssignableFrom(type)){
|
|
|
|
typeDefinition.superclasses = retrieveSuperClasses(type, Resource.class, Entity.class.getSimpleName());
|
|
|
|
}else{
|
|
|
|
if(Facet.class.isAssignableFrom(type)){
|
|
|
|
typeDefinition.superclasses = retrieveSuperClasses(type, Facet.class, Entity.class.getSimpleName());
|
|
|
|
} else {
|
2016-07-05 16:04:18 +02:00
|
|
|
typeDefinition.superclasses = retrieveSuperClasses(type, Entity.class, VERTEX_CLASS_NAME);
|
2016-07-04 15:26:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if(Relation.class.isAssignableFrom(type)){
|
|
|
|
if(RelatedTo.class.isAssignableFrom(type)){
|
|
|
|
typeDefinition.superclasses = retrieveSuperClasses(type, RelatedTo.class, Relation.class.getSimpleName());
|
|
|
|
} else if(ConsistOf.class.isAssignableFrom(type)) {
|
|
|
|
typeDefinition.superclasses = retrieveSuperClasses(type, ConsistOf.class, Relation.class.getSimpleName());
|
|
|
|
} else {
|
2016-07-05 16:04:18 +02:00
|
|
|
typeDefinition.superclasses = retrieveSuperClasses(type, Relation.class, EDGE_CLASS_NAME);
|
2016-07-04 15:26:54 +02:00
|
|
|
}
|
|
|
|
} else if(Embedded.class.isAssignableFrom(type)){
|
|
|
|
typeDefinition.superclasses = retrieveSuperClasses(type, Embedded.class, null);
|
|
|
|
} else {
|
|
|
|
throw new RuntimeException("Serialization required");
|
|
|
|
}
|
2016-07-01 16:02:37 +02:00
|
|
|
|
2016-07-04 15:26:54 +02:00
|
|
|
if(!Resource.class.isAssignableFrom(type)){
|
2016-07-04 12:05:47 +02:00
|
|
|
typeDefinition.properties = retrieveListOfProperties(type);
|
2016-07-01 16:02:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
logger.trace("{} TypeDefinition {} ", type, typeDefinition);
|
2016-06-09 10:56:14 +02:00
|
|
|
return typeDefinition;
|
|
|
|
}
|
2016-07-01 16:02:37 +02:00
|
|
|
|
2016-07-04 12:05:47 +02:00
|
|
|
protected static Set<Property> retrieveListOfProperties(Class<?> type){
|
|
|
|
Set<Property> properties = new HashSet<>();
|
|
|
|
for (Method m : type.getDeclaredMethods()){
|
|
|
|
m.setAccessible(true);
|
|
|
|
if(m.isAnnotationPresent(ISProperty.class)){
|
|
|
|
ISProperty propAnnotation = m.getAnnotation(ISProperty.class);
|
|
|
|
Property prop = getProperty(propAnnotation, m);
|
2016-06-09 10:56:14 +02:00
|
|
|
properties.add(prop);
|
2016-07-04 12:05:47 +02:00
|
|
|
logger.trace("Property {} retrieved in type {} ", prop, type.getSimpleName());
|
2016-06-09 10:56:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return properties;
|
|
|
|
}
|
|
|
|
|
2016-07-04 12:05:47 +02:00
|
|
|
protected static String getPropertyNameFromMethodName(Method method){
|
|
|
|
String name = method.getName();
|
|
|
|
if(name.startsWith("get")){
|
|
|
|
name = name.replace("get", "");
|
|
|
|
|
|
|
|
}
|
|
|
|
if(name.startsWith("is")){
|
|
|
|
name = name.replace("is", "");
|
|
|
|
}
|
2016-06-09 10:56:14 +02:00
|
|
|
|
2016-07-04 12:05:47 +02:00
|
|
|
if(name.length() > 0){
|
|
|
|
name = Character.toLowerCase(name.charAt(0)) + (name.length() > 1 ? name.substring(1) : "");
|
|
|
|
}
|
2016-06-09 10:56:14 +02:00
|
|
|
|
2016-07-04 12:05:47 +02:00
|
|
|
return name;
|
2016-06-09 10:56:14 +02:00
|
|
|
}
|
2016-07-04 12:05:47 +02:00
|
|
|
|
|
|
|
protected static Property getProperty(ISProperty propertyAnnotation, Method method){
|
|
|
|
String name = propertyAnnotation.name().isEmpty()?getPropertyNameFromMethodName(method):propertyAnnotation.name();
|
2016-07-04 15:29:44 +02:00
|
|
|
Property property = new Property();
|
|
|
|
property.name = name;
|
|
|
|
property.description = propertyAnnotation.description();
|
|
|
|
property.mandatory= propertyAnnotation.mandatory();
|
|
|
|
property.notnull = !propertyAnnotation.nullable();
|
|
|
|
property.readonly = propertyAnnotation.readonly();
|
|
|
|
if(propertyAnnotation.max()>0) property.max = propertyAnnotation.max();
|
|
|
|
if(propertyAnnotation.max()>=propertyAnnotation.min() && propertyAnnotation.min()>0) property.min = propertyAnnotation.min();
|
|
|
|
if(!propertyAnnotation.regexpr().isEmpty()) property.regexpr = propertyAnnotation.regexpr();
|
2016-07-04 12:05:47 +02:00
|
|
|
|
2016-07-05 12:34:13 +02:00
|
|
|
logger.trace("Looking for property type {}", method.getReturnType());
|
2016-07-04 12:05:47 +02:00
|
|
|
Class<?> type = method.getReturnType();
|
2016-07-04 19:07:13 +02:00
|
|
|
property.type = OType.EMBEDDED.getIntValue();
|
|
|
|
|
2016-07-04 12:05:47 +02:00
|
|
|
if(Embedded.class.isAssignableFrom(type)){
|
2016-07-04 15:29:44 +02:00
|
|
|
property.linkedClass = getStaticStringFieldByName(type, NAME, type.getSimpleName());
|
|
|
|
property.type = OType.EMBEDDED.getIntValue();
|
2016-07-04 12:05:47 +02:00
|
|
|
}else if (Type.getTypeByClass(type)!=null) {
|
2016-07-04 15:29:44 +02:00
|
|
|
property.type = Type.getTypeByClass(type).getIntValue();
|
2016-07-05 12:34:13 +02:00
|
|
|
if(property.type > 9 && property.type <= 12){
|
|
|
|
java.lang.reflect.Type genericReturnType = method.getGenericReturnType();
|
|
|
|
logger.trace("Generic Return Type {} for method {}", genericReturnType, method);
|
|
|
|
|
|
|
|
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);
|
|
|
|
genericType = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
Class<?> genericClass = (Class<?>) genericType;
|
|
|
|
OType linkedOType = Type.getTypeByClass(genericClass);
|
|
|
|
if(linkedOType!=null){
|
|
|
|
property.linkedType = linkedOType.getIntValue();
|
|
|
|
}else{
|
|
|
|
property.linkedClass = getStaticStringFieldByName(genericClass, NAME, genericClass.getSimpleName());
|
|
|
|
}
|
|
|
|
|
2016-07-04 19:07:13 +02:00
|
|
|
}
|
2016-07-04 12:05:47 +02:00
|
|
|
} else {
|
|
|
|
throw new RuntimeException("Type " + type.getSimpleName() + " not reconized");
|
|
|
|
}
|
|
|
|
|
2016-07-04 15:29:44 +02:00
|
|
|
return property;
|
2016-06-09 10:56:14 +02:00
|
|
|
}
|
2016-07-04 12:05:47 +02:00
|
|
|
|
2016-06-09 10:56:14 +02:00
|
|
|
|
2016-07-01 16:02:37 +02:00
|
|
|
private static Set<String> retrieveSuperClasses(Class<?> type, Class<?> baseClass, String topSuperClass){
|
|
|
|
Set<String> interfaceList = new HashSet<>();
|
|
|
|
|
|
|
|
if(type==baseClass){
|
|
|
|
interfaceList.add(topSuperClass);
|
|
|
|
return interfaceList;
|
|
|
|
}
|
|
|
|
|
|
|
|
Class<?>[] interfaces = type.getInterfaces();
|
|
|
|
|
|
|
|
for (Class<?> interfaceClass : interfaces) {
|
|
|
|
if(interfaceClass==Embedded.class){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!baseClass.isAssignableFrom(interfaceClass)){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
interfaceList.add(getStaticStringFieldByName(interfaceClass, NAME, interfaceClass.getSimpleName()));
|
2016-06-09 10:56:14 +02:00
|
|
|
}
|
2016-07-01 16:02:37 +02:00
|
|
|
|
|
|
|
return interfaceList;
|
2016-06-09 10:56:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
|
|
|
|
public static class TypeDefinition{
|
|
|
|
|
2016-07-01 16:02:37 +02:00
|
|
|
protected String name;
|
|
|
|
protected String description;
|
|
|
|
protected boolean abstractType;
|
|
|
|
protected Set<String> superclasses;
|
|
|
|
protected Set<Property> properties;
|
2016-06-09 10:56:14 +02:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "TypeDefinition [name=" + name +", description="
|
|
|
|
+ description + ", superclasses="
|
|
|
|
+ superclasses + ", properties=" + properties + "]";
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getName() {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getDescription() {
|
|
|
|
return description;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isAbstractType() {
|
|
|
|
return abstractType;
|
|
|
|
}
|
|
|
|
|
2016-07-01 16:02:37 +02:00
|
|
|
public Set<String> getSuperclasses() {
|
2016-06-09 10:56:14 +02:00
|
|
|
return superclasses;
|
|
|
|
}
|
|
|
|
|
2016-07-01 16:02:37 +02:00
|
|
|
public Set<Property> getProperties() {
|
2016-06-09 10:56:14 +02:00
|
|
|
return properties;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
|
2016-07-04 15:29:44 +02:00
|
|
|
public static class Property {
|
2016-06-09 10:56:14 +02:00
|
|
|
|
|
|
|
private String name= "";
|
|
|
|
private String description= "";
|
|
|
|
private boolean mandatory = false;
|
|
|
|
private boolean readonly = false;
|
|
|
|
private boolean notnull = false;
|
|
|
|
private Integer max= null;
|
|
|
|
private Integer min= null;
|
2016-07-05 12:34:13 +02:00
|
|
|
private String regexpr= null;
|
|
|
|
private Integer linkedType = null;
|
2016-06-09 10:56:14 +02:00
|
|
|
private String linkedClass = null;
|
|
|
|
private Integer type=null;
|
|
|
|
|
|
|
|
public String getName() {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getDescription() {
|
|
|
|
return description;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isMandatory() {
|
|
|
|
return mandatory;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isReadonly() {
|
|
|
|
return readonly;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isNotnull() {
|
|
|
|
return notnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Integer getMax() {
|
|
|
|
return max;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Integer getMin() {
|
|
|
|
return min;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getRegexpr() {
|
|
|
|
return regexpr;
|
|
|
|
}
|
2016-07-05 12:34:13 +02:00
|
|
|
|
|
|
|
public Integer getLinkedType() {
|
|
|
|
return linkedType;
|
|
|
|
}
|
|
|
|
|
2016-06-09 10:56:14 +02:00
|
|
|
public String getLinkedClass() {
|
|
|
|
return linkedClass;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Integer getType() {
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "Property [name=" + name + ", description=" + description
|
|
|
|
+ ", mandatory=" + mandatory + ", readonly=" + readonly
|
|
|
|
+ ", notnull=" + notnull + ", max=" + max + ", min="
|
2016-07-05 12:34:13 +02:00
|
|
|
+ min + ", regexpr=" + regexpr + ", type = " + type
|
|
|
|
+ ", linkedType = " + linkedType + ", linkedClass = "
|
|
|
|
+ linkedClass + "]";
|
2016-06-09 10:56:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|