2929import com .clickhouse .client .api .internal .SettingsConverter ;
3030import com .clickhouse .client .api .internal .TableSchemaParser ;
3131import com .clickhouse .client .api .internal .ValidationUtils ;
32+ import com .clickhouse .client .api .metadata .ColumnToMethodMatchingStrategy ;
33+ import com .clickhouse .client .api .metadata .DefaultColumnToMethodMatchingStrategy ;
3234import com .clickhouse .client .api .metadata .TableSchema ;
3335import com .clickhouse .client .api .metrics .ClientMetrics ;
3436import com .clickhouse .client .api .metrics .OperationMetrics ;
@@ -146,8 +148,10 @@ public class Client implements AutoCloseable {
146148 private Map <String , TableSchema > tableSchemaCache = new ConcurrentHashMap <>();
147149 private Map <String , Boolean > tableSchemaHasDefaults = new ConcurrentHashMap <>();
148150
151+ private final ColumnToMethodMatchingStrategy columnToMethodMatchingStrategy ;
152+
149153 private Client (Set <String > endpoints , Map <String ,String > configuration , boolean useNewImplementation ,
150- ExecutorService sharedOperationExecutor ) {
154+ ExecutorService sharedOperationExecutor , ColumnToMethodMatchingStrategy columnToMethodMatchingStrategy ) {
151155 this .endpoints = endpoints ;
152156 this .configuration = configuration ;
153157 this .endpoints .forEach (endpoint -> {
@@ -170,6 +174,7 @@ private Client(Set<String> endpoints, Map<String,String> configuration, boolean
170174 this .oldClient = ClientV1AdaptorHelper .createClient (configuration );
171175 LOG .info ("Using old http client implementation" );
172176 }
177+ this .columnToMethodMatchingStrategy = columnToMethodMatchingStrategy ;
173178 }
174179
175180 /**
@@ -211,6 +216,7 @@ public static class Builder {
211216 private boolean useNewImplementation = true ;
212217
213218 private ExecutorService sharedOperationExecutor = null ;
219+ private ColumnToMethodMatchingStrategy columnToMethodMatchingStrategy ;
214220
215221 public Builder () {
216222 this .endpoints = new HashSet <>();
@@ -846,6 +852,18 @@ public Builder serverSetting(String name, Collection<String> values) {
846852 return this ;
847853 }
848854
855+ /**
856+ * Sets column to method matching strategy. It is used while registering POJO serializers and deserializers.
857+ * Default is {@link DefaultColumnToMethodMatchingStrategy}.
858+ *
859+ * @param strategy - matching strategy
860+ * @return same instance of the builder
861+ */
862+ public Builder columnToMethodMatchingStrategy (ColumnToMethodMatchingStrategy strategy ) {
863+ this .columnToMethodMatchingStrategy = strategy ;
864+ return this ;
865+ }
866+
849867 public Client build () {
850868 setDefaults ();
851869
@@ -891,7 +909,7 @@ public Client build() {
891909 throw new IllegalArgumentException ("Nor server timezone nor specific timezone is set" );
892910 }
893911
894- return new Client (this .endpoints , this .configuration , this .useNewImplementation , this .sharedOperationExecutor );
912+ return new Client (this .endpoints , this .configuration , this .useNewImplementation , this .sharedOperationExecutor , this . columnToMethodMatchingStrategy );
895913 }
896914
897915 private static final int DEFAULT_NETWORK_BUFFER_SIZE = 300_000 ;
@@ -963,6 +981,10 @@ private void setDefaults() {
963981 if (!configuration .containsKey ("client_allow_binary_reader_to_reuse_buffers" )) {
964982 allowBinaryReaderToReuseBuffers (false );
965983 }
984+
985+ if (columnToMethodMatchingStrategy == null ) {
986+ columnToMethodMatchingStrategy = DefaultColumnToMethodMatchingStrategy .INSTANCE ;
987+ }
966988 }
967989 }
968990
@@ -1018,19 +1040,17 @@ public synchronized void register(Class<?> clazz, TableSchema schema) {
10181040 }
10191041 tableSchemaCache .put (schemaKey , schema );
10201042
1043+ ColumnToMethodMatchingStrategy matchingStrategy = columnToMethodMatchingStrategy ;
1044+
10211045 //Create a new POJOSerializer with static .serialize(object, columns) methods
10221046 Map <String , Method > classGetters = new HashMap <>();
10231047 Map <String , Method > classSetters = new HashMap <>();
10241048 for (Method method : clazz .getMethods ()) {//Clean up the method names
1025- String methodName = method .getName ();
1026- if (methodName .startsWith ("get" ) || methodName .startsWith ("has" )) {
1027- methodName = methodName .substring (3 ).toLowerCase ();
1028- classGetters .put (methodName , method );
1029- } else if (methodName .startsWith ("is" )) {
1030- methodName = methodName .substring (2 ).toLowerCase ();
1049+ if (matchingStrategy .isGetter (method .getName ())) {
1050+ String methodName = matchingStrategy .normalizeMethodName (method .getName ());
10311051 classGetters .put (methodName , method );
1032- } else if (methodName . startsWith ( "set" )) {
1033- methodName = methodName . substring ( 3 ). toLowerCase ( );
1052+ } else if (matchingStrategy . isSetter ( method . getName () )) {
1053+ String methodName = matchingStrategy . normalizeMethodName ( method . getName () );
10341054 classSetters .put (methodName , method );
10351055 }
10361056 }
@@ -1040,7 +1060,7 @@ public synchronized void register(Class<?> clazz, TableSchema schema) {
10401060 boolean defaultsSupport = schema .hasDefaults ();
10411061 tableSchemaHasDefaults .put (schemaKey , defaultsSupport );
10421062 for (ClickHouseColumn column : schema .getColumns ()) {
1043- String propertyName = column .getColumnName (). toLowerCase (). replace ( "_" , "" ). replace ( "." , "" );
1063+ String propertyName = columnToMethodMatchingStrategy . normalizeColumnName ( column .getColumnName ());
10441064 Method getterMethod = classGetters .get (propertyName );
10451065 if (getterMethod != null ) {
10461066 schemaSerializers .put (column .getColumnName (), (obj , stream ) -> {
0 commit comments