package org.kohsuke.github; import java.io.IOException; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; /** * An abstract data object builder/updater. * * This class can be use to make a Builder that supports both batch and single property changes. *
* Batching looks like this: *
* ** update().someName(value).otherName(value).done() **
* Single changes look like this: *
* ** set().someName(value); * set().otherName(value); **
* If {@link S} is the same as {@link R}, {@link #with(String, Object)} will commit changes after the first value change * and return a {@link R} from {@link #done()}. *
*
* If {@link S} is not the same as {@link R}, {@link #with(String, Object)} will batch together multiple changes and let
* the user call {@link #done()} when they are ready.
*
* @param
* Intermediate return type for this builder returned by calls to {@link #with(String, Object)}. If {@link S}
* the same as {@link R}, this builder will commit changes after each call to {@link #with(String, Object)}.
*/
abstract class AbstractBuilder intermediateReturnType,
@Nonnull GitHub root,
@CheckForNull R baseInstance) {
super(root);
this.requester = root.createRequest();
this.returnType = finalReturnType;
this.commitChangesImmediately = returnType.equals(intermediateReturnType);
if (!commitChangesImmediately && !intermediateReturnType.isInstance(this)) {
throw new IllegalArgumentException(
"Argument \"intermediateReturnType\": This instance must be castable to intermediateReturnType or finalReturnType must be equal to intermediateReturnType.");
}
this.baseInstance = baseInstance;
this.updateInPlace = false;
}
/**
* Finishes an update, committing changes.
*
* This method may update-in-place or not. Either way it returns the resulting instance.
*
* @return an instance with updated current data
* @throws IOException
* if there is an I/O Exception
*/
@Nonnull
@BetaApi
@Deprecated
public R done() throws IOException {
R result;
if (updateInPlace && baseInstance != null) {
result = requester.fetchInto(baseInstance);
} else {
result = requester.fetch(returnType);
}
return result;
}
/**
* Applies a value to a name for this builder.
*
* If {@link S} is the same as {@link R}, this method will commit changes after the first value change and return a
* {@link R} from {@link #done()}.
*
* If {@link S} is not the same as {@link R}, this method will return an {@link S} and letting the caller batch
* together multiple changes and call {@link #done()} when they are ready.
*
* @param name
* the name of the field
* @param value
* the value of the field
* @return either a continuing builder or an updated data record
* @throws IOException
* if an I/O error occurs
*/
@Nonnull
@BetaApi
@Deprecated
protected S with(@Nonnull String name, Object value) throws IOException {
requester.with(name, value);
return continueOrDone();
}
/**
* Chooses whether to return a continuing builder or an updated data record
*
* If {@link S} is the same as {@link R}, this method will commit changes after the first value change and return a
* {@link R} from {@link #done()}.
*
* If {@link S} is not the same as {@link R}, this method will return an {@link S} and letting the caller batch
* together multiple changes and call {@link #done()} when they are ready.
*
* @return either a continuing builder or an updated data record
* @throws IOException
* if an I/O error occurs
*/
@Nonnull
@BetaApi
@Deprecated
protected S continueOrDone() throws IOException {
// This little bit of roughness in this base class means all inheriting builders get to create Updater and
// Setter classes from almost identical code. Creator can often be implemented with significant code reuse as
// well.
if (commitChangesImmediately) {
// These casts look strange and risky, but they they're actually guaranteed safe due to the return path
// being based on the previous comparison of class instances passed to the constructor.
return (S) done();
} else {
return (S) this;
}
}
}