# ValueAccessPointVariantSupport.java

    package org.codefilarete.stalactite.engine.configurer;

    import java.lang.reflect.Field;

    import org.codefilarete.reflection.AccessorByField;
    import org.codefilarete.reflection.ReversibleAccessor;
    import org.codefilarete.tool.Reflections;
    import org.codefilarete.tool.function.ThreadSafeLazyInitializer;
    import org.danekja.java.util.function.serializable.SerializableBiConsumer;
    import org.danekja.java.util.function.serializable.SerializableFunction;

    /**
     * Storage for different ways of declaring an attribute accessor: for each case, a constructor is available. Either by accessor, or mutator, or field.
     * The output is a {@link ReversibleAccessor} based on the attribute accessor given at construction time. The resolution is made through
     * {@link PropertyAccessorResolver}.
     *
     * @param <T> the owning type of the attribute
     * @param <O> attribute type
     * @author Guillaume Mary
     */
    public class ValueAccessPointVariantSupport<T, O> {

    	private final ThreadSafeLazyInitializer<ReversibleAccessor<T, O>> accessor;

    	private SerializableFunction<T, O> getter;

    	private SerializableBiConsumer<T, O> setter;

    	// to be used in addition to getter or setter when attribute differs from method name (case when Java Naming Convention is not respected)
    	private Field field;

    	public ValueAccessPointVariantSupport(SerializableFunction<T, O> getter) {
    		this.getter = getter;
    		this.accessor = new AccessorFieldLazyInitializer();
    	}

    	public ValueAccessPointVariantSupport(SerializableBiConsumer<T, O> setter) {
    		this.setter = setter;
    		this.accessor = new AccessorFieldLazyInitializer();
    	}

    	public ValueAccessPointVariantSupport(Class persistedClass, String fieldName) {
    		this.accessor = new ThreadSafeLazyInitializer<ReversibleAccessor<T, O>>() {
    			@Override
    			protected ReversibleAccessor<T, O> createInstance() {
    				return new AccessorByField<>(Reflections.getField(persistedClass, fieldName));
    			}
    		};
    	}

    	public void setField(Class persistedClass, String fieldName) {
    		this.field = Reflections.getField(persistedClass, fieldName);;
    	}

    	public ReversibleAccessor<T, O> getAccessor() {
    		return accessor.get();
    	}

    	/**
    	 * Internal class that computes a {@link ReversibleAccessor} from getter or setter according to which one is set up
    	 */
    	private class AccessorFieldLazyInitializer extends ThreadSafeLazyInitializer<ReversibleAccessor<T, O>> {

    		@Override
    		protected ReversibleAccessor<T, O> createInstance() {
    			return new PropertyAccessorResolver<>(new PropertyAccessorResolver.PropertyMapping<T, O>() {

    				@Override
    				public SerializableFunction<T, O> getGetter() {
    					return ValueAccessPointVariantSupport.this.getter;
    				}

    				@Override
    				public SerializableBiConsumer<T, O> getSetter() {
    					return ValueAccessPointVariantSupport.this.setter;
    				}

    				@Override
    				public Field getField() {
    					return ValueAccessPointVariantSupport.this.field;
    				}
    			}).resolve();
    		}
    	}
    }