You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Generated builders expose public methods to set attributes; in cases where the Builder is sub-classed (in combination with some other flag), make those methods protected such that only the subclass builder can access them. This allow the subclass builder to normalize data, enforce various rules & expose a use-case / domain-specific / higher-level API - while still generating the same immutable object.
Example:
This immutable template:
@Value.Immutable
public abstract class AbstractPolicyStatement {
public abstract List<String> actions();
public abstract List<String> notActions();
public abstract List<String> resources();
public abstract String effect();
public static Builder builder() {
return new Builder();
}
@SuppressWarnings("ResultOfMethodCallIgnored")
public static class Builder extends ImmutablePolicyStatement.Builder {
public Builder anyAction() {
return resource("*");
}
public Builder anyResource() {
return resource("*");
}
// addResources( ... ) remains publicly available
public Builder resource( String resource ) {
return addResources(resource );
}
// effect( String ) remains publicly available
public Builder allow() {
return effect("Allow");
}
// effect( String ) remains publicly available
public Builder deny() {
return effect("Deny");
}
public Builder denyAll() {
anyAction();
anyResource();
return deny();
}
}
}
Used this way:
void example() {
// issues:
// type safety (partially fixed by using enums in some cases)
// inconventient: attributes set one by one;
// lower-level, not necessarily reflective of domain (as attributes can only be set one-by-one, can't model
// higher-level combinations/use-cases
var usingRawBuilder = ImmutablePolicyStatement.builder()
.effect("Deny")
.addResources("*")
.addActions("*")
.build();
// simpler, reflects domain, addresses type safety & contextual requirements
var usingFriendlyBuilder = ImmutablePolicyStatement.builder()
.denyAll()
.build();
// however... base builder methods still exposed
var usingFriendlyBuilder2 = ImmutablePolicyStatement.builder()
.denyAll()
.addActions("someAction")
.build();
}
...almost gets us there but exposes the raw builder methods to all consumers, which may not be desirable in all cases. It gets increasingly worse for more complex object, such as ones that have Multimap attributes, etc (required to match domain model / support JSON marshalling, but not a small/safe builder api)
Perhaps something like this on the subclass builder:
@Builder.AttributeVisibility(PROTECTED)
public static class Builder extends ImmutablePolicyStatement.Builder {
public Builder anyAction() {
return resource("*");
}
The text was updated successfully, but these errors were encountered:
Generated builders expose public methods to set attributes; in cases where the Builder is sub-classed (in combination with some other flag), make those methods protected such that only the subclass builder can access them. This allow the subclass builder to normalize data, enforce various rules & expose a use-case / domain-specific / higher-level API - while still generating the same immutable object.
Example:
This immutable template:
Used this way:
...almost gets us there but exposes the raw builder methods to all consumers, which may not be desirable in all cases. It gets increasingly worse for more complex object, such as ones that have Multimap attributes, etc (required to match domain model / support JSON marshalling, but not a small/safe builder api)
Perhaps something like this on the subclass builder:
The text was updated successfully, but these errors were encountered: