Repository: apache/shardingsphere
Issue: recieve ClassCastException while testing ComplexKeysShardingAlgorithm

## Bug Report

**For English only**, other languages will not accept.

Before report a bug, make sure you have:

- Searched open and closed [GitHub issues](https://github.com/apache/incubator-shardingsphere-example/issues).
- Read documentation: [ShardingSphere Doc](https://shardingsphere.apache.org/document/current/en/overview).

Please pay attention on issues you submitted, because we maybe need more details. 
If no response **more than 7 days** and we cannot reproduce it on current information, we will **close it**.

Please answer these questions before submitting your issue. Thanks!

### Which version of ShardingSphere did you use?
- sharding-jdbc-core:4.0.0-RC1

### Which project did you use? Sharding-JDBC or Sharding-Proxy?
- Sharding-JDBC

### Expected behavior
- return the right type of RouteValue

### Actual behavior
- java.lang.ClassCastException

### Reason analyze (If you can)

- just BetweenRouteValue cast to ListRouteValue error.

- i think it`s no need to cast to ListRouteValue, just let us to deal with it

- at org.apache.shardingsphere.core.strategy.route.complex.ComplexShardingStrategy

```java
line 61: 
columnShardingValues.put(each.getColumnName(), ((ListRouteValue) each).getValues());

```




### Steps to reproduce the behavior, such as: SQL to execute, sharding rule configuration, when exception occur etc.

- i am trying to test the ComplexKeysShardingAlgorithm, but before it come into my code, it occur a java.lang.ClassCastException, 

- the table configuration

  ```java
  public static TableRuleConfiguration defaultCreateTimeTableRuleConfiguration(String datasourceName, String tableName) {
          TableRuleConfiguration tableRule = new TableRuleConfiguration(tableName, String.format("%s.%s_$->{19..19}0$->{1..6}", datasourceName, tableName));
          tableRule.setTableShardingStrategyConfig(
                  new ComplexShardingStrategyConfiguration("id,create_time", new BaseComplexKeysShardingAlgorithm()));
          return tableRule;
  }
  ```

- my algorithm -- yes, it do nothing but log

  ```java
  @Slf4j(topic = "sharding")
  public class BaseComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm {
  
      @Override
      public Collection<String> doSharding(Collection availableTargetNames, ComplexKeysShardingValue shardingValue) {
          log.info("availableTargetNames: {}\\nshardingValue: {}", availableTargetNames, shardingValue);
          return availableTargetNames;
      }
  
  }
  ```

- sql 

  ```sql
  select * from t_order order0_ where order0_.create_time between ? and ?
  ```

  ```sql
  create table sharding.t_order
  (
  	create_time timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP,
  	id varchar(255) not null
  		primary key,
  	update_time datetime null,
  	name varchar(255) null,
  	test_id int null
  )
  ```

- JDK

  ```
  java 11.0.3 2019-04-16 LTS
  ```

- framework

  ```xml
  spring-boot-starter-data-jpa:2.1.4RELEASE
  <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
  ```

- the full trace is here

```java
Caused by: java.lang.ClassCastException: class org.apache.shardingsphere.core.strategy.route.value.BetweenRouteValue cannot be cast to class org.apache.shardingsphere.core.strategy.route.value.ListRouteValue (org.apache.shardingsphere.core.strategy.route.value.BetweenRouteValue and org.apache.shardingsphere.core.strategy.route.value.ListRouteValue are in unnamed module of loader 'app')
	at org.apache.shardingsphere.core.strategy.route.complex.ComplexShardingStrategy.doSharding(ComplexShardingStrategy.java:61) ~[sharding-core-common-4.0.0-RC1.jar:4.0.0-RC1]
	at org.apache.shardingsphere.core.route.type.standard.StandardRoutingEngine.routeTables(StandardRoutingEngine.java:199) ~[sharding-core-route-4.0.0-RC1.jar:4.0.0-RC1]
	at org.apache.shardingsphere.core.route.type.standard.StandardRoutingEngine.route(StandardRoutingEngine.java:181) ~[sharding-core-route-4.0.0-RC1.jar:4.0.0-RC1]
	at org.apache.shardingsphere.core.route.type.standard.StandardRoutingEngine.routeByShardingConditionsWithCondition(StandardRoutingEngine.java:108) ~[sharding-core-route-4.0.0-RC1.jar:4.0.0-RC1]
	at org.apache.shardingsphere.core.route.type.standard.StandardRoutingEngine.routeByShardingConditions(StandardRoutingEngine.java:102) ~[sharding-core-route-4.0.0-RC1.jar:4.0.0-RC1]
	at org.apache.shardingsphere.core.route.type.standard.StandardRoutingEngine.getDataNodes(StandardRoutingEngine.java:87) ~[sharding-core-route-4.0.0-RC1.jar:4.0.0-RC1]
	at org.apache.shardingsphere.core.route.type.standard.StandardRoutingEngine.route(StandardRoutingEngine.java:69) ~[sharding-core-route-4.0.0-RC1.jar:4.0.0-RC1]
	at org.apache.shardingsphere.core.route.router.sharding.ParsingSQLRouter.route(ParsingSQLRouter.java:106) ~[sharding-core-route-4.0.0-RC1.jar:4.0.0-RC1]
	at org.apache.shardingsphere.core.route.PreparedStatementRoutingEngine.route(PreparedStatementRoutingEngine.java:66) ~[sharding-core-route-4.0.0-RC1.jar:4.0.0-RC1]
	at org.apache.shardingsphere.core.PreparedQueryShardingEngine.route(PreparedQueryShardingEngine.java:60) ~[sharding-core-entry-4.0.0-RC1.jar:4.0.0-RC1]
	at org.apache.shardingsphere.core.BaseShardingEngine.shard(BaseShardingEngine.java:64) ~[sharding-core-entry-4.0.0-RC1.jar:4.0.0-RC1]
	at org.apache.shardingsphere.shardingjdbc.jdbc.core.statement.ShardingPreparedStatement.shard(ShardingPreparedStatement.java:224) ~[sharding-jdbc-core-4.0.0-RC1.jar:4.0.0-RC1]
	at org.apache.shardingsphere.shardingjdbc.jdbc.core.statement.ShardingPreparedStatement.executeQuery(ShardingPreparedStatement.java:109) ~[sharding-jdbc-core-4.0.0-RC1.jar:4.0.0-RC1]
	at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:60) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.loader.Loader.getResultSet(Loader.java:2167) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1930) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1892) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.loader.Loader.doQuery(Loader.java:937) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:340) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.loader.Loader.doList(Loader.java:2689) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.loader.Loader.doList(Loader.java:2672) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2506) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.loader.Loader.list(Loader.java:2501) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:504) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:395) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:220) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1507) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1537) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1505) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at org.hibernate.query.Query.getResultList(Query.java:132) ~[hibernate-core-5.3.9.Final.jar:5.3.9.Final]
	at com.querydsl.jpa.impl.AbstractJPAQuery.getResultList(AbstractJPAQuery.java:160) ~[querydsl-jpa-4.2.1.jar:na]
	at com.querydsl.jpa.impl.AbstractJPAQuery.fetch(AbstractJPAQuery.java:202) ~[querydsl-jpa-4.2.1.jar:na]
	at com.f5futurestore.cloud.demo.service.OrderServiceImpl.test(OrderServiceImpl.java:103) ~[classes/:na]
	at com.f5futurestore.cloud.demo.service.OrderServiceImpl$$FastClassBySpringCGLIB$$d3d4b7a6.invoke(<generated>) ~[classes/:na]
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) ~[spring-tx-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at com.f5futurestore.cloud.demo.service.OrderServiceImpl$$EnhancerBySpringCGLIB$$4987f585.test(<generated>) ~[classes/:na]
	at com.f5futurestore.cloud.demo.controller.DemoController.test(DemoController.java:39) ~[classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:363) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:307) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
```

### Example codes for reproduce this issue (such as a github link).

i will post it to github later

Changed files:
sharding-core/sharding-core-api/src/main/java/org/apache/shardingsphere/api/sharding/complex/ComplexKeysShardingValue.java
sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/strategy/route/ShardingStrategyTest.java
sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/strategy/route/complex/ComplexShardingStrategy.java

diff --git a/sharding-core/sharding-core-api/src/main/java/org/apache/shardingsphere/api/sharding/complex/ComplexKeysShardingValue.java b/sharding-core/sharding-core-api/src/main/java/org/apache/shardingsphere/api/sharding/complex/ComplexKeysShardingValue.java
index faaa06e0076..3a4dade7640 100644
--- a/sharding-core/sharding-core-api/src/main/java/org/apache/shardingsphere/api/sharding/complex/ComplexKeysShardingValue.java
+++ b/sharding-core/sharding-core-api/src/main/java/org/apache/shardingsphere/api/sharding/complex/ComplexKeysShardingValue.java
@@ -17,6 +17,7 @@
 
 package org.apache.shardingsphere.api.sharding.complex;
 
+import com.google.common.collect.Range;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import lombok.ToString;
@@ -38,4 +39,6 @@ public final class ComplexKeysShardingValue<T extends Comparable<?>> implements
     private final String logicTableName;
     
     private final Map<String, Collection<T>> columnNameAndShardingValuesMap;
+    
+    private final Map<String, Range<T>> columnNameAndRangeValuesMap;
 }
diff --git a/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/strategy/route/complex/ComplexShardingStrategy.java b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/strategy/route/complex/ComplexShardingStrategy.java
index 618e080d54c..723b147c46e 100644
--- a/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/strategy/route/complex/ComplexShardingStrategy.java
+++ b/sharding-core/sharding-core-common/src/main/java/org/apache/shardingsphere/core/strategy/route/complex/ComplexShardingStrategy.java
@@ -19,12 +19,15 @@ package org.apache.shardingsphere.core.strategy.route.complex;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
+import com.google.common.collect.Range;
+
 import lombok.Getter;
 import org.apache.shardingsphere.api.config.sharding.strategy.ComplexShardingStrategyConfiguration;
 import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
 import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;
 import org.apache.shardingsphere.core.strategy.route.ShardingStrategy;
 import org.apache.shardingsphere.core.strategy.route.value.ListRouteValue;
+import org.apache.shardingsphere.core.strategy.route.value.RangeRouteValue;
 import org.apache.shardingsphere.core.strategy.route.value.RouteValue;
 
 import java.util.Collection;
@@ -56,12 +59,17 @@ public final class ComplexShardingStrategy implements ShardingStrategy {
     @Override
     public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<RouteValue> shardingValues) {
         Map<String, Collection<Comparable<?>>> columnShardingValues = new HashMap<>(shardingValues.size(), 1);
+        Map<String, Range<Comparable<?>>> columnRangeValues = new HashMap<>(shardingValues.size(), 1);
         String logicTableName = "";
         for (RouteValue each : shardingValues) {
-            columnShardingValues.put(each.getColumnName(), ((ListRouteValue) each).getValues());
+            if (each instanceof ListRouteValue) {
+                columnShardingValues.put(each.getColumnName(), ((ListRouteValue) each).getValues());
+            } else if (each instanceof RangeRouteValue) {
+                columnRangeValues.put(each.getColumnName(), ((RangeRouteValue) each).getValueRange());
+            }
             logicTableName = each.getTableName();
         }
-        Collection<String> shardingResult = shardingAlgorithm.doSharding(availableTargetNames, new ComplexKeysShardingValue(logicTableName, columnShardingValues));
+        Collection<String> shardingResult = shardingAlgorithm.doSharding(availableTargetNames, new ComplexKeysShardingValue(logicTableName, columnShardingValues, columnRangeValues));
         Collection<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
         result.addAll(shardingResult);
         return result;
diff --git a/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/strategy/route/ShardingStrategyTest.java b/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/strategy/route/ShardingStrategyTest.java
index 0ac1045f183..2ccdb4eb30a 100644
--- a/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/strategy/route/ShardingStrategyTest.java
+++ b/sharding-core/sharding-core-common/src/test/java/org/apache/shardingsphere/core/strategy/route/ShardingStrategyTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.shardingsphere.core.strategy.route;
 
+import com.google.common.collect.Lists;
 import com.google.common.collect.Range;
 import com.google.common.collect.Sets;
 import org.apache.shardingsphere.api.config.sharding.strategy.ComplexShardingStrategyConfiguration;
@@ -34,6 +35,7 @@ import org.junit.Test;
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
@@ -58,8 +60,11 @@ public final class ShardingStrategyTest {
     
     @Test
     public void assertDoShardingForMultipleKeys() {
-        ComplexShardingStrategy strategy = new ComplexShardingStrategy(new ComplexShardingStrategyConfiguration("column", new ComplexKeysShardingAlgorithmFixture()));
-        assertThat(strategy.doSharding(targets, Collections.<RouteValue>singletonList(new ListRouteValue<>("column", "logicTable", Collections.singletonList(1)))), 
-                is((Collection<String>) Sets.newHashSet("1", "2", "3")));
+        ComplexShardingStrategy strategy = new ComplexShardingStrategy(new ComplexShardingStrategyConfiguration("column1, column2", new ComplexKeysShardingAlgorithmFixture()));
+        List<RouteValue> routeValues = Lists.<RouteValue>newArrayList(
+            new ListRouteValue<>("column1", "logicTable", Collections.singletonList(1)),
+            new RangeRouteValue<>("column2", "logicTable", Range.open(1, 3))
+        );
+        assertThat(strategy.doSharding(targets, routeValues), is((Collection<String>) Sets.newHashSet("1", "2", "3")));
     }
 }