ValueBuilder.java
package com.brianmearns.crafter;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* A simple {@link BuilderInterface} for a single value. This is generally used as a utility inside another builder.
*
* @author Brian Mearns <bmearns@ieee.org>
*/
@SuppressWarnings("unused")
public abstract class ValueBuilder<T> implements BuilderInterface<T> {
/**
* Instantiate a new {@link ValueBuilder} initialized with the given <code>value</code>. I.e., when
* the {@link #get()} method is invoked, it will return <code>value</code> as the built object.
*
* @param value The value to which the returned builder is initialized.
* @param <T> The type which is built by the returned builder.
*/
@Nonnull
public static <T> ValueBuilder<T> create(@Nullable T value) {
return new DefaultValueBuilder<>(value);
}
/**
* Instantiate a new {@link ValueBuilder} initialized with the given <code>value</code>. I.e., when
* the {@link #get()} method is invoked, it will delegate to the given object.
*/
@Nonnull
public static <T> ValueBuilder<T> create(BuilderInterface<T> value) {
return new DefaultValueBuilder<>(value);
}
/**
* Create a new instance that does not yet have the value set.
*/
@Nonnull
public static <T> ValueBuilder<T> create() {
return new DefaultValueBuilder<>();
}
/**
* Create a new instance that does not yet have the value set.
*/
@Nonnull
public static <T> ValueBuilder<T> create(Class<T> cls) {
return new DefaultValueBuilder<>();
}
/**
* Returns a function which maps Builders of objects to ValueBuilders, using the {@link #create(BuilderInterface)}
* method.
*/
@Nonnull
public static <T> Function<BuilderInterface<T>, ValueBuilder<T>> ofBuilderFunction() {
return new ValueBuilderOfBuilderFunction<>();
}
/**
* Returns a function which maps values to ValueBuilders of that value, using the {@link #create(Object)}
* method.
*/
@Nonnull
public static <T> Function<T, ValueBuilder<T>> ofInstanceFunction() {
return new ValueBuilderOfInstanceFunction<>();
}
/**
* Sets the builder to use the given instance. The {@link #get()} method will return this instance as is.
*
* @return This {@code ValueBuilder} itself, for chaining convenience.
*/
@Nonnull
public ValueBuilder<T> set(@Nullable T value) {
return set(Suppliers.ofInstance(value));
}
/**
* Use the given builder to get the value of the instance. The builder is not invoked to build the value immediately,
* it will be invoked when <em>this</em> builder's {@link #get()} method is invoked.
*
* @return This {@code ValueBuilder} itself, for chaining convenience.
*/
@Nonnull
public ValueBuilder<T> set(@Nonnull BuilderInterface<T> valueBuilder) {
return set((Supplier<T>)valueBuilder);
}
/**
* Helper method to set the value that will be used by {@link #get()} to return a new instance.
*
* This is a helper method which {@link #set(BuilderInterface)} and {@link #set(Object)} delegate to. The public interface
* does not allow generic {@link Supplier} objects to be used to set the value.
*
* @return This {@code ValueBuilder} itself, for chaining convenience.
*/
@Nonnull
protected abstract ValueBuilder<T> set(@Nonnull Supplier<T> value);
/**
* Apply the given function to {@code this} object, and return {@code this} object again.
*
* <p>
* This is simply a way to add some arbitrary code in the middle of a chain of method invocations.
* You could use the {@link Function} to perform some complex logic to configure the builder, for instance.
*
* <p>
* The return value of the function is ignored, but for safety and clarity, it should be a void return.
*
* @param function The {@link Function} to be invoked on {@code this} object.
*
* @return This {@code ValueBuilder} itself, for chaining convenience.
*/
@Nonnull
protected abstract ValueBuilder<T> apply(@Nonnull Function<ValueBuilder<T>, Void> function);
@Nonnull
protected abstract ValueBuilder<T> maybeSet(@Nonnull Supplier<T> value, boolean doSet);
@Nonnull
public ValueBuilder<T> maybeSet(@Nullable T value, boolean doSet) {
this.maybeSet(Suppliers.ofInstance(value), doSet);
return this;
}
/**
* Build the value (if needed) and return it. If a value was given (as with {@link #set(Object)}), then it is simply
* returned. If a builder for a value was given (as with {@link #set(BuilderInterface)}), then this method delegates to
* that's builder's {@link BuilderInterface#get()} method.
*
* @return The built value.
* @throws IncompleteBuilderException if a value has not yet been set for the builder.
*/
@Nullable
@Override
public abstract T get() throws IncompleteBuilderException ;
/**
* Returns the top-level non-conditional builder.
*/
@Nonnull
public abstract ValueBuilder<T> always();
/**
* Returns a builder which either does or doesn't delegate to this builder based on the given boolean.
* @param yes If {@code true}, then methods invoked on the returned builder will modify the state of {@code this}
* builder. Otherwise, methods invoked on the returned builder will not modify state.
*/
@Nonnull
public abstract ValueBuilder<T> maybe(boolean yes);
/**
* Returns the parent builder of a conditional builder. This is not necessarily the originating top level
* builder if you have nested (or rather chained) calls to {@link #maybe(boolean)}.
*/
@Nonnull
public abstract ValueBuilder<T> endMaybe();
protected static class DefaultValueBuilder<T> extends ValueBuilder<T> {
/**
* A supplier for the value. Suppliers are used to encapsulate the fact that you can
* set the value using either a value directly, or a builder for the value.
*/
@Nonnull
private Optional<Supplier<T>> value = Optional.absent();
/**
* Create a new instance and {@linkplain #set(Object) set} the value to the given {@code value}.
*/
protected DefaultValueBuilder(@Nullable T value) {
set(value);
}
protected DefaultValueBuilder() {
}
/**
* Create a new instance and {@linkplain #set(BuilderInterface) set} the value using the given {@code builder}.
* The builder is not invoked to build the value immediately, it will be invoked when <em>this</em> builder's
* {@link #get()} method is invoked.
*/
protected DefaultValueBuilder(BuilderInterface<T> builder) {
set(builder);
}
@Nonnull
@Override
protected ValueBuilder<T> set(@Nonnull Supplier<T> value) {
this.value = Optional.of(value);
return this;
}
@Nonnull
@Override
protected ValueBuilder<T> maybeSet(@Nonnull Supplier<T> value, boolean doSet) {
if(doSet) {
set(value);
}
return this;
}
@Nullable
@Override
public T get() throws IncompleteBuilderException {
if(value.isPresent()) {
return value.get().get();
}
throw new IncompleteBuilderException("Builder value has not yet been set.");
}
@Override
@Nonnull
protected ValueBuilder<T> apply(@Nonnull Function<ValueBuilder<T>, Void> function) {
function.apply(this);
return this;
}
/**
* Returns itself.
*/
@Override
@Nonnull
public ValueBuilder<T> always() {
return this;
}
/**
* Returns either {@code this} object itself, or a new {@link NeverValueBuilder} if {@code yes} is {@code false}.
*/
@Override
@Nonnull
public ValueBuilder<T> maybe(boolean yes) {
if(yes) {
return this;
} else {
return new NeverValueBuilder<>(this, this);
}
}
@Nonnull
@Override
public ValueBuilder<T> endMaybe() {
return this;
}
}
/**
* A {@link ValueBuilder} which doesn't actually do anything.
*/
protected static class NeverValueBuilder<T> extends ValueBuilder<T> {
@Nonnull
private final ValueBuilder<T> alwaysBuilder;
@Nonnull
private final ValueBuilder<T> parent;
protected NeverValueBuilder(@Nonnull ValueBuilder<T> alwaysBuilder, @Nonnull ValueBuilder<T> parent) {
this.alwaysBuilder = alwaysBuilder;
this.parent = parent;
}
@Nonnull
@Override
protected ValueBuilder<T> set(@Nonnull Supplier<T> value) {
return this;
}
@Nonnull
@Override
protected ValueBuilder<T> apply(@Nonnull Function<ValueBuilder<T>, Void> function) {
return this;
}
@Nonnull
@Override
protected ValueBuilder<T> maybeSet(@Nonnull Supplier<T> value, boolean doSet) {
return this;
}
@Nullable
@Override
public T get() throws IncompleteBuilderException {
return alwaysBuilder.get();
}
@Nonnull
@Override
public ValueBuilder<T> always() {
return alwaysBuilder;
}
@Nonnull
@Override
public ValueBuilder<T> maybe(boolean yes) {
return new NeverValueBuilder<>(alwaysBuilder, this);
}
@Nonnull
@Override
public ValueBuilder<T> endMaybe() {
return parent;
}
}
/**
* A function that maps any value to a {@link ValueBuilder} {@linkplain #create(Object) of that instance}.
*/
protected static class ValueBuilderOfInstanceFunction<T> implements Function<T, ValueBuilder<T>> {
@Nullable
@Override
public ValueBuilder<T> apply(@Nullable T input) {
return create(input);
}
}
/**
* A function that maps any builder of a value to a {@link ValueBuilder} {@linkplain #create(BuilderInterface) of that builder}.
*/
protected static class ValueBuilderOfBuilderFunction<T> implements Function<BuilderInterface<T>, ValueBuilder<T>> {
@Nullable
@Override
public ValueBuilder<T> apply(BuilderInterface<T> input) {
if(input == null) {
throw new NullPointerException("Builder cannot be null. To create an instance with a null value, supply a null value instead of a null builder.");
}
return create(input);
}
}
}