338 lines
12 KiB
Java
338 lines
12 KiB
Java
package org.gcube.informationsystem.types;
|
|
|
|
import java.lang.reflect.Field;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
|
|
import org.gcube.informationsystem.model.annotations.ISEmbeddedType;
|
|
import org.gcube.informationsystem.model.annotations.ISEntity;
|
|
import org.gcube.informationsystem.model.annotations.ISFacet;
|
|
import org.gcube.informationsystem.model.annotations.ISProperty;
|
|
import org.gcube.informationsystem.model.annotations.ISPropertyRef;
|
|
import org.gcube.informationsystem.model.annotations.ISResource;
|
|
import org.gcube.informationsystem.model.entity.Entity;
|
|
import org.gcube.informationsystem.model.entity.Facet;
|
|
import org.gcube.informationsystem.model.entity.Resource;
|
|
import org.gcube.informationsystem.types.Type.OType;
|
|
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 final String DEFAULT_FACET_SUPERCLASS = "Facet";
|
|
private static final String DEFAULT_RESOURCE_SUPERCLASS = "Entity";
|
|
private static final String DEFAULT_ENTITY_SUPERCLASS = "Entity";
|
|
|
|
private static Logger logger = LoggerFactory.getLogger(TypeBinder.class);
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static String serializeEntity(Class<Entity> type) throws Exception{
|
|
if(type.isAssignableFrom(Resource.class)){
|
|
return serializeResource((Class<? extends Resource>) type);
|
|
}else if(type.isAssignableFrom(Facet.class)){
|
|
return serializeFacet((Class<? extends Facet>) type);
|
|
}
|
|
|
|
if (!type.isAnnotationPresent(ISEntity.class))
|
|
throw new IllegalArgumentException("the class "+type.getCanonicalName()+" must be annotated with @ISEntity");
|
|
TypeDefinition def = createEntityDefinition(type);
|
|
ObjectMapper mapper = new ObjectMapper();
|
|
String json = mapper.writeValueAsString(def);
|
|
return json;
|
|
}
|
|
|
|
public static String serializeResource(Class<? extends Resource> type) throws Exception{
|
|
if (!type.isAnnotationPresent(ISResource.class))
|
|
throw new IllegalArgumentException("the class "+type.getCanonicalName()+" must be annotated with @ISResource");
|
|
TypeDefinition def = createResourceDefinition(type);
|
|
ObjectMapper mapper = new ObjectMapper();
|
|
String json = mapper.writeValueAsString(def);
|
|
return json;
|
|
}
|
|
|
|
public static String serializeFacet(Class<? extends Facet> type) throws Exception{
|
|
if (!type.isAnnotationPresent(ISFacet.class))
|
|
throw new IllegalArgumentException("the class "+type.getCanonicalName()+" must be annotated with @ISFacet");
|
|
TypeDefinition def = createFacetDefinition(type);
|
|
ObjectMapper mapper = new ObjectMapper();
|
|
String json = mapper.writeValueAsString(def);
|
|
return json;
|
|
}
|
|
|
|
public static String serializeEmbeddedType(Class<?> embeddedTypeClass) throws Exception{
|
|
if (!embeddedTypeClass.isAnnotationPresent(ISEmbeddedType.class))
|
|
throw new IllegalArgumentException("the class "+embeddedTypeClass.getSimpleName()+" must be annotated with @ISEmbeddedType");
|
|
TypeDefinition def = createEmbeddedDefintion(embeddedTypeClass);
|
|
ObjectMapper mapper = new ObjectMapper();
|
|
String json = mapper.writeValueAsString(def);
|
|
return json;
|
|
}
|
|
|
|
private static TypeDefinition createEmbeddedDefintion(Class<?> type){
|
|
ISEmbeddedType isType = type.getAnnotation(ISEmbeddedType.class);
|
|
TypeDefinition typeDefinition = new TypeDefinition();
|
|
String name = isType.name().isEmpty()?type.getSimpleName():isType.name();
|
|
typeDefinition.name = name;
|
|
typeDefinition.description = isType.description();
|
|
typeDefinition.properties = retrieveListOfProperties(type);
|
|
typeDefinition.abstractType = isType.abstractType();
|
|
logger.trace("retrieved type definition {} ",typeDefinition);
|
|
return typeDefinition;
|
|
}
|
|
|
|
private static TypeDefinition createEntityDefinition(Class<? extends Entity> type){
|
|
ISEntity isType = type.getAnnotation(ISEntity.class);
|
|
TypeDefinition typeDefinition = new TypeDefinition();
|
|
String name = isType.name().isEmpty()?type.getSimpleName():isType.name();
|
|
typeDefinition.name = name;
|
|
typeDefinition.description = isType.description();
|
|
typeDefinition.properties = retrieveListOfProperties(type);
|
|
typeDefinition.abstractType = isType.abstractType();
|
|
|
|
if (name.equals(DEFAULT_ENTITY_SUPERCLASS)) {
|
|
typeDefinition.superclasses = Collections.singletonList("V");
|
|
} else {
|
|
String superClassName = retrieveSuperClasses(type);
|
|
typeDefinition.superclasses = Collections.singletonList(superClassName.isEmpty()?DEFAULT_ENTITY_SUPERCLASS:superClassName);
|
|
}
|
|
|
|
logger.trace("retrieved type definition {} ",typeDefinition);
|
|
return typeDefinition;
|
|
}
|
|
|
|
private static TypeDefinition createResourceDefinition(Class<? extends Resource> type){
|
|
ISResource isResource = type.getAnnotation(ISResource.class);
|
|
TypeDefinition typeDefinition = new TypeDefinition();
|
|
String name = isResource.name().isEmpty()?type.getSimpleName():isResource.name();
|
|
typeDefinition.name = name;
|
|
typeDefinition.description = isResource.description();
|
|
//typeDefinition.properties = retrieveListOfProperties(type);
|
|
typeDefinition.abstractType = isResource.abstractType();
|
|
|
|
if (name.equals(DEFAULT_RESOURCE_SUPERCLASS)) {
|
|
typeDefinition.superclasses = Collections.singletonList(DEFAULT_ENTITY_SUPERCLASS);
|
|
} else {
|
|
String superClassName = retrieveSuperClasses(type);
|
|
typeDefinition.superclasses = Collections.singletonList(superClassName.isEmpty()?DEFAULT_RESOURCE_SUPERCLASS:superClassName);
|
|
}
|
|
|
|
logger.trace("retrieved type definition {} ",typeDefinition);
|
|
return typeDefinition;
|
|
}
|
|
|
|
|
|
private static TypeDefinition createFacetDefinition(Class<? extends Facet> type){
|
|
ISFacet isFacet = type.getAnnotation(ISFacet.class);
|
|
TypeDefinition typeDefinition = new TypeDefinition();
|
|
String name = isFacet.name().isEmpty()?type.getSimpleName():isFacet.name();
|
|
typeDefinition.name = name;
|
|
typeDefinition.properties = retrieveListOfProperties(type);
|
|
typeDefinition.description = isFacet.description();
|
|
typeDefinition.abstractType = isFacet.abstractType();
|
|
if (name.equals(DEFAULT_FACET_SUPERCLASS)) {
|
|
typeDefinition.superclasses = Collections.singletonList(DEFAULT_ENTITY_SUPERCLASS);
|
|
} else {
|
|
String superClassName = retrieveSuperClasses(type);
|
|
typeDefinition.superclasses = Collections.singletonList(superClassName.isEmpty()?DEFAULT_FACET_SUPERCLASS:superClassName);
|
|
}
|
|
|
|
logger.trace("retrieved type definition {} ",typeDefinition);
|
|
|
|
return typeDefinition;
|
|
}
|
|
|
|
private static List<Property> retrieveListOfProperties(Class<?> type){
|
|
List<Property> properties = new ArrayList<TypeBinder.Property>();
|
|
for (Field f:type.getDeclaredFields()){
|
|
f.setAccessible(true);
|
|
if (f.isAnnotationPresent(ISPropertyRef.class)){
|
|
ISPropertyRef refAnnotation = f.getAnnotation(ISPropertyRef.class);
|
|
Property prop = getProperty(refAnnotation, f);
|
|
properties.add(prop);
|
|
logger.trace("property {} retrieved in type {} ",prop, type.getSimpleName());
|
|
|
|
}else if (f.isAnnotationPresent(ISProperty.class)){
|
|
ISProperty propAnnotation = f.getAnnotation(ISProperty.class);
|
|
Property prop = getProperty(propAnnotation, f);
|
|
properties.add(prop);
|
|
logger.trace("property {} retrieved in type {} ",prop, type.getSimpleName());
|
|
}
|
|
|
|
}
|
|
return properties;
|
|
}
|
|
|
|
private static Property getProperty(ISPropertyRef refPropertyAnnotation, Field field){
|
|
if (!refPropertyAnnotation.ref().isAnnotationPresent(ISEmbeddedType.class)) throw new RuntimeException("class "+refPropertyAnnotation.ref().getSimpleName()+" must be annotated with @ISEmbeddedType");
|
|
ISEmbeddedType embeddedTypeAnn= refPropertyAnnotation.ref().getAnnotation(ISEmbeddedType.class);
|
|
String link = embeddedTypeAnn.name().isEmpty()?refPropertyAnnotation.ref().getSimpleName():embeddedTypeAnn.name();
|
|
|
|
String name = refPropertyAnnotation.name().isEmpty()?field.getName():refPropertyAnnotation.name();
|
|
Property prop = new Property();
|
|
prop.name = name;
|
|
prop.description = refPropertyAnnotation.description();
|
|
prop.mandatory= refPropertyAnnotation.mandatory();
|
|
prop.notnull = !refPropertyAnnotation.nullable();
|
|
prop.readonly = refPropertyAnnotation.readonly();
|
|
if(refPropertyAnnotation.max()>0) prop.max = refPropertyAnnotation.max();
|
|
if(refPropertyAnnotation.max()>=refPropertyAnnotation.min() && refPropertyAnnotation.min()>0) prop.min = refPropertyAnnotation.min();
|
|
if(!refPropertyAnnotation.regexpr().isEmpty()) prop.regexpr = refPropertyAnnotation.regexpr();
|
|
logger.trace("serching correspondance for type {}",field.getType());
|
|
if (Type.getTypeByClass(field.getType())!=null)
|
|
prop.type = Type.getTypeByClass(field.getType()).getIntValue();
|
|
|
|
prop.linkedClass = link;
|
|
|
|
if (prop.type==null)
|
|
prop.type = OType.EMBEDDED.getIntValue();
|
|
|
|
return prop;
|
|
}
|
|
|
|
private static Property getProperty(ISProperty propertyAnnotation, Field field){
|
|
String name = propertyAnnotation.name().isEmpty()?field.getName():propertyAnnotation.name();
|
|
Property prop = new Property();
|
|
prop.name = name;
|
|
prop.description = propertyAnnotation.description();
|
|
prop.mandatory= propertyAnnotation.mandatory();
|
|
prop.notnull = !propertyAnnotation.nullable();
|
|
prop.readonly = propertyAnnotation.readonly();
|
|
if(propertyAnnotation.max()>0) prop.max = propertyAnnotation.max();
|
|
if(propertyAnnotation.max()>=propertyAnnotation.min() && propertyAnnotation.min()>0) prop.min = propertyAnnotation.min();
|
|
if(!propertyAnnotation.regexpr().isEmpty()) prop.regexpr = propertyAnnotation.regexpr();
|
|
logger.trace("serching correspondance for type {}",field.getType());
|
|
if (Type.getTypeByClass(field.getType())!=null)
|
|
prop.type = Type.getTypeByClass(field.getType()).getIntValue();
|
|
else throw new RuntimeException("type "+field.getType().getSimpleName()+" not reconized");
|
|
return prop;
|
|
}
|
|
|
|
private static String retrieveSuperClasses(Class<?> type){
|
|
Class<?> superclass = type.getSuperclass();
|
|
if (superclass!=null && Facet.class.isAssignableFrom(superclass)){
|
|
if (superclass.isAnnotationPresent(ISFacet.class)){
|
|
ISFacet superIsType = superclass.getAnnotation(ISFacet.class);
|
|
String superTypeName = superIsType.name().isEmpty()?superclass.getSimpleName():superIsType.name();
|
|
return superTypeName;
|
|
} else
|
|
return retrieveSuperClasses(superclass);
|
|
}
|
|
return "";
|
|
}
|
|
|
|
|
|
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
|
|
public static class TypeDefinition{
|
|
|
|
private String name;
|
|
private String description;
|
|
private boolean abstractType;
|
|
private List<String> superclasses;
|
|
private List<Property> properties;
|
|
|
|
@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;
|
|
}
|
|
|
|
public List<String> getSuperclasses() {
|
|
return superclasses;
|
|
}
|
|
|
|
public List<Property> getProperties() {
|
|
return properties;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
|
|
public static class Property{
|
|
|
|
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;
|
|
private String regexpr= null;
|
|
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;
|
|
}
|
|
|
|
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="
|
|
+ min + ", regexpr=" + regexpr + ", linkedClass = "+linkedClass+"]";
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|