Skip to content

Commit

Permalink
Few enhancements in the builder framework
Browse files Browse the repository at this point in the history
- Infer the type of the Args class by looking it up through reflection
(`getEnclosingClass()`), so that there is no need for concrete builder
classes to implement the `build()` method.

- Change the generic type notations `<T, B>` to `<B, A>` to make them
more intuitive (`B -> Builder` and `A -> Args`)

- When inheriting from a parent builder class in an abstract builder
class like `BucketArgs.Builder`, pass the type parameters of the current
class (`<B, A>`) as is. This ensures that the builder methods,
irrespective of what order they're called in, will always return an
object with type of the original builder class.
  • Loading branch information
anjalshireesh committed May 18, 2020
1 parent 91cd2a7 commit 2d08918
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 17 deletions.
15 changes: 8 additions & 7 deletions api/src/main/java/io/minio/BaseArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,26 @@
import java.util.function.Consumer;

public abstract class BaseArgs {
public abstract static class BaseBuilder<T extends BaseBuilder<T, B>, B extends BaseArgs> {
protected List<Consumer<B>> operations;
public abstract static class Builder<B extends Builder<B, A>, A extends BaseArgs> {
protected List<Consumer<A>> operations;

public BaseBuilder() {
public Builder() {
this.operations = new ArrayList<>();
}

protected B build(Class<B> clazz) throws IllegalArgumentException {
@SuppressWarnings("unchecked") // safe as B will always be the builder of the current args class
public A build() throws IllegalArgumentException {
try {
B args = clazz.getDeclaredConstructor().newInstance();
A args = (A) this.getClass().getEnclosingClass().getDeclaredConstructor().newInstance();
operations.forEach(operation -> operation.accept(args));
return args;
} catch (InstantiationException
| IllegalAccessException
| InvocationTargetException
| NoSuchMethodException
| SecurityException e) {
// This should never happen as we'll always be
// sending a proper class as argument to build()
// This should never happen as we'll always have the
// Builder class as an enclosed class of the args class
e.printStackTrace();
return null;
}
Expand Down
12 changes: 6 additions & 6 deletions api/src/main/java/io/minio/BucketArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ public String region() {
}

/** Base argument builder class. */
public abstract static class Builder<T extends Builder<T, B>, B extends BucketArgs>
extends BaseArgs.BaseBuilder<Builder<T, B>, B> {
public abstract static class Builder<B extends Builder<B, A>, A extends BucketArgs>
extends BaseArgs.Builder<B, A> {
protected void validateName(String name) {
if (name == null) {
throw new IllegalArgumentException("null bucket name");
Expand Down Expand Up @@ -61,16 +61,16 @@ protected void validateName(String name) {
}

@SuppressWarnings("unchecked") // Its safe to type cast to T as T is inherited by this class
public T bucket(String name) {
public B bucket(String name) {
validateName(name);
operations.add(args -> args.name = name);
return (T) this;
return (B) this;
}

@SuppressWarnings("unchecked") // Its safe to type cast to T as T is inherited by this class
public T region(String region) {
public B region(String region) {
operations.add(args -> args.region = region);
return (T) this;
return (B) this;
}
}
}
4 changes: 0 additions & 4 deletions api/src/main/java/io/minio/MakeBucketArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,5 @@ public Builder objectLock(boolean objectLock) {
operations.add(args -> args.objectLock = objectLock);
return this;
}

public MakeBucketArgs build() throws IllegalArgumentException {
return build(MakeBucketArgs.class);
}
}
}

0 comments on commit 2d08918

Please sign in to comment.