Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
de.naturzukunft.rdf4j.ommapper.Converter Maven / Gradle / Ivy
package de.naturzukunft.rdf4j.ommapper;
import static org.eclipse.rdf4j.model.util.Values.iri;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TimeZone;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.Model;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.rio.RDFFormat;
import org.eclipse.rdf4j.rio.Rio;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Converter {
private Class cls;
public Converter(Class cls) {
this.cls = cls;
}
public Optional fromModel(IRI subject, Model model) {
log.debug("->fromModel("+subject+")");
Constructor constructor = getConstructor(cls);
if(model.filter(subject, null, null).size() == 0) {
log.warn("no statements for " + subject);
log.info("<- fromModel(...");
return Optional.empty();
}
StringWriter sw = new StringWriter();
Rio.write(model, sw, RDFFormat.TURTLE);
log.debug("model: " + sw.toString());
try {
T instance = constructor.newInstance();
Map fieldsByIri = getFieldsByIri(cls);
List nonNullFileds = getNonNullFields(cls);
Model filtered = model.filter(subject, null, null);
log.debug("model filtered by subject. Statements after filtering: " + filtered.size());
filtered.forEach(stmt->{
log.debug("processing statement: " + stmt);
IRI predicate = stmt.getPredicate();
Field field = fieldsByIri.get(predicate);
log.trace("fieldsByIri.get("+predicate+") -> " + field );
Value stmtObject = stmt.getObject();
if(field!=null) {
try {
log.debug("matching field (reflection): ("+field.getName()+ ") literal ("+stmtObject+") type ("+field.getType().getName()+")" );
if (Collection.class.isAssignableFrom(field.getType())) {
handleSetForCollection(instance, field, stmtObject);
} else
if(stmtObject.isLiteral()) {
setValue(instance, field, (Literal)stmtObject);
} else if(stmtObject.isIRI()) {
if (Collection.class.isAssignableFrom(field.getType())) { // TODO remove
handleSetForCollection(instance, field, stmtObject);
}
else if(stmtObject.isResource()) {
Iri iriAnnotation = field.getAnnotation(Iri.class);
log.debug("iriAnnotation of " + field.getName() + ": " + iriAnnotation);
if(iriAnnotation!=null && !field.getType().equals(org.eclipse.rdf4j.model.IRI.class)) {
log.debug("field is reference to: (DELETE ME, just for debugging reasons) ");
log.debug("field is reference to: " + iriAnnotation.value());
Converter> converter = new Converter(field.getType());
log.debug("calling converter for subtype: " + field.getName() + "("+field.getType()+")");
Optional> subObjectOptional = converter.fromModel((IRI)stmtObject, model);
if(subObjectOptional.isPresent()) {
field.set(instance, subObjectOptional.get());
} else {
log.warn("Optional.empty() -> " + iriAnnotation.value() + "(" +stmtObject +")");
}
} else {
log.info("isn't it a bug to set a value here ?");
field.set(instance, iri(stmtObject.toString()));
}
}
}
} catch (Exception e) {
if(e instanceof NonNullException) {
throw (NonNullException)e;
} else {
String name = null;
if(field != null) {
name = field.getName();
}
throw new RuntimeException("error setting value of field " + name, e);
}
}
}
});
setSubject(subject, instance);
nonNullFileds.stream().forEach(it-> {
try {
if(it.get(instance) == null) {
throw new NonNullException(it.getName() + " is annotated with NonNull, but is null!");
}
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException("error checking NonNull" + it, e);
}
});
log.debug("<- fromModel(...");
return Optional.ofNullable(instance);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
log.info("<- fromModel(...");
throw new RuntimeException("error instantiating constructor", e1);
}
}
private void setSubject(IRI subject, T instance) throws IllegalAccessException {
try {
List fields = getFields(instance.getClass());
Field subjectField = fields.stream().filter(field->field.getName().equals("subject")).findFirst().get();
subjectField.set(instance, subject);
} catch (SecurityException e) {
throw new RuntimeException("error setting subject", e);
}
}
private Constructor getConstructor(Class cls) {
Constructor constructor;
try {
constructor = cls.getConstructor();
} catch (NoSuchMethodException e1) {
throw new RuntimeException("NoArg Constructor is mandatory! " + cls.getName());
}
return constructor;
}
private void handleSetForCollection(T instance, Field field, Value object)
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Object collection = field.get(instance);
if(collection==null) {
field.set(instance, new HashSet<>());
collection = field.get(instance);
}
java.lang.reflect.Method add = Collection.class.getDeclaredMethod("add",Object.class);
if( object.isLiteral() )
{
String value = object.stringValue();
add.invoke(collection, value);
} else if( object.isIRI()) {
String value = object.stringValue();
add.invoke(collection, iri(value));
}
}
private List getFields(Class> cls) {
List fields =getAllFields(new LinkedList(), cls);
fields.forEach(field->field.setAccessible(true));
return fields;
}
private List getAllFields(List fields, Class> type) {
fields.addAll(Arrays.asList(type.getDeclaredFields()));
if (type.getSuperclass() != null) {
getAllFields(fields, type.getSuperclass());
}
return fields;
}
private void setValue(T instance, Field field, Literal object) throws IllegalArgumentException, IllegalAccessException {
switch (field.getType().getName()) {
case "java.lang.Boolean":
case "boolean":
field.set(instance, object.booleanValue());
break;
case "java.lang.Byte":
case "byte":
field.set(instance, object.byteValue());
break;
// case "char":
// case "java.lang.Char":
// Character chatr = Character.valueOf(object.byteValue());
// field.set(instance, chatr);
// break;
case "java.lang.Double":
case "double":
field.set(instance, object.doubleValue());
break;
case "java.lang.Float":
case "float":
field.set(instance, object.floatValue());
break;
case "java.math.BigInteger":
field.set(instance, object.integerValue());
break;
case "java.lang.Integer":
case "int":
field.set(instance, object.intValue());
break;
case "java.lang.Long":
case "long":
field.set(instance, object.longValue());
break;
case "java.lang.Short":
case "short":
field.set(instance, object.shortValue());
break;
case "java.lang.String":
field.set(instance, object.stringValue());
break;
case "java.time.LocalDateTime":
XMLGregorianCalendar xmlGregorianCalendar = object.calendarValue();
GregorianCalendar gregorianCalendar = xmlGregorianCalendar.toGregorianCalendar();
TimeZone tz = gregorianCalendar.getTimeZone();
ZoneId zoneId = tz.toZoneId();
Instant instant = gregorianCalendar.toInstant();
LocalDateTime localDate = LocalDateTime.ofInstant(instant, zoneId);
field.set(instance, localDate);
break;
case "java.time.Duration":
try {
Duration d = DatatypeFactory.newInstance().newDuration(object.stringValue());
java.time.Duration timeDuration = java.time.Duration.ofMillis(d.getTimeInMillis(Calendar.getInstance()));
field.set(instance, timeDuration);
} catch (DatatypeConfigurationException e) {
log.error("error setting duration from value " + object.stringValue(), e);
}
break;
default:
log.warn("setValue DEFAULT is called for field ("+field.getName()+ ") literal ("+object+") type ("+field.getType().getName()+")" );
// Iri iriAnnotation = field.getAnnotation(Iri.class);
// if(iriAnnotation!=null) {
// log.debug("field is reference to: " + iriAnnotation.value());
// fromModel(field.getType(), iriAnnotation.value(), model);
// } else {
field.set(instance, object.stringValue());
// }
break;
}
}
private Map getFieldsByIri(Class cls) {
Map response = new HashMap<>();
List fields = getFields(cls);
for (Field field : fields) {
log.trace("getFieldsByIri(): processing field " + field.getName());
List asList = Arrays.asList(field.getAnnotations());
Optional annotation = asList.stream().filter(anno->anno.annotationType().equals(Iri.class)).findFirst();
if(annotation.isPresent()) {
String fieldIri = field.getAnnotation(Iri.class).value();
response.put(iri(fieldIri), field);
}
}
return response;
}
private List getNonNullFields(Class cls) {
List response = new ArrayList<>();
List fields = getFields(cls);
for (Field field : fields) {
List asList = Arrays.asList(field.getAnnotations());
Optional annotation = asList.stream().filter(anno->anno.annotationType().equals(de.naturzukunft.rdf4j.ommapper.NonNull.class)).findFirst();
if(annotation.isPresent()) {
response.add(field);
log.trace("getNonNullFields(): processing field " + field.getName() + " NoneNull -> TRUE");
}
}
return response;
}
}