code: package com.taxonic.carml.model.impl;
  
  import java.util.Optional;
  import java.util.Set;
  import java.util.function.BiConsumer;
  
  import javax.inject.Inject;
  
  import org.eclipse.rdf4j.model.IRI;
  import org.eclipse.rdf4j.model.Literal;
  import org.eclipse.rdf4j.model.Model;
  import org.eclipse.rdf4j.model.Resource;
  import org.eclipse.rdf4j.model.Value;
  
  import com.taxonic.carml.rdf_mapper.Mapper;
  import com.taxonic.carml.rdf_mapper.PropertyHandler;
  import com.taxonic.carml.rdf_mapper.impl.ComplexValueTransformer;
  import com.taxonic.carml.rdf_mapper.impl.MappingCache;
  import com.taxonic.carml.rdf_mapper.qualifiers.PropertyPredicate;
  import com.taxonic.carml.rdf_mapper.qualifiers.PropertySetter;
  
  public class LogicalSourceSourcePropertyHandler implements PropertyHandler {
  
  	private IRI predicate;
  	private BiConsumer<Object, Object> setter;
  	private Mapper mapper;
  	private MappingCache mappingCache;
  
  	private Optional<Object> determineValue(Model model, Resource resource) {
  		
  		Set<Value> objects = model.filter(resource, predicate, null).objects();
  		if (objects.size() > 1)
  			throw new RuntimeException("more than 1 object for the predicate [" + predicate + "] for a logical source");
  		
  		if (objects.isEmpty())
  			return Optional.empty();
  
  		Value object = objects.iterator().next();
  		
  		if (object instanceof Literal)
  			return Optional.of(object.stringValue());
  		
  		// map 'object' to some complex type
  		// TODO quite nasty to create the transformer here
  		ComplexValueTransformer transformer = new ComplexValueTransformer(
  			new LogicalSourceSourceTypeDecider(mapper),
  			mappingCache,
  			mapper,
  			o -> o
  		);
  		Object value = transformer.transform(model, object);
  		return Optional.of(value);
  	}
  	
  	@Override
  	public void handle(Model model, Resource resource, Object instance) {
  		
  		determineValue(model, resource)
  		
  		.ifPresent(value ->
  			setter.accept(instance, value)
  		);
  	}
  
  	@Override
  	public boolean hasEffect(Model model, Resource resource) {
  		return !model.filter(resource, predicate, null).isEmpty();
  	}
  
  	@Inject @PropertyPredicate
  	public void setPredicate(IRI predicate) {
  		this.predicate = predicate;
  	}
  	
  	@Inject @PropertySetter
  	public void setSetter(BiConsumer<Object, Object> setter) {
  		this.setter = setter;
  	}
  	
  	@Inject
  	public void setMapper(Mapper mapper) {
  		this.mapper = mapper;
  	}
  	
  	@Inject
  	public void setMappingCache(MappingCache mappingCache) {
  		this.mappingCache = mappingCache;
  	}
  	
  }
  