Skip to main content
Bumped by Community user
added 1 character in body
Source Link
  • The interfaces are fullfully functional and type-safe.
  • For every relation in a class (e.g., lets assume each User gets an additional Set<Post> posts of written posts), one additional generic parameter has to be introduced.
  • As of now, UserImpl and GroupImpl are tightly coupled. I have not yet found a possibility to modify the generic parameters in such a way that I could e.g. inject some UserBuilderNested in GroupImplBuilder.
  • Furhtermore, adding a new User-implementation requires the correct, generic wiring, as shown in the example-implementation implementation.
  • The interfaces are full functional and type-safe.
  • For every relation in a class (e.g., lets assume each User gets an additional Set<Post> posts of written posts), one additional generic parameter has to be introduced.
  • As of now, UserImpl and GroupImpl are tightly coupled. I have not yet found a possibility to modify the generic parameters in such a way that I could e.g. inject some UserBuilderNested in GroupImplBuilder.
  • Furhtermore, adding a new User-implementation requires the correct, generic wiring, as shown in the example-implementation.
  • The interfaces are fully functional and type-safe.
  • For every relation in a class (e.g., lets assume each User gets an additional Set<Post> posts of written posts), one additional generic parameter has to be introduced.
  • As of now, UserImpl and GroupImpl are tightly coupled. I have not yet found a possibility to modify the generic parameters in such a way that I could e.g. inject some UserBuilderNested in GroupImplBuilder.
  • Furhtermore, adding a new User-implementation requires the correct generic wiring, as shown in the example implementation.
deleted 2 characters in body
Source Link

Problem statement:

With the User-Group-example, the separation is not as clear. When starting construction a User-objects, a build()-method must be present. Starting a (recursive) Group-construction, the builder must not provide build(), but and() (or some other callback-method) instead. Here is an example usage:

To avoid WET-programming, I created two interfaces UserBuilderCore and GroupBuilderCore, containing only the with...(...) methods for the respective builder. UserBuilder and UserBuilderNested implement UserBuilderCore, and GroupBuilder; GroupBuilder and GroupBuilderNested implement GroupBuilderCore. The code for User and its builders is shown at the end of the question, the code for Group and its builders is analogue. The whole code can be found on bitbucket.

User.java:

// User.java
package com.turing.builder;

import java.util.Set;

public interface User {
  String getName();
  String getEmail();
  Set<Group> getGroups();
  void addGroup(Group group);
}

// UserBuilderCore.java
package com.turing.builder;

public interface UserBuilderCore< // @formatter:off
        S extends UserBuilderCore<S, C>,
        C extends GroupBuilderNested<C, ?, S>> { // @formatter:on
  S withName(String name);
  S withEmail(String email);
  S withGroup(Group group);
  C withGroup();
}
 
// UserBuilder.java

UserBuilder.java:

package com.turing.builder;

public interface UserBuilder< // @formatter:off
        S extends UserBuilder<S, C>,
        C extends GroupBuilderNested<C, ?, S>> // @formatter:on
    extends UserBuilderCore<S, C> {
  User build();
}

// UserBuilderNested.java

UserBuilderNested.java:

package com.turing.builder;

public interface UserBuilderNested< // @formatter:off
        S extends UserBuilderNested<S, C, P>,
        C extends GroupBuilderNested<C, ?, S>,
        P extends GroupBuilderCore<P, ?>> // @formatter:on
    extends UserBuilderCore<S, C> {
  P and();
}

// UserImpl.java

UserImpl.java:

package com.turing.builder.impl;

import com.turing.builder.Group;
import com.turing.builder.User;
import com.turing.builder.UserBuilder;
import com.turing.builder.UserBuilderCore;
import com.turing.builder.UserBuilderNested;
import com.turing.builder.impl.GroupImpl.GroupImplBuilderCore;
import com.turing.builder.impl.GroupImpl.GroupImplBuilderNested;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

public class UserImpl implements User {
  private String name;
  private String email;
  private Set<Group> groups = new HashSet<>();

  @Override
  public String getName() {
    return name;
  }

  private void setName(String name) {
    this.name = name;
  }

  @Override
  public String getEmail() {
    return email;
  }

  private void setEmail(String email) {
    this.email = email;
  }

  @Override
  public Set<Group> getGroups() {
    return groups;
  }

  private void setGroups(Set<Group> groups) {
    this.groups = groups;
  }

  @Override
  public void addGroup(Group group) {
    this.groups.add(group);
  }

  @Override
  public String toString() {
    return String.format("User %s=%s",
        getName(),
        getGroups().stream()
            .map(Group::getName)
            .collect(Collectors.toList()));
  }

  protected abstract static class UserImplBuilderCore< // @formatter:off
          S extends UserImplBuilderCore<S>>
      implements UserBuilderCore<
          /* S = */ S,
          /* C = */ GroupImplBuilderNested<S>> { // @formatter:on
    private UserImpl managed = new UserImpl();

    @Override
    @SuppressWarnings("unchecked")
    public S withName(String name) {
      managed.setName(name);
      return ((S) this);
    }

    @Override
    @SuppressWarnings("unchecked")
    public S withEmail(String email) {
      managed.setEmail(email);
      return ((S) this);
    }

    @Override
    @SuppressWarnings("unchecked")
    public S withGroup(Group group) {
      managed.addGroup(group);
      return ((S) this);
    }

    @Override
    public GroupImplBuilderNested<S> withGroup() {
      return new GroupImplBuilderNested<>(this::withGroup);
    }

    protected User construct() {
      User constructed = this.managed;
      this.managed = new UserImpl();
      return constructed;
    }
  }

  public static class UserImplBuilder extends UserImplBuilderCore<UserImplBuilder>
      implements UserBuilder< // @formatter:off
          /* S = */ UserImplBuilder,
          /* C = */ GroupImplBuilderNested<UserImplBuilder>> { // @formatter:on
    public User build() {
      return construct();
    }
  }

  public static class UserImplBuilderNested<T extends GroupImplBuilderCore<T>>
      extends UserImplBuilderCore<UserImplBuilderNested<T>>
      implements UserBuilderNested< // @formatter:off
          /* S = */ UserImplBuilderNested<T>,
          /* C = */ GroupImplBuilderNested<UserImplBuilderNested<T>>,
          /* P = */ T> { // @formatter:on
    private final Function<User, T> callback;

    public UserImplBuilderNested(Function<User, T> callback) {
      this.callback = callback;
    }

    public T and() {
      return callback.apply(construct());
    }
  }
}

Problem statement:

With the User-Group-example, the separation is not as clear. When starting construction a User-objects, a build()-method must be present. Starting a (recursive) Group-construction, the builder must not provide build(), but and() (or some other callback-method) instead. Here is an example usage

To avoid WET-programming, I created two interfaces UserBuilderCore and GroupBuilderCore, containing only the with...(...) methods for the respective builder. UserBuilder and UserBuilderNested implement UserBuilderCore, and GroupBuilder; GroupBuilderNested implement GroupBuilderCore. The code for User and its builders is shown at the end of the question, the code for Group and its builders is analogue. The whole code can be found on bitbucket.

// User.java
package com.turing.builder;

import java.util.Set;

public interface User {
  String getName();
  String getEmail();
  Set<Group> getGroups();
  void addGroup(Group group);
}

// UserBuilderCore.java
package com.turing.builder;

public interface UserBuilderCore< // @formatter:off
        S extends UserBuilderCore<S, C>,
        C extends GroupBuilderNested<C, ?, S>> { // @formatter:on
  S withName(String name);
  S withEmail(String email);
  S withGroup(Group group);
  C withGroup();
}
 
// UserBuilder.java
package com.turing.builder;

public interface UserBuilder< // @formatter:off
        S extends UserBuilder<S, C>,
        C extends GroupBuilderNested<C, ?, S>> // @formatter:on
    extends UserBuilderCore<S, C> {
  User build();
}

// UserBuilderNested.java
package com.turing.builder;

public interface UserBuilderNested< // @formatter:off
        S extends UserBuilderNested<S, C, P>,
        C extends GroupBuilderNested<C, ?, S>,
        P extends GroupBuilderCore<P, ?>> // @formatter:on
    extends UserBuilderCore<S, C> {
  P and();
}

// UserImpl.java
package com.turing.builder.impl;

import com.turing.builder.Group;
import com.turing.builder.User;
import com.turing.builder.UserBuilder;
import com.turing.builder.UserBuilderCore;
import com.turing.builder.UserBuilderNested;
import com.turing.builder.impl.GroupImpl.GroupImplBuilderCore;
import com.turing.builder.impl.GroupImpl.GroupImplBuilderNested;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

public class UserImpl implements User {
  private String name;
  private String email;
  private Set<Group> groups = new HashSet<>();

  @Override
  public String getName() {
    return name;
  }

  private void setName(String name) {
    this.name = name;
  }

  @Override
  public String getEmail() {
    return email;
  }

  private void setEmail(String email) {
    this.email = email;
  }

  @Override
  public Set<Group> getGroups() {
    return groups;
  }

  private void setGroups(Set<Group> groups) {
    this.groups = groups;
  }

  @Override
  public void addGroup(Group group) {
    this.groups.add(group);
  }

  @Override
  public String toString() {
    return String.format("User %s=%s",
        getName(),
        getGroups().stream()
            .map(Group::getName)
            .collect(Collectors.toList()));
  }

  protected abstract static class UserImplBuilderCore< // @formatter:off
          S extends UserImplBuilderCore<S>>
      implements UserBuilderCore<
          /* S = */ S,
          /* C = */ GroupImplBuilderNested<S>> { // @formatter:on
    private UserImpl managed = new UserImpl();

    @Override
    @SuppressWarnings("unchecked")
    public S withName(String name) {
      managed.setName(name);
      return ((S) this);
    }

    @Override
    @SuppressWarnings("unchecked")
    public S withEmail(String email) {
      managed.setEmail(email);
      return ((S) this);
    }

    @Override
    @SuppressWarnings("unchecked")
    public S withGroup(Group group) {
      managed.addGroup(group);
      return ((S) this);
    }

    @Override
    public GroupImplBuilderNested<S> withGroup() {
      return new GroupImplBuilderNested<>(this::withGroup);
    }

    protected User construct() {
      User constructed = this.managed;
      this.managed = new UserImpl();
      return constructed;
    }
  }

  public static class UserImplBuilder extends UserImplBuilderCore<UserImplBuilder>
      implements UserBuilder< // @formatter:off
          /* S = */ UserImplBuilder,
          /* C = */ GroupImplBuilderNested<UserImplBuilder>> { // @formatter:on
    public User build() {
      return construct();
    }
  }

  public static class UserImplBuilderNested<T extends GroupImplBuilderCore<T>>
      extends UserImplBuilderCore<UserImplBuilderNested<T>>
      implements UserBuilderNested< // @formatter:off
          /* S = */ UserImplBuilderNested<T>,
          /* C = */ GroupImplBuilderNested<UserImplBuilderNested<T>>,
          /* P = */ T> { // @formatter:on
    private final Function<User, T> callback;

    public UserImplBuilderNested(Function<User, T> callback) {
      this.callback = callback;
    }

    public T and() {
      return callback.apply(construct());
    }
  }
}

Problem statement

With the User-Group-example, the separation is not as clear. When starting construction a User-objects, a build()-method must be present. Starting a (recursive) Group-construction, the builder must not provide build(), but and() (or some other callback-method) instead. Here is an example usage:

To avoid WET-programming, I created two interfaces UserBuilderCore and GroupBuilderCore, containing only the with...(...) methods for the respective builder. UserBuilder and UserBuilderNested implement UserBuilderCore; GroupBuilder and GroupBuilderNested implement GroupBuilderCore. The code for User and its builders is shown at the end of the question, the code for Group and its builders is analogue. The whole code can be found on bitbucket.

User.java:

package com.turing.builder;

import java.util.Set;

public interface User {
  String getName();
  String getEmail();
  Set<Group> getGroups();
  void addGroup(Group group);
}

// UserBuilderCore.java
package com.turing.builder;

public interface UserBuilderCore< // @formatter:off
        S extends UserBuilderCore<S, C>,
        C extends GroupBuilderNested<C, ?, S>> { // @formatter:on
  S withName(String name);
  S withEmail(String email);
  S withGroup(Group group);
  C withGroup();
}

UserBuilder.java:

package com.turing.builder;

public interface UserBuilder< // @formatter:off
        S extends UserBuilder<S, C>,
        C extends GroupBuilderNested<C, ?, S>> // @formatter:on
    extends UserBuilderCore<S, C> {
  User build();
}

UserBuilderNested.java:

package com.turing.builder;

public interface UserBuilderNested< // @formatter:off
        S extends UserBuilderNested<S, C, P>,
        C extends GroupBuilderNested<C, ?, S>,
        P extends GroupBuilderCore<P, ?>> // @formatter:on
    extends UserBuilderCore<S, C> {
  P and();
}

UserImpl.java:

package com.turing.builder.impl;

import com.turing.builder.Group;
import com.turing.builder.User;
import com.turing.builder.UserBuilder;
import com.turing.builder.UserBuilderCore;
import com.turing.builder.UserBuilderNested;
import com.turing.builder.impl.GroupImpl.GroupImplBuilderCore;
import com.turing.builder.impl.GroupImpl.GroupImplBuilderNested;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

public class UserImpl implements User {
  private String name;
  private String email;
  private Set<Group> groups = new HashSet<>();

  @Override
  public String getName() {
    return name;
  }

  private void setName(String name) {
    this.name = name;
  }

  @Override
  public String getEmail() {
    return email;
  }

  private void setEmail(String email) {
    this.email = email;
  }

  @Override
  public Set<Group> getGroups() {
    return groups;
  }

  private void setGroups(Set<Group> groups) {
    this.groups = groups;
  }

  @Override
  public void addGroup(Group group) {
    this.groups.add(group);
  }

  @Override
  public String toString() {
    return String.format("User %s=%s",
        getName(),
        getGroups().stream()
            .map(Group::getName)
            .collect(Collectors.toList()));
  }

  protected abstract static class UserImplBuilderCore< // @formatter:off
          S extends UserImplBuilderCore<S>>
      implements UserBuilderCore<
          /* S = */ S,
          /* C = */ GroupImplBuilderNested<S>> { // @formatter:on
    private UserImpl managed = new UserImpl();

    @Override
    @SuppressWarnings("unchecked")
    public S withName(String name) {
      managed.setName(name);
      return ((S) this);
    }

    @Override
    @SuppressWarnings("unchecked")
    public S withEmail(String email) {
      managed.setEmail(email);
      return ((S) this);
    }

    @Override
    @SuppressWarnings("unchecked")
    public S withGroup(Group group) {
      managed.addGroup(group);
      return ((S) this);
    }

    @Override
    public GroupImplBuilderNested<S> withGroup() {
      return new GroupImplBuilderNested<>(this::withGroup);
    }

    protected User construct() {
      User constructed = this.managed;
      this.managed = new UserImpl();
      return constructed;
    }
  }

  public static class UserImplBuilder extends UserImplBuilderCore<UserImplBuilder>
      implements UserBuilder< // @formatter:off
          /* S = */ UserImplBuilder,
          /* C = */ GroupImplBuilderNested<UserImplBuilder>> { // @formatter:on
    public User build() {
      return construct();
    }
  }

  public static class UserImplBuilderNested<T extends GroupImplBuilderCore<T>>
      extends UserImplBuilderCore<UserImplBuilderNested<T>>
      implements UserBuilderNested< // @formatter:off
          /* S = */ UserImplBuilderNested<T>,
          /* C = */ GroupImplBuilderNested<UserImplBuilderNested<T>>,
          /* P = */ T> { // @formatter:on
    private final Function<User, T> callback;

    public UserImplBuilderNested(Function<User, T> callback) {
      this.callback = callback;
    }

    public T and() {
      return callback.apply(construct());
    }
  }
}
added 5201 characters in body
Source Link

To avoid WET-programming, I created two interfaces UserBuilderCore and GroupBuilderCore, containing only the with...(...) methods for the respective builder. UserBuilder and UserBuilderNested implement UserBuilderCore, and GroupBuilder; GroupBuilderNested implement GroupBuilderCore. The code for User and its builders is  shown at the end of the question, the code for Group and its builders is analogue. The whole code can be found on on bitbucketbitbucket.

Source code

// User.java
package com.turing.builder;

import java.util.Set;

public interface User {
  String getName();
  String getEmail();
  Set<Group> getGroups();
  void addGroup(Group group);
}

// UserBuilderCore.java
package com.turing.builder;

public interface UserBuilderCore< // @formatter:off
        S extends UserBuilderCore<S, C>,
        C extends GroupBuilderNested<C, ?, S>> { // @formatter:on
  S withName(String name);
  S withEmail(String email);
  S withGroup(Group group);
  C withGroup();
}

// UserBuilder.java
package com.turing.builder;

public interface UserBuilder< // @formatter:off
        S extends UserBuilder<S, C>,
        C extends GroupBuilderNested<C, ?, S>> // @formatter:on
    extends UserBuilderCore<S, C> {
  User build();
}

// UserBuilderNested.java
package com.turing.builder;

public interface UserBuilderNested< // @formatter:off
        S extends UserBuilderNested<S, C, P>,
        C extends GroupBuilderNested<C, ?, S>,
        P extends GroupBuilderCore<P, ?>> // @formatter:on
    extends UserBuilderCore<S, C> {
  P and();
}

// UserImpl.java
package com.turing.builder.impl;

import com.turing.builder.Group;
import com.turing.builder.User;
import com.turing.builder.UserBuilder;
import com.turing.builder.UserBuilderCore;
import com.turing.builder.UserBuilderNested;
import com.turing.builder.impl.GroupImpl.GroupImplBuilderCore;
import com.turing.builder.impl.GroupImpl.GroupImplBuilderNested;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

public class UserImpl implements User {
  private String name;
  private String email;
  private Set<Group> groups = new HashSet<>();

  @Override
  public String getName() {
    return name;
  }

  private void setName(String name) {
    this.name = name;
  }

  @Override
  public String getEmail() {
    return email;
  }

  private void setEmail(String email) {
    this.email = email;
  }

  @Override
  public Set<Group> getGroups() {
    return groups;
  }

  private void setGroups(Set<Group> groups) {
    this.groups = groups;
  }

  @Override
  public void addGroup(Group group) {
    this.groups.add(group);
  }

  @Override
  public String toString() {
    return String.format("User %s=%s",
        getName(),
        getGroups().stream()
            .map(Group::getName)
            .collect(Collectors.toList()));
  }

  protected abstract static class UserImplBuilderCore< // @formatter:off
          S extends UserImplBuilderCore<S>>
      implements UserBuilderCore<
          /* S = */ S,
          /* C = */ GroupImplBuilderNested<S>> { // @formatter:on
    private UserImpl managed = new UserImpl();

    @Override
    @SuppressWarnings("unchecked")
    public S withName(String name) {
      managed.setName(name);
      return ((S) this);
    }

    @Override
    @SuppressWarnings("unchecked")
    public S withEmail(String email) {
      managed.setEmail(email);
      return ((S) this);
    }

    @Override
    @SuppressWarnings("unchecked")
    public S withGroup(Group group) {
      managed.addGroup(group);
      return ((S) this);
    }

    @Override
    public GroupImplBuilderNested<S> withGroup() {
      return new GroupImplBuilderNested<>(this::withGroup);
    }

    protected User construct() {
      User constructed = this.managed;
      this.managed = new UserImpl();
      return constructed;
    }
  }

  public static class UserImplBuilder extends UserImplBuilderCore<UserImplBuilder>
      implements UserBuilder< // @formatter:off
          /* S = */ UserImplBuilder,
          /* C = */ GroupImplBuilderNested<UserImplBuilder>> { // @formatter:on
    public User build() {
      return construct();
    }
  }

  public static class UserImplBuilderNested<T extends GroupImplBuilderCore<T>>
      extends UserImplBuilderCore<UserImplBuilderNested<T>>
      implements UserBuilderNested< // @formatter:off
          /* S = */ UserImplBuilderNested<T>,
          /* C = */ GroupImplBuilderNested<UserImplBuilderNested<T>>,
          /* P = */ T> { // @formatter:on
    private final Function<User, T> callback;

    public UserImplBuilderNested(Function<User, T> callback) {
      this.callback = callback;
    }

    public T and() {
      return callback.apply(construct());
    }
  }
}

To avoid WET-programming, I created two interfaces UserBuilderCore and GroupBuilderCore, containing only the with...(...) methods for the respective builder. UserBuilder and UserBuilderNested implement UserBuilderCore, and GroupBuilder; GroupBuilderNested implement GroupBuilderCore. The code is  on bitbucket.

To avoid WET-programming, I created two interfaces UserBuilderCore and GroupBuilderCore, containing only the with...(...) methods for the respective builder. UserBuilder and UserBuilderNested implement UserBuilderCore, and GroupBuilder; GroupBuilderNested implement GroupBuilderCore. The code for User and its builders is shown at the end of the question, the code for Group and its builders is analogue. The whole code can be found on bitbucket.

Source code

// User.java
package com.turing.builder;

import java.util.Set;

public interface User {
  String getName();
  String getEmail();
  Set<Group> getGroups();
  void addGroup(Group group);
}

// UserBuilderCore.java
package com.turing.builder;

public interface UserBuilderCore< // @formatter:off
        S extends UserBuilderCore<S, C>,
        C extends GroupBuilderNested<C, ?, S>> { // @formatter:on
  S withName(String name);
  S withEmail(String email);
  S withGroup(Group group);
  C withGroup();
}

// UserBuilder.java
package com.turing.builder;

public interface UserBuilder< // @formatter:off
        S extends UserBuilder<S, C>,
        C extends GroupBuilderNested<C, ?, S>> // @formatter:on
    extends UserBuilderCore<S, C> {
  User build();
}

// UserBuilderNested.java
package com.turing.builder;

public interface UserBuilderNested< // @formatter:off
        S extends UserBuilderNested<S, C, P>,
        C extends GroupBuilderNested<C, ?, S>,
        P extends GroupBuilderCore<P, ?>> // @formatter:on
    extends UserBuilderCore<S, C> {
  P and();
}

// UserImpl.java
package com.turing.builder.impl;

import com.turing.builder.Group;
import com.turing.builder.User;
import com.turing.builder.UserBuilder;
import com.turing.builder.UserBuilderCore;
import com.turing.builder.UserBuilderNested;
import com.turing.builder.impl.GroupImpl.GroupImplBuilderCore;
import com.turing.builder.impl.GroupImpl.GroupImplBuilderNested;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

public class UserImpl implements User {
  private String name;
  private String email;
  private Set<Group> groups = new HashSet<>();

  @Override
  public String getName() {
    return name;
  }

  private void setName(String name) {
    this.name = name;
  }

  @Override
  public String getEmail() {
    return email;
  }

  private void setEmail(String email) {
    this.email = email;
  }

  @Override
  public Set<Group> getGroups() {
    return groups;
  }

  private void setGroups(Set<Group> groups) {
    this.groups = groups;
  }

  @Override
  public void addGroup(Group group) {
    this.groups.add(group);
  }

  @Override
  public String toString() {
    return String.format("User %s=%s",
        getName(),
        getGroups().stream()
            .map(Group::getName)
            .collect(Collectors.toList()));
  }

  protected abstract static class UserImplBuilderCore< // @formatter:off
          S extends UserImplBuilderCore<S>>
      implements UserBuilderCore<
          /* S = */ S,
          /* C = */ GroupImplBuilderNested<S>> { // @formatter:on
    private UserImpl managed = new UserImpl();

    @Override
    @SuppressWarnings("unchecked")
    public S withName(String name) {
      managed.setName(name);
      return ((S) this);
    }

    @Override
    @SuppressWarnings("unchecked")
    public S withEmail(String email) {
      managed.setEmail(email);
      return ((S) this);
    }

    @Override
    @SuppressWarnings("unchecked")
    public S withGroup(Group group) {
      managed.addGroup(group);
      return ((S) this);
    }

    @Override
    public GroupImplBuilderNested<S> withGroup() {
      return new GroupImplBuilderNested<>(this::withGroup);
    }

    protected User construct() {
      User constructed = this.managed;
      this.managed = new UserImpl();
      return constructed;
    }
  }

  public static class UserImplBuilder extends UserImplBuilderCore<UserImplBuilder>
      implements UserBuilder< // @formatter:off
          /* S = */ UserImplBuilder,
          /* C = */ GroupImplBuilderNested<UserImplBuilder>> { // @formatter:on
    public User build() {
      return construct();
    }
  }

  public static class UserImplBuilderNested<T extends GroupImplBuilderCore<T>>
      extends UserImplBuilderCore<UserImplBuilderNested<T>>
      implements UserBuilderNested< // @formatter:off
          /* S = */ UserImplBuilderNested<T>,
          /* C = */ GroupImplBuilderNested<UserImplBuilderNested<T>>,
          /* P = */ T> { // @formatter:on
    private final Function<User, T> callback;

    public UserImplBuilderNested(Function<User, T> callback) {
      this.callback = callback;
    }

    public T and() {
      return callback.apply(construct());
    }
  }
}
edited body
Source Link
Loading
deleted 9 characters in body
Source Link
Loading
deleted 9 characters in body
Source Link
Loading
Source Link
Loading