How can I use generics propery in my particular case? The code first, then the explanation:
AbstractConstraint.java
public abstract class AbstractConstraint {
public abstract Constraint[] getConstraints();
}
AccountConstraint.java
public class AccountConstraint extends AbstractConstraint {
private Constraint<Range<Integer>> accountIdConstraint;
private Constraint<String> usernameConstraint;
private Constraint<String> passwordConstraint;
private Constraint<String> emailConstraint;
private AccountConstraint(Builder builder) {
this.accountIdConstraint = builder.accountIdConstraint;
this.usernameConstraint = builder.usernameConstraint;
this.passwordConstraint = builder.passwordConstraint;
this.emailConstraint = builder.emailConstraint;
}
@Override
public Constraint[] getConstraints() {
return new Constraint[] {
this.accountIdConstraint,
this.usernameConstraint,
this.passwordConstraint,
this.emailConstraint
};
}
public static class Builder extends ConstraintBuilder<AccountConstraint> {
private Constraint<Range<Integer>> accountIdConstraint;
private Constraint<String> usernameConstraint;
private Constraint<String> passwordConstraint;
private Constraint<String> emailConstraint;
public Builder() {
this.accountIdConstraint = null;
this.usernameConstraint = null;
this.passwordConstraint = null;
this.emailConstraint = null;
init();
}
public Builder accountId(final int val) {
this.accountIdConstraint = new Constraint<>(operation, truthed, new Range<>(val), "accountId");
return this;
}
public Builder accountId(final int min, final int max) {
this.accountIdConstraint = new Constraint<>(operation, truthed, new Range<>(min, max), "accountId");
return this;
}
public Builder accountId(final Range<Integer> accountId) {
this.accountIdConstraint = new Constraint<>(operation, truthed, accountId, "accountId");
return this;
}
public Builder username(final String username) {
this.usernameConstraint = new Constraint<>(operation, truthed, username, "username");
return this;
}
public Builder email(final String email) {
this.emailConstraint = new Constraint<>(operation, truthed, email, "email");
return this;
}
@Override
public AccountConstraint build() {
return new AccountConstraint(this);
}
}
}
ConstraintBuilder.java
public abstract class ConstraintBuilder<T> {
protected boolean truthed;
protected Operation operation;
protected void init() {
truthed = true;
operation = Operation.IS;
}
public ConstraintBuilder not() {
truthed = false;
return this;
}
public ConstraintBuilder like() {
operation = Operation.LIKE;
return this;
}
public abstract T build();
}
I want to be able to call new AccountConstraint.Builder().not().username("test"); but this is not possible as I lose the 'reference to the builder' at new AccountConstraint.Builder().not()., ie. I cannot select username("test") anymore.
In what ways could I fix this? I do want that the AccountBuilder.Builder extends ConstraintBuilder<AccountConstraint.Builder> such that I do not have to duplicate the commonly shared methods then.
Regards.
EDIT: I managed to get it working:
See the answer below for the changes.
I hope I haven't broken any Java fundamentals with this solution, I hope it is more of a solution than a dirty hack. I would be pleased if someone could review this edit.
I think this should work:
Builder builder = (Builder) new AccountConstraint.Builder().not();
builder = builder.username("test");
Your issue is that:
new AccountConstraint.Builder().not()
returns a ConstrainBuilder<T>, which doesn't necessarily have access to username(final String). So, you cast it to a Builder builder, and then call username(final String) on builder.
EDIT: You can turn this into one line:
((Builder) (new AccountConstraint.Builder().not())).username("test");
EDIT 2:
You could override not() in Builder: make it call super.not() and cast the return to a Builder. As in:
public Builder not()
{
return (Builder) super.not();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With