code: package com.taxonic.carml.model.impl;
  
  import com.google.common.collect.ImmutableSet;
  import com.taxonic.carml.model.Resource;
  import com.taxonic.carml.model.TermMap;
  import com.taxonic.carml.model.TermType;
  import com.taxonic.carml.model.TriplesMap;
  import com.taxonic.carml.rdf_mapper.annotations.RdfProperty;
  import com.taxonic.carml.rdf_mapper.annotations.RdfType;
  import com.taxonic.carml.vocab.*;
  import java.util.Objects;
  import java.util.Set;
  import org.eclipse.rdf4j.model.Value;
  import org.eclipse.rdf4j.model.util.ModelBuilder;
  
  public abstract class CarmlTermMap extends CarmlResource implements TermMap {
  
  	String reference;
  	String inverseExpression;
  	String template;
  	TermType termType;
  	Value constant;
  	TriplesMap functionValue;
  
  	public CarmlTermMap() {
  		// Empty constructor for object mapper
  	}
  
  	public CarmlTermMap(
  		String reference,
  		String inverseExpression,
  		String template,
  		TermType termType,
  		Value constant,
  		TriplesMap functionValue
  	) {
  		this.reference = reference;
  		this.inverseExpression = inverseExpression;
  		this.template = template;
  		this.termType = termType;
  		this.constant = constant;
  		this.functionValue = functionValue;
  	}
  
  	@RdfProperty(Rml.reference)
  	@RdfProperty(value = Carml.multiReference, deprecated = true)
  	@Override
  	public String getReference() {
  		return reference;
  	}
  
  	@RdfProperty(Rr.inverseExpression)
  	@Override
  	public String getInverseExpression() {
  		return inverseExpression;
  	}
  
  	@RdfProperty(Rr.template)
  	@RdfProperty(value = Carml.multiTemplate, deprecated = true)
  	@Override
  	public String getTemplate() {
  		return template;
  	}
  
  	// TODO https://www.w3.org/TR/r2rml/#dfn-term-type
  	@RdfProperty(Rr.termType)
  	@Override
  	public TermType getTermType() {
  		return termType;
  	}
  
  	@RdfProperty(Rr.constant)
  	@Override
  	public Value getConstant() {
  		return constant;
  	}
  
  	@RdfProperty(Fnml.functionValue)
  	@RdfProperty(value = Carml.multiFunctionValue, deprecated = true)
  	@RdfType(CarmlTriplesMap.class)
  	@Override
  	public TriplesMap getFunctionValue() {
  		return functionValue;
  	}
  
  	public void setReference(String reference) {
  		this.reference = reference;
  	}
  
  	public void setInverseExpression(String inverseExpression) {
  		this.inverseExpression = inverseExpression;
  	}
  
  	public void setTemplate(String template) {
  		this.template = template;
  	}
  
  	public void setTermType(TermType termType) {
  		this.termType = termType;
  	}
  
  	public void setConstant(Value constant) {
  		this.constant = constant;
  	}
  
  	public void setFunctionValue(TriplesMap functionValue) {
  		this.functionValue = functionValue;
  	}
  
  	@Override
  	public int hashCode() {
  		return Objects.hash(reference, inverseExpression, template, termType, constant, functionValue);
  	}
  
  	@Override
  	public boolean equals(Object obj) {
  		if (this == obj) {
  			return true;
  		}
  		if (obj == null) {
  			return false;
  		}
  		if (getClass() != obj.getClass()) {
  			return false;
  		}
  		CarmlTermMap other = (CarmlTermMap) obj;
  		return Objects.equals(reference, other.reference) &&
  				Objects.equals(inverseExpression, other.inverseExpression) &&
  				Objects.equals(template, other.template) &&
  				Objects.equals(termType, other.termType) &&
  				Objects.equals(constant, other.constant) &&
  				Objects.equals(functionValue, other.functionValue);
  	}
  
  	Set<Resource> getReferencedResourcesBase() {
  		return functionValue != null ? ImmutableSet.of(functionValue) : ImmutableSet.of();
  	}
  
  	void addTriplesBase(ModelBuilder builder) {
  		if (reference != null) {
  			builder.add(Rml.reference, reference);
  		}
  		if (inverseExpression != null) {
  			builder.add(Rr.inverseExpression, inverseExpression);
  		}
  		if (template != null) {
  			builder.add(Rr.template, template);
  		}
  		if (termType != null) {
  			addTermTypeTriple(builder);
  		}
  		if (constant != null) {
  			builder.add(Rr.constant, constant);
  		}
  		if (functionValue != null) {
  			builder.add(Fnml.functionValue, functionValue.getAsResource());
  		}
  	}
  
  	private void addTermTypeTriple(ModelBuilder builder) {
  		switch (termType) {
  			case IRI:
  				builder.add(Rr.termType, Rdf.Rr.IRI);
  				break;
  			case LITERAL:
  				builder.add(Rr.termType, Rdf.Rr.Literal);
  				break;
  			case BLANK_NODE:
  				builder.add(Rr.termType, Rdf.Rr.BlankNode);
  				break;
  			default:
  				throw new IllegalStateException(String.format("Illegal term type value '%s' encountered.", termType));
  		}
  	}
  
  	public static class Builder {
  
  		String reference;
  		String inverseExpression;
  		String template;
  		TermType termType;
  		Value constant;
  		TriplesMap functionValue;
  
  		Builder reference(String reference) {
  			this.reference = reference;
  			return this;
  		}
  
  		Builder inverseExpression(String inverseExpression) {
  			this.inverseExpression = inverseExpression;
  			return this;
  		}
  
  		Builder template(String template) {
  			this.template = template;
  			return this;
  		}
  
  		Builder termType(TermType termType) {
  			this.termType = termType;
  			return this;
  		}
  
  		Builder constant(Value constant) {
  			this.constant = constant;
  			return this;
  		}
  
  		Builder functionValue(TriplesMap functionValue) {
  			this.functionValue = functionValue;
  			return this;
  		}
  
  		String getReference() {
  			return reference;
  		}
  
  		String getInverseExpression() {
  			return inverseExpression;
  		}
  
  		String getTemplate() {
  			return template;
  		}
  
  		TermType getTermType() {
  			return termType;
  		}
  
  		Value getConstant() {
  			return constant;
  		}
  
  		TriplesMap getFunctionValue() {
  			return functionValue;
  		}
  	}
  }
  