# EntityMappingConfiguration.java

    package org.codefilarete.stalactite.dsl.entity;

    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.function.Consumer;
    import java.util.function.Function;
    import javax.annotation.Nullable;

    import org.codefilarete.reflection.ReadWritePropertyAccessPoint;
    import org.codefilarete.reflection.ValueAccessPoint;
    import org.codefilarete.stalactite.dsl.MappableSuperClassConfiguration;
    import org.codefilarete.stalactite.dsl.PolymorphismPolicy;
    import org.codefilarete.stalactite.dsl.RelationalMappingConfiguration;
    import org.codefilarete.stalactite.dsl.embeddable.EmbeddableMappingConfiguration;
    import org.codefilarete.stalactite.dsl.idpolicy.IdentifierPolicy;
    import org.codefilarete.stalactite.dsl.key.CompositeKeyMappingConfigurationProvider;
    import org.codefilarete.stalactite.dsl.naming.AssociationTableNamingStrategy;
    import org.codefilarete.stalactite.dsl.naming.ColumnNamingStrategy;
    import org.codefilarete.stalactite.dsl.naming.ElementCollectionTableNamingStrategy;
    import org.codefilarete.stalactite.dsl.naming.ForeignKeyNamingStrategy;
    import org.codefilarete.stalactite.dsl.naming.JoinColumnNamingStrategy;
    import org.codefilarete.stalactite.dsl.naming.MapEntryTableNamingStrategy;
    import org.codefilarete.stalactite.dsl.naming.TableNamingStrategy;
    import org.codefilarete.stalactite.dsl.naming.UniqueConstraintNamingStrategy;
    import org.codefilarete.stalactite.sql.ddl.Size;
    import org.codefilarete.stalactite.sql.ddl.structure.Table;
    import org.codefilarete.stalactite.sql.result.ColumnedRow;
    import org.codefilarete.tool.collection.ReadOnlyIterator;

    import static org.codefilarete.tool.Nullable.nullable;

    /**
     * Defines elements needed to configure a mapping of an entity class
     *
     * @author Guillaume Mary
     */
    public interface EntityMappingConfiguration<C, I> extends MappableSuperClassConfiguration<C>, RelationalMappingConfiguration<C> {

    	@Nullable
    	EntityFactoryProvider<C, ?> getEntityFactoryProvider();

    	/**
    	 * Gives the table owning entity data.
    	 * @return may return null, then a table name will be deduced from entity name and {@link TableNamingStrategy}
    	 */
    	@Nullable
    	Table getTable();

    	@Nullable
    	TableNamingStrategy getTableNamingStrategy();

    	@Nullable
    	ColumnNamingStrategy getColumnNamingStrategy();

    	KeyMapping<C, I> getKeyMapping();

    	EmbeddableMappingConfiguration<C> getPropertiesMapping();

    	@Nullable
    	OptimisticLockOption<C, ?> getOptimisticLockOption();

    	/**
    	 * Returns the parent configuration. Information is taken on the {@link #getInheritanceConfiguration()} instance.
    	 * <strong>Be aware that the caller may take the {@link InheritanceConfiguration#isJoiningTables()} option
    	 * into account for a complete behavior</strong>
    	 *
    	 * @return the configuration of a parent type
    	 */
    	@Nullable
    	@Override
    	default EntityMappingConfiguration<? super C, I> getMappedSuperClassConfiguration() {
    		return nullable(getInheritanceConfiguration()).map(InheritanceConfiguration::getParentMappingConfiguration).get();
    	}

    	/** Gives inheritance information if inheritance has been defined, else returns null */
    	@SuppressWarnings("squid:S1452" /* Can't remove wildcard here because it requires to create a local generic "super" type which is forbidden */)
    	@Nullable
    	InheritanceConfiguration<C, I> getInheritanceConfiguration();

    	@Nullable
    	ForeignKeyNamingStrategy getForeignKeyNamingStrategy();

    	@Nullable
    	UniqueConstraintNamingStrategy getUniqueConstraintNamingStrategy();

    	@Nullable
    	AssociationTableNamingStrategy getAssociationTableNamingStrategy();

    	@Nullable
    	ElementCollectionTableNamingStrategy getElementCollectionTableNamingStrategy();

    	@Nullable
    	JoinColumnNamingStrategy getJoinColumnNamingStrategy();

    	/**
    	 * Gives {@link ColumnNamingStrategy} for index column of one-to-many {@link List} association
    	 * @return maybe null, {@link ColumnNamingStrategy#INDEX_DEFAULT} will be used instead
    	 */
    	@Nullable
    	ColumnNamingStrategy getIndexColumnNamingStrategy();

    	@Nullable
    	MapEntryTableNamingStrategy getEntryMapTableNamingStrategy();

    	PolymorphismPolicy<C> getPolymorphismPolicy();

    	/**
    	 * Returns an {@link Iterable} over all mapped super class configurations.
    	 *
    	 * @return an iterable for all inheritance configurations, including this
    	 */
    	@Override
    	default Iterable<EntityMappingConfiguration<?, I>> inheritanceIterable() {
    		// overridden to specialize the result
    		Iterable<? extends MappableSuperClassConfiguration<?>> superIterable = MappableSuperClassConfiguration.super.inheritanceIterable();
    		return () -> new ReadOnlyIterator<EntityMappingConfiguration<?, I>>() {
    			private final Iterator<? extends MappableSuperClassConfiguration<?>> delegate = superIterable.iterator();

    			@Override
    			public boolean hasNext() {
    				return delegate.hasNext();
    			}

    			@Override
    			public EntityMappingConfiguration<?, I> next() {
    				return (EntityMappingConfiguration<?, I>) delegate.next();
    			}
    		};
    	}

    	interface EntityFactoryProvider<C, T extends Table> {

    		Function<ColumnedRow, C> giveEntityFactory(T table);

    		boolean isIdentifierSetByFactory();
    	}

    	interface InheritanceConfiguration<E, I> {

    		/** Entity configuration */
    		EntityMappingConfiguration<E, I> getParentMappingConfiguration();

    		/**
    		 * Tells if the super configuration table must be stored on a separate table and joined to the current one
    		 * @return true if the super configuration table must be stored on a separate table and joined to the current one
    		 */
    		boolean isJoiningTables();
    	}

    	interface KeyMapping<C, I> {

    		ReadWritePropertyAccessPoint<C, I> getAccessor();

    		boolean isSetByConstructor();
    	}

    	interface SingleKeyMapping<C, I> extends KeyMapping<C, I> {

    		IdentifierPolicy<I> getIdentifierPolicy();

    		ColumnLinkageOptions getColumnOptions();

    		@Nullable
    		String getFieldName();
    	}

    	interface CompositeKeyMapping<C, I> extends KeyMapping<C, I> {

    		Consumer<C> getMarkAsPersistedFunction();

    		Function<C, Boolean> getIsPersistedFunction();

    		CompositeKeyMappingConfigurationProvider<I> getCompositeKeyMappingBuilder();
    	}

    	interface ColumnLinkageOptions {

    		@Nullable
    		String getColumnName();

    		@Nullable
    		Size getColumnSize();

    	}

    	interface CompositeKeyLinkageOptions {

    		Map<ValueAccessPoint, String> getColumnsNames();

    	}
    }