diff --git a/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java b/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java
index 0d3a9ec44..ee372794b 100644
--- a/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java
+++ b/src/main/java/org/mybatis/dynamic/sql/SqlColumn.java
@@ -25,6 +25,74 @@
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
import org.mybatis.dynamic.sql.util.StringUtilities;
+/**
+ * This class represents the definition of a column in a table.
+ *
+ *
The class contains many attributes that are helpful for use in MyBatis and Spring runtime
+ * environments, but the only required attributes are the name of the column and a reference to
+ * the {@link SqlTable} the column is a part of.
+ *
+ *
The class can be extended if you wish to associate additional attributes with a column for your
+ * own purposes. Extending the class is a bit more challenging than you might expect because you will need to
+ * handle the covariant types for many methods in {@code SqlColumn}. Additionally, many methods in {@code SqlColumn}
+ * create new instances of the class in keeping with the library's primary strategy of immutability. You will also
+ * need to ensure that these methods create instances of your extended class, rather than the base {@code SqlColumn}
+ * class. We have worked to keep this process as simple as possible.
+ *
+ *
Extending the class involves the following activities:
+ *
+ * - Create a class that extends {@link SqlColumn}
+ * - In your extended class, create a static builder class that extends {@link SqlColumn.AbstractBuilder}
+ * - Add your desired attributes to the class and the builder
+ * - In your extended class, override the {@link SqlColumn#copyBuilder()} method and return a new instance of
+ * your builder with all attributes set. You should call the
+ * {@link SqlColumn#populateBaseBuilder(AbstractBuilder)} method
+ * to set the attributes from {@code SqlColumn}, then populate your extended attributes.
+ *
+ * - You MUST override the following methods. These methods are used with regular operations in the library.
+ * If you do not override these methods, it is likely that your extended attributes will be lost during
+ * regular usage. For example, if you do not override the {@code as} method and a user calls the method to
+ * apply an alias, then the base {@code SqlColumn} class would create a new instance of {@code SqlColumn}, NOT
+ * your extended class.
+ *
+ * - {@link SqlColumn#as(String)}
+ * - {@link SqlColumn#asCamelCase()}
+ * - {@link SqlColumn#descending()}
+ * - {@link SqlColumn#qualifiedWith(String)}
+ *
+ *
+ * - You SHOULD override the following methods. These methods can be used to add additional attributes to a
+ * column by creating a new instance with a specified attribute set. These methods are used during the
+ * construction of columns. If you do not override these methods, and a user calls them, then a new
+ * {@code SqlColumn} will be created that does not contain your extended attributes.
+ *
+ * - {@link SqlColumn#withJavaProperty(String)}
+ * - {@link SqlColumn#withRenderingStrategy(RenderingStrategy)}
+ * - {@link SqlColumn#withTypeHandler(String)}
+ * - {@link SqlColumn#withJavaType(Class)}
+ * - {@link SqlColumn#withParameterTypeConverter(ParameterTypeConverter)}
+ *
+ *
+ *
+ *
+ * For all overridden methods except {@code copyBuilder()}, the process is to call the superclass
+ * method and cast the result properly. We provide a {@link SqlColumn#cast(SqlColumn)} method to aid with this
+ * process. For example, overriding the {@code descending} method could look like this:
+ *
+ *
+ *
+ * {@code
+ * @Override
+ * public MyExtendedColumn descending() {
+ * return cast(super.descending());
+ * }
+ * }
+ *
+ *
+ * The test code for this library contains an example of a proper extension of this class.
+ *
+ * @param the Java type associated with the column
+ */
public class SqlColumn implements BindableColumn, SortSpecification {
protected final String name;
@@ -39,7 +107,7 @@ public class SqlColumn implements BindableColumn, SortSpecification {
protected final @Nullable Class javaType;
protected final @Nullable String javaProperty;
- private SqlColumn(Builder builder) {
+ protected SqlColumn(AbstractBuilder builder) {
name = Objects.requireNonNull(builder.name);
table = Objects.requireNonNull(builder.table);
jdbcType = builder.jdbcType;
@@ -90,16 +158,27 @@ public Optional javaProperty() {
return value == null ? null : parameterTypeConverter.convert(value);
}
+ /**
+ * Create a new column instance that will render as descending when used in an order by phrase.
+ *
+ * @return a new column instance that will render as descending when used in an order by phrase
+ */
@Override
- public SortSpecification descending() {
- Builder b = copy();
- return b.withDescendingPhrase(" DESC").build(); //$NON-NLS-1$
+ public SqlColumn descending() {
+ return cast(copyBuilder().withDescendingPhrase(" DESC").build()); //$NON-NLS-1$
}
+ /**
+ * Create a new column instance with the specified alias that will render as "as alias" in a column list.
+ *
+ * @param alias
+ * the column alias to set
+ *
+ * @return a new column instance with the specified alias
+ */
@Override
public SqlColumn as(String alias) {
- Builder b = copy();
- return b.withAlias(alias).build();
+ return cast(copyBuilder().withAlias(alias).build());
}
/**
@@ -110,25 +189,24 @@ public SqlColumn as(String alias) {
* @return a new column that will be rendered with the specified table qualifier
*/
public SqlColumn qualifiedWith(String tableQualifier) {
- Builder b = copy();
- b.withTableQualifier(tableQualifier);
- return b.build();
+ return cast(copyBuilder().withTableQualifier(tableQualifier).build());
}
/**
- * Set an alias with a camel cased string based on the column name. This can be useful for queries using
+ * Set an alias with a camel-cased string based on the column name. This can be useful for queries using
* the {@link org.mybatis.dynamic.sql.util.mybatis3.CommonSelectMapper} where the columns are placed into
* a map based on the column name returned from the database.
*
- * A camel case string is mixed case, and most databases do not support unquoted mixed case strings
+ *
A camel case string is a mixed case string, and most databases do not support unquoted mixed case strings
* as identifiers. Therefore, the generated alias will be surrounded by double quotes thereby making it a
* quoted identifier. Most databases will respect quoted mixed case identifiers.
*
* @return a new column aliased with a camel case version of the column name
*/
public SqlColumn asCamelCase() {
- Builder b = copy();
- return b.withAlias("\"" + StringUtilities.toCamelCase(name) + "\"").build(); //$NON-NLS-1$ //$NON-NLS-2$
+ return cast(copyBuilder()
+ .withAlias("\"" + StringUtilities.toCamelCase(name) + "\"") //$NON-NLS-1$ //$NON-NLS-2$
+ .build());
}
@Override
@@ -150,43 +228,118 @@ public Optional renderingStrategy() {
return Optional.ofNullable(renderingStrategy);
}
+ /**
+ * Create a new column instance with the specified type handler.
+ *
+ * This method uses a different type (S). This allows it to be chained with the other
+ * with* methods. Using new types forces the compiler to delay type inference until the end of a call chain.
+ * Without this different type (for example, if we used T), the compiler would erase the type after the call
+ * and method chaining would not work. This is a workaround for Java's lack of reification.
+ *
+ * @param typeHandler the type handler to set
+ * @return a new column instance with the specified type handler
+ * @param the type of the new column (will be the same as T)
+ */
public SqlColumn withTypeHandler(String typeHandler) {
- Builder b = copy();
- return b.withTypeHandler(typeHandler).build();
+ return cast(copyBuilder().withTypeHandler(typeHandler).build());
}
+ /**
+ * Create a new column instance with the specified rendering strategy.
+ *
+ *
This method uses a different type (S). This allows it to be chained with the other
+ * with* methods. Using new types forces the compiler to delay type inference until the end of a call chain.
+ * Without this different type (for example, if we used T), the compiler would erase the type after the call
+ * and method chaining would not work. This is a workaround for Java's lack of reification.
+ *
+ * @param renderingStrategy the rendering strategy to set
+ * @return a new column instance with the specified type handler
+ * @param the type of the new column (will be the same as T)
+ */
public SqlColumn withRenderingStrategy(RenderingStrategy renderingStrategy) {
- Builder b = copy();
- return b.withRenderingStrategy(renderingStrategy).build();
+ return cast(copyBuilder().withRenderingStrategy(renderingStrategy).build());
}
+ /**
+ * Create a new column instance with the specified parameter type converter.
+ *
+ *
Parameter type converters are useful with Spring JDBC. Typically, they are not needed for MyBatis.
+ *
+ *
This method uses a different type (S). This allows it to be chained with the other
+ * with* methods. Using new types forces the compiler to delay type inference until the end of a call chain.
+ * Without this different type (for example, if we used T), the compiler would erase the type after the call
+ * and method chaining would not work. This is a workaround for Java's lack of reification.
+ *
+ * @param parameterTypeConverter the parameter type converter to set
+ * @return a new column instance with the specified type handler
+ * @param the type of the new column (will be the same as T)
+ */
+ @SuppressWarnings("unchecked")
public SqlColumn withParameterTypeConverter(ParameterTypeConverter parameterTypeConverter) {
- Builder b = copy();
- return b.withParameterTypeConverter(parameterTypeConverter).build();
+ return cast(copyBuilder().withParameterTypeConverter((ParameterTypeConverter) parameterTypeConverter)
+ .build());
}
+ /**
+ * Create a new column instance with the specified Java type.
+ *
+ * Specifying a Java type will force rendering of the Java type for MyBatis parameters. This can be useful
+ * with some MyBatis type handlers.
+ *
+ *
This method uses a different type (S). This allows it to be chained with the other
+ * with* methods. Using new types forces the compiler to delay type inference until the end of a call chain.
+ * Without this different type (for example, if we used T), the compiler would erase the type after the call
+ * and method chaining would not work. This is a workaround for Java's lack of reification.
+ *
+ * @param javaType the Java type to set
+ * @return a new column instance with the specified type handler
+ * @param the type of the new column (will be the same as T)
+ */
+ @SuppressWarnings("unchecked")
public SqlColumn withJavaType(Class javaType) {
- Builder b = copy();
- return b.withJavaType(javaType).build();
+ return cast(copyBuilder().withJavaType((Class) javaType).build());
}
+ /**
+ * Create a new column instance with the specified Java property.
+ *
+ * Specifying a Java property in the column will allow usage of the column as a "mapped column" in record-based
+ * insert statements.
+ *
+ *
This method uses a different type (S). This allows it to be chained with the other
+ * with* methods. Using new types forces the compiler to delay type inference until the end of a call chain.
+ * Without this different type (for example, if we used T), the compiler would erase the type after the call
+ * and method chaining would not work. This is a workaround for Java's lack of reification.
+ *
+ * @param javaProperty the Java property to set
+ * @return a new column instance with the specified type handler
+ * @param the type of the new column (will be the same as T)
+ */
public SqlColumn withJavaProperty(String javaProperty) {
- Builder b = copy();
- return b.withJavaProperty(javaProperty).build();
+ return cast(copyBuilder().withJavaProperty(javaProperty).build());
+ }
+
+ protected AbstractBuilder copyBuilder() {
+ return populateBaseBuilder(new Builder<>());
+ }
+
+ @SuppressWarnings("unchecked")
+ protected > S cast(SqlColumn> column) {
+ return (S) column;
}
/**
- * This method helps us tell a bit of fiction to the Java compiler. Java, for better or worse,
- * does not carry generic type information through chained methods. We want to enable method
- * chaining in the "with" methods. With this bit of fiction, we force the compiler to delay type
- * inference to the last method in the chain.
+ * This method will add all current attributes to the specified builder. It is useful when creating
+ * new class instances that only change one attribute - we set all current attributes, then
+ * change the one attribute. This utility can be used with the with* methods and other methods that
+ * create new instances.
*
- * @param the type. Will be the same as T for this usage.
- * @return a new SqlColumn of type S (S is the same as T)
+ * @param the concrete builder type
+ * @return the populated builder
*/
@SuppressWarnings("unchecked")
- private Builder copy() {
- return new Builder()
+ protected > B populateBaseBuilder(B builder) {
+ return (B) builder
.withName(this.name)
.withTable(this.table)
.withJdbcType(this.jdbcType)
@@ -194,9 +347,9 @@ private Builder copy() {
.withAlias(this.alias)
.withTypeHandler(this.typeHandler)
.withRenderingStrategy(this.renderingStrategy)
- .withParameterTypeConverter((ParameterTypeConverter) this.parameterTypeConverter)
+ .withParameterTypeConverter(this.parameterTypeConverter)
.withTableQualifier(this.tableQualifier)
- .withJavaType((Class) this.javaType)
+ .withJavaType(this.javaType)
.withJavaProperty(this.javaProperty);
}
@@ -213,7 +366,7 @@ public static SqlColumn of(String name, SqlTable table, JDBCType jdbcType
.build();
}
- public static class Builder {
+ public static abstract class AbstractBuilder, B extends AbstractBuilder> {
protected @Nullable String name;
protected @Nullable SqlTable table;
protected @Nullable JDBCType jdbcType;
@@ -226,63 +379,75 @@ public static class Builder {
protected @Nullable Class javaType;
protected @Nullable String javaProperty;
- public Builder withName(String name) {
+ public B withName(String name) {
this.name = name;
- return this;
+ return getThis();
}
- public Builder withTable(SqlTable table) {
+ public B withTable(SqlTable table) {
this.table = table;
- return this;
+ return getThis();
}
- public Builder withJdbcType(@Nullable JDBCType jdbcType) {
+ public B withJdbcType(@Nullable JDBCType jdbcType) {
this.jdbcType = jdbcType;
- return this;
+ return getThis();
}
- public Builder withDescendingPhrase(String descendingPhrase) {
+ public B withDescendingPhrase(String descendingPhrase) {
this.descendingPhrase = descendingPhrase;
- return this;
+ return getThis();
}
- public Builder withAlias(@Nullable String alias) {
+ public B withAlias(@Nullable String alias) {
this.alias = alias;
- return this;
+ return getThis();
}
- public Builder withTypeHandler(@Nullable String typeHandler) {
+ public B withTypeHandler(@Nullable String typeHandler) {
this.typeHandler = typeHandler;
- return this;
+ return getThis();
}
- public Builder withRenderingStrategy(@Nullable RenderingStrategy renderingStrategy) {
+ public B withRenderingStrategy(@Nullable RenderingStrategy renderingStrategy) {
this.renderingStrategy = renderingStrategy;
- return this;
+ return getThis();
}
- public Builder withParameterTypeConverter(ParameterTypeConverter parameterTypeConverter) {
+ public B withParameterTypeConverter(ParameterTypeConverter parameterTypeConverter) {
this.parameterTypeConverter = parameterTypeConverter;
- return this;
+ return getThis();
}
- private Builder withTableQualifier(@Nullable String tableQualifier) {
+ public B withTableQualifier(@Nullable String tableQualifier) {
this.tableQualifier = tableQualifier;
- return this;
+ return getThis();
}
- public Builder withJavaType(@Nullable Class javaType) {
+ public B withJavaType(@Nullable Class javaType) {
this.javaType = javaType;
- return this;
+ return getThis();
}
- public Builder withJavaProperty(@Nullable String javaProperty) {
+ public B withJavaProperty(@Nullable String javaProperty) {
this.javaProperty = javaProperty;
- return this;
+ return getThis();
}
+ protected abstract B getThis();
+
+ public abstract C build();
+ }
+
+ public static class Builder extends AbstractBuilder, Builder> {
+ @Override
public SqlColumn build() {
return new SqlColumn<>(this);
}
+
+ @Override
+ protected Builder getThis() {
+ return this;
+ }
}
}
diff --git a/src/test/java/examples/simple/ExtendedColumnTest.java b/src/test/java/examples/simple/ExtendedColumnTest.java
new file mode 100644
index 000000000..af89355ed
--- /dev/null
+++ b/src/test/java/examples/simple/ExtendedColumnTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2016-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.simple;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+import org.mybatis.dynamic.sql.ParameterTypeConverter;
+import org.mybatis.dynamic.sql.SqlTable;
+import org.mybatis.dynamic.sql.render.RenderingStrategies;
+
+class ExtendedColumnTest {
+
+ private final SqlTable table = SqlTable.of("foo");
+ private final PrimaryKeyColumn bar = new PrimaryKeyColumn.Builder()
+ .withName("first_name")
+ .withTable(table)
+ .isPrimaryKeyColumn(true)
+ .build();
+ private final ParameterTypeConverter ptc = Object::toString;
+
+ @Test
+ void testPropagatedDescending() {
+ var baz = bar.descending();
+
+ assertThat(baz.isPrimaryKeyColumn()).isTrue();
+ }
+
+ @Test
+ void testPropagatedAlias() {
+ var baz = bar.as("fred");
+
+ assertThat(baz.alias()).hasValue("fred");
+ assertThat(baz.isPrimaryKeyColumn()).isTrue();
+ }
+
+ @Test
+ void testPropagatedQualifiedWith() {
+ var baz = bar.qualifiedWith("fred");
+
+ assertThat(baz.isPrimaryKeyColumn()).isTrue();
+ }
+
+ @Test
+ void testPropagatedAsCamelCase() {
+ var baz = bar.asCamelCase();
+
+ assertThat(baz.isPrimaryKeyColumn()).isTrue();
+ }
+
+ @Test
+ void testPropagatedWithTypeHandler() {
+ var baz = bar.withTypeHandler("barney");
+
+ assertThat(baz.typeHandler()).hasValue("barney");
+ assertThat(baz.isPrimaryKeyColumn()).isTrue();
+ }
+
+ @Test
+ void testPropagatedRenderingStrategy() {
+ var baz = bar.withRenderingStrategy(RenderingStrategies.MYBATIS3);
+
+ assertThat(baz.renderingStrategy()).hasValue(RenderingStrategies.MYBATIS3);
+ assertThat(baz.isPrimaryKeyColumn()).isTrue();
+ }
+
+ @Test
+ void testPropagatedParameterTypeConverter() {
+ var baz = bar.withParameterTypeConverter(ptc);
+
+ assertThat(baz.convertParameterType(11)).isEqualTo("11");
+ assertThat(baz.isPrimaryKeyColumn()).isTrue();
+ }
+
+ @Test
+ void testPropagatedJavaType() {
+ var baz = bar.withJavaType(Integer.class);
+
+ assertThat(baz.javaType()).hasValue(Integer.class);
+ assertThat(baz.isPrimaryKeyColumn()).isTrue();
+ }
+
+ @Test
+ void testPropagatedJavaProperty() {
+ var baz = bar.withJavaProperty("id");
+
+ assertThat(baz.javaProperty()).hasValue("id");
+ assertThat(baz.isPrimaryKeyColumn()).isTrue();
+ }
+
+ @Test
+ void testAll() {
+ PrimaryKeyColumn baz = bar.descending()
+ .as("fred")
+ .qualifiedWith("fred")
+ .asCamelCase()
+ .withTypeHandler("barney")
+ .withRenderingStrategy(RenderingStrategies.MYBATIS3)
+ .withParameterTypeConverter(ptc)
+ .withJavaType(Integer.class)
+ .withJavaProperty("id");
+
+ assertThat(baz.alias()).hasValue("\"firstName\"");
+ assertThat(baz.typeHandler()).hasValue("barney");
+ assertThat(baz.renderingStrategy()).hasValue(RenderingStrategies.MYBATIS3);
+ assertThat(baz.convertParameterType(11)).isEqualTo("11");
+ assertThat(baz.javaType()).hasValue(Integer.class);
+ assertThat(baz.javaProperty()).hasValue("id");
+ assertThat(baz.isPrimaryKeyColumn()).isTrue();
+ }
+}
diff --git a/src/test/java/examples/simple/PersonDynamicSqlSupport.java b/src/test/java/examples/simple/PersonDynamicSqlSupport.java
index ba31eea5d..62d3c0840 100644
--- a/src/test/java/examples/simple/PersonDynamicSqlSupport.java
+++ b/src/test/java/examples/simple/PersonDynamicSqlSupport.java
@@ -23,7 +23,7 @@
public final class PersonDynamicSqlSupport {
public static final Person person = new Person();
- public static final SqlColumn id = person.id;
+ public static final PrimaryKeyColumn id = person.id;
public static final SqlColumn firstName = person.firstName;
public static final SqlColumn lastName = person.lastName;
public static final SqlColumn birthDate = person.birthDate;
@@ -32,7 +32,13 @@ public final class PersonDynamicSqlSupport {
public static final SqlColumn addressId = person.addressId;
public static final class Person extends SqlTable {
- public final SqlColumn id = column("id", JDBCType.INTEGER).withJavaProperty("id");
+ public final PrimaryKeyColumn id = new PrimaryKeyColumn.Builder()
+ .withTable(this)
+ .withName("id")
+ .withJdbcType(JDBCType.INTEGER)
+ .withJavaProperty("id")
+ .isPrimaryKeyColumn(true)
+ .build();
public final SqlColumn firstName = column("first_name", JDBCType.VARCHAR)
.withJavaProperty("firstName");
public final SqlColumn lastName =
diff --git a/src/test/java/examples/simple/PrimaryKeyColumn.java b/src/test/java/examples/simple/PrimaryKeyColumn.java
new file mode 100644
index 000000000..30d51f72a
--- /dev/null
+++ b/src/test/java/examples/simple/PrimaryKeyColumn.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2016-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package examples.simple;
+
+import org.mybatis.dynamic.sql.ParameterTypeConverter;
+import org.mybatis.dynamic.sql.SqlColumn;
+import org.mybatis.dynamic.sql.render.RenderingStrategy;
+
+/**
+ * This class is an example of a properly extended {@link SqlColumn}.
+ *
+ * @param the Java type associated with this column
+ */
+public class PrimaryKeyColumn extends SqlColumn {
+ private final boolean isPrimaryKeyColumn;
+
+ private PrimaryKeyColumn(Builder builder) {
+ super(builder);
+ isPrimaryKeyColumn = builder.isPrimaryKeyColumn;
+ }
+
+ public boolean isPrimaryKeyColumn() {
+ return isPrimaryKeyColumn;
+ }
+
+ @Override
+ public PrimaryKeyColumn descending() {
+ return cast(super.descending());
+ }
+
+ @Override
+ public PrimaryKeyColumn as(String alias) {
+ return cast(super.as(alias));
+ }
+
+ @Override
+ public PrimaryKeyColumn qualifiedWith(String tableQualifier) {
+ return cast(super.qualifiedWith(tableQualifier));
+ }
+
+ @Override
+ public PrimaryKeyColumn asCamelCase() {
+ return cast(super.asCamelCase());
+ }
+
+ @Override
+ public PrimaryKeyColumn withTypeHandler(String typeHandler) {
+ return cast(super.withTypeHandler(typeHandler));
+ }
+
+ @Override
+ public PrimaryKeyColumn withRenderingStrategy(RenderingStrategy renderingStrategy) {
+ return cast(super.withRenderingStrategy(renderingStrategy));
+ }
+
+ @Override
+ public PrimaryKeyColumn withParameterTypeConverter(ParameterTypeConverter parameterTypeConverter) {
+ return cast(super.withParameterTypeConverter(parameterTypeConverter));
+ }
+
+ @Override
+ public PrimaryKeyColumn withJavaType(Class javaType) {
+ return cast(super.withJavaType(javaType));
+ }
+
+ @Override
+ public PrimaryKeyColumn withJavaProperty(String javaProperty) {
+ return cast(super.withJavaProperty(javaProperty));
+ }
+
+ @Override
+ protected Builder copyBuilder() {
+ return populateBaseBuilder(new Builder<>()).isPrimaryKeyColumn(isPrimaryKeyColumn);
+ }
+
+ public static class Builder extends AbstractBuilder, Builder> {
+ private boolean isPrimaryKeyColumn;
+
+ public Builder isPrimaryKeyColumn(boolean isPrimaryKeyColumn) {
+ this.isPrimaryKeyColumn = isPrimaryKeyColumn;
+ return this;
+ }
+
+ @Override
+ public PrimaryKeyColumn build() {
+ return new PrimaryKeyColumn<>(this);
+ }
+
+ @Override
+ protected Builder getThis() {
+ return this;
+ }
+ }
+}