de.naturzukunft.rdf4j.ommapper.ModelCreator Maven / Gradle / Ivy
package de.naturzukunft.rdf4j.ommapper;
import static org.eclipse.rdf4j.model.util.Values.iri;
import static org.eclipse.rdf4j.model.util.Values.literal;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.apache.commons.lang3.ClassUtils;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Model;
import org.eclipse.rdf4j.model.Namespace;
import org.eclipse.rdf4j.model.util.ModelBuilder;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.rio.RDFFormat;
import org.eclipse.rdf4j.rio.Rio;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ModelCreator {
private T object;
public ModelCreator(T object) {
this.object = object;
}
public Model toModel(Namespace...namespace) {
List submodels = new ArrayList<>();
if(object.getSubject()==null) {
throw new RuntimeException("subject is mandatory!");
}
ModelBuilder modelBuilder = new ModelBuilder();
for (Namespace ns : namespace) {
modelBuilder.setNamespace(ns);
}
List fields = getFields(object.getClass());
for (Field field : fields) {
field.setAccessible(true);
Object value;
try {
value = field.get(object);
} catch (Exception e) {
throw new RuntimeException("error getting value of field " + field.getName(), e);
}
if(value!=null) {
Iri iri = field.getAnnotation(Iri.class);
if(iri!=null) {
if(value instanceof Collection) {
((Collection>) value).forEach(item->modelBuilder.add(object.getSubject(), iri(iri.value()), item));
} else if(isLiteral(value.getClass())){
modelBuilder.add(object.getSubject(), iri(iri.value()), value);
} else if(isIri(value)) {
modelBuilder.add(object.getSubject(), iri(iri.value()), value);
} else if(value instanceof Duration) {
try {
javax.xml.datatype.Duration duration = DatatypeFactory.newInstance().newDuration(((Duration)value).toMillis());
modelBuilder.add(object.getSubject(), iri(iri.value()), literal(duration.toString()));
} catch (DatatypeConfigurationException e) {
log.error("cannot convert duration '"+value.toString()+"'. ignoring it!", e);
}
} else if(value instanceof LocalDateTime) {
try {
XMLGregorianCalendar xmlDateTime = DatatypeFactory.newInstance().newXMLGregorianCalendar(((LocalDateTime)value).format(DateTimeFormatter.ISO_DATE_TIME));
modelBuilder.add(object.getSubject(), iri(iri.value()), literal(xmlDateTime.toString()));
} catch (DatatypeConfigurationException e) {
log.error("error converting dateTime: " + value, e);
}
} else if(BaseObject.class.isInstance(value))
{
ModelCreator> creator = new ModelCreator((BaseObject)value);
submodels.add(creator.toModel());
modelBuilder.add(object.getSubject(), iri(iri.value()), ((BaseObject)value).getSubject());
} else {
log.error("unknown field " + field);
}
}
} else {
if(field.getAnnotation(NonNull.class)!=null) {
throw new NonNullException(field.getName() + " is annotated with NonNull, but is null!");
}
}
}
Model result = modelBuilder.build();
if(result.filter(null, RDF.TYPE, null).size() < 1) {
StringWriter sw = new StringWriter();
Rio.write(result, sw, RDFFormat.TURTLE );
log.error("error processing: \n" + sw.toString());
throw new RuntimeException(RDF.TYPE + " is mandatory! ("+object.getClass().getName()+")");
}
submodels.forEach(sub->result.addAll(sub));
return result;
}
private List getFields(Class> cls) {
// return Arrays.asList(object.getClass().getDeclaredFields());
return getAllFields(new LinkedList(), cls);
}
private List getAllFields(List fields, Class> type) {
fields.addAll(Arrays.asList(type.getDeclaredFields()));
if (type.getSuperclass() != null) {
getAllFields(fields, type.getSuperclass());
}
return fields;
}
private boolean isIri(Object value) {
return IRI.class.isInstance(value);
}
private boolean isLiteral(Class> cls) {
return ClassUtils.isPrimitiveOrWrapper(cls) || BigInteger.class.equals(cls) || String.class.equals(cls);
}
}